diff --git a/.github/workflows/dotnet-build.yml b/.github/workflows/dotnet-build.yml index 0ea9feb6..1e4e4c7d 100644 --- a/.github/workflows/dotnet-build.yml +++ b/.github/workflows/dotnet-build.yml @@ -33,12 +33,6 @@ jobs: fetch-depth: 0 submodules: true - # Set up a VS build environment. - - name: Setup Environment Variables - run: | - "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" -no_logo - shell: cmd - # Install NuGet tools. - name: Setup NuGet uses: NuGet/setup-nuget@v2 @@ -172,4 +166,4 @@ jobs: **/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_PACKAGE_PUSH_TOKEN }} - --skip-duplicate \ No newline at end of file + --skip-duplicate diff --git a/.gitignore b/.gitignore index 203b9893..ed41585a 100644 --- a/.gitignore +++ b/.gitignore @@ -238,3 +238,7 @@ launchSettings.json # Nuget Package files. pack/ + +# Native dependencies restored by MSBuild. +/.vcpkg/ +/vcpkg_installed/ diff --git a/Directory.Build.props b/Directory.Build.props index 9615baed..63077b78 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -125,7 +125,7 @@ - + @@ -144,7 +144,7 @@ $(NoWarn);8002 - + diff --git a/Lottie-Windows.sln b/Lottie-Windows.sln index a1b9997f..e7b0b362 100644 --- a/Lottie-Windows.sln +++ b/Lottie-Windows.sln @@ -173,6 +173,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LottieSamples", "LottieSamp EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lottie-Windows-UwpNET", "Lottie-Windows\Lottie-Windows-UwpNET\Lottie-Windows-UwpNET.csproj", "{FA1977D8-5C6F-DF3A-0926-C12A1A415024}" EndProject +Project("{BC8A1FFA-BEE3-4634-8014-F334798102B3}") = "LottieRuntimeTool", "source\LottieRuntime\LottieRuntimeTool.vcxproj", "{9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution BETA|Any CPU = BETA|Any CPU @@ -192,6 +194,27 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}.BETA|Any CPU.ActiveCfg = Release|x64 + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}.BETA|ARM.ActiveCfg = Release|ARM64 + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}.BETA|ARM64.ActiveCfg = Release|ARM64 + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}.BETA|ARM64.Build.0 = Release|ARM64 + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}.BETA|x64.ActiveCfg = Release|x64 + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}.BETA|x64.Build.0 = Release|x64 + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}.BETA|x86.ActiveCfg = Release|x64 + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}.Debug|Any CPU.ActiveCfg = Debug|x64 + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}.Debug|ARM.ActiveCfg = Debug|ARM64 + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}.Debug|ARM64.Build.0 = Debug|ARM64 + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}.Debug|x64.ActiveCfg = Debug|x64 + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}.Debug|x64.Build.0 = Debug|x64 + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}.Debug|x86.ActiveCfg = Debug|x64 + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}.Release|Any CPU.ActiveCfg = Release|x64 + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}.Release|ARM.ActiveCfg = Release|ARM64 + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}.Release|ARM64.ActiveCfg = Release|ARM64 + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}.Release|ARM64.Build.0 = Release|ARM64 + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}.Release|x64.ActiveCfg = Release|x64 + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}.Release|x64.Build.0 = Release|x64 + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48}.Release|x86.ActiveCfg = Release|x64 {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.BETA|Any CPU.ActiveCfg = BETA|x86 {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.BETA|ARM.ActiveCfg = BETA|ARM {5120EFD7-A556-46BF-8D56-F65F1EF9A305}.BETA|ARM.Build.0 = BETA|ARM @@ -685,6 +708,7 @@ Global {FC89273A-B2DA-4625-8A73-EF02A658D65E} = {AB232F35-AAF7-4AE2-B1D2-45DD9BC2F7D7} {7654A857-9A99-4185-9F8E-DD0CE662AF23} = {AB232F35-AAF7-4AE2-B1D2-45DD9BC2F7D7} {DC7F7A39-B7A7-40B4-937A-601460CAE38C} = {AB232F35-AAF7-4AE2-B1D2-45DD9BC2F7D7} + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48} = {AB232F35-AAF7-4AE2-B1D2-45DD9BC2F7D7} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {51B9BB4C-5196-41CF-950C-12B04AD8A61C} diff --git a/LottieGen/DotnetTool/LottieGen.csproj b/LottieGen/DotnetTool/LottieGen.csproj index 9eb44636..b82eebeb 100644 --- a/LottieGen/DotnetTool/LottieGen.csproj +++ b/LottieGen/DotnetTool/LottieGen.csproj @@ -9,7 +9,9 @@ true true LottieGen + x64-windows + <_SourceDir>..\..\source\ @@ -18,6 +20,7 @@ + @@ -33,4 +36,32 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LottieGen/MSBuildTask/LottieGen.cs b/LottieGen/MSBuildTask/LottieGen.cs index e0100fbf..1e38ab75 100644 --- a/LottieGen/MSBuildTask/LottieGen.cs +++ b/LottieGen/MSBuildTask/LottieGen.cs @@ -42,7 +42,7 @@ public sealed class LottieGen : Microsoft.Build.Utilities.ToolTask public string? InputFile { get; set; } /// - /// cs, cppcx, or cppwinrt. + /// cs, cppcx, cppwinrt, or flatbuffer. /// [Required] public string? Language { get; set; } @@ -190,6 +190,13 @@ public override bool Execute() } break; + + case Lang.Flatbuffer: + // The number of .lcomp variants depends on the UAP versions + // required by the animation, so use the paths LottieGen reported. + OutputFiles = _outputFiles.ConvertAll(f => (ITaskItem)new TaskItem(f)).ToArray(); + break; + default: throw new InvalidOperationException(); } @@ -341,6 +348,7 @@ protected override bool ValidateParameters() case Lang.Cppwinrt: case Lang.CSharp: case Lang.Cx: + case Lang.Flatbuffer: break; default: @@ -379,7 +387,8 @@ protected override void LogEventsFromTextOutput(string singleLine, MessageImport singleLine.StartsWith("C# code for class ") || singleLine.StartsWith("Cppwinrt header for class ") || singleLine.StartsWith("Cppwinrt source for class ") || - singleLine.StartsWith("Cppwinrt IDL for class "); + singleLine.StartsWith("Cppwinrt IDL for class ") || + singleLine.StartsWith("Flatbuffer data for class "); } Lang GetNormalizedLanguage() @@ -397,6 +406,9 @@ Lang GetNormalizedLanguage() case "cx": return Lang.Cx; + case "flatbuffer": + return Lang.Flatbuffer; + default: return Lang.Unknown; } @@ -408,6 +420,7 @@ enum Lang CSharp, Cx, Cppwinrt, + Flatbuffer, } } } diff --git a/LottieGen/win-x64/LottieGen.win-x64.csproj b/LottieGen/win-x64/LottieGen.win-x64.csproj index 6d0dfe5a..fb44ba06 100644 --- a/LottieGen/win-x64/LottieGen.win-x64.csproj +++ b/LottieGen/win-x64/LottieGen.win-x64.csproj @@ -35,6 +35,7 @@ + @@ -50,4 +51,7 @@ + + + diff --git a/README.md b/README.md index 968bb183..1efd23a3 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,12 @@ Lottie-Windows consists of 3 related products: This repo also contains source code for **[samples](/LottieViewer)**. +It also contains **[LottieRuntime](/source/LottieRuntime)**, native C++/WinRT source that +builds the composition tree at runtime from a serialized animation produced by +`LottieGen -Language flatbuffer`. It keeps the animation as data, like the JSON path does, but +without shipping a JSON parser or the translator. See +[the format](/source/LottieFlatbuffer/README.md) for how the two relate. + ## Quick start There are **two** options to integrate Lottie animations into your **WinUI 3** or **UWP** project. diff --git a/build/FlatBuffers.targets b/build/FlatBuffers.targets new file mode 100644 index 00000000..57621c6d --- /dev/null +++ b/build/FlatBuffers.targets @@ -0,0 +1,27 @@ + + + <_FlatBuffersRepoRoot>$(MSBuildThisFileDirectory)..\ + <_RestoreFlatBuffers Condition="'$(FlatBuffersIncludeDirectory)' == ''">true + $(VcpkgRoot) + $(VCPKG_ROOT) + $(VSInstallRoot)\VC\vcpkg + $(_FlatBuffersRepoRoot).vcpkg + $(_FlatBuffersRepoRoot)vcpkg_installed + x64-windows + arm64-windows + arm64-windows + x64-windows + $(FlatBuffersVcpkgInstalledDir)\$(FlatBuffersVcpkgTriplet)\include + + + + + + + + + diff --git a/build/RegenerateFlatbuffers.ps1 b/build/RegenerateFlatbuffers.ps1 new file mode 100644 index 00000000..4909cc20 --- /dev/null +++ b/build/RegenerateFlatbuffers.ps1 @@ -0,0 +1,49 @@ +# Regenerates the FlatBuffers code for lottie_comp.fbs. +# +# The generated C# and C++ sources are checked in so that contributors do not +# need flatc installed in order to build. Run this script after any change to +# source/LottieFlatbuffer/lottie_comp.fbs, and check in the result. +# +[CmdletBinding()] +param( + [string]$VcpkgRoot = $env:VCPKG_ROOT, + + [string]$InstalledDir = (Join-Path $PSScriptRoot "..\vcpkg_installed"), + + [string]$HostTriplet = $(if ($env:PROCESSOR_ARCHITECTURE -eq "ARM64" -or $env:PROCESSOR_ARCHITEW6432 -eq "ARM64") { "arm64-windows" } else { "x64-windows" }) +) + +$ErrorActionPreference = "Stop" + +$repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..") +$schema = Join-Path $repoRoot "source\LottieFlatbuffer\lottie_comp.fbs" +$csharpOut = Join-Path $repoRoot "source\CompDataFlatbuffer\Generated" +$cppOut = Join-Path $repoRoot "source\LottieRuntime\Generated" + +if (!$VcpkgRoot) { + $VcpkgRoot = Join-Path $repoRoot ".vcpkg" +} + +& (Join-Path $PSScriptRoot "RestoreFlatBuffers.ps1") -VcpkgRoot $VcpkgRoot ` + -InstalledDir $InstalledDir -Triplet $HostTriplet -HostTriplet $HostTriplet +$flatc = Join-Path $InstalledDir "$HostTriplet\tools\flatbuffers\flatc.exe" + +New-Item -ItemType Directory -Force -Path $csharpOut, $cppOut | Out-Null + +# --gen-onefile keeps the checked in C# to a single file rather than one file +# per type spread over a namespace directory tree. +& $flatc --csharp --gen-onefile -o $csharpOut $schema +if ($LASTEXITCODE -ne 0) { throw "flatc failed to generate C#." } + +& $flatc --cpp --scoped-enums -o $cppOut $schema +if ($LASTEXITCODE -ne 0) { throw "flatc failed to generate C++." } + +foreach ($path in @( + (Join-Path $csharpOut "lottie_comp_generated.cs"), + (Join-Path $cppOut "lottie_comp_generated.h") +)) { + $contents = [IO.File]::ReadAllText($path) + [IO.File]::WriteAllText($path, ($contents -replace '\r?\n', "`r`n"), [Text.UTF8Encoding]::new($false)) +} + +Write-Host "Generated FlatBuffers code from $schema" diff --git a/build/RestoreFlatBuffers.ps1 b/build/RestoreFlatBuffers.ps1 new file mode 100644 index 00000000..56df898c --- /dev/null +++ b/build/RestoreFlatBuffers.ps1 @@ -0,0 +1,67 @@ +[CmdletBinding()] +param( + [Parameter(Mandatory)] + [string]$VcpkgRoot, + + [Parameter(Mandatory)] + [string]$InstalledDir, + + [Parameter(Mandatory)] + [string]$Triplet, + + [string]$HostTriplet = "x64-windows" +) + +$ErrorActionPreference = "Stop" +$repoRoot = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot "..")) +$VcpkgRoot = [IO.Path]::GetFullPath($VcpkgRoot) +$InstalledDir = [IO.Path]::GetFullPath($InstalledDir) +$localRoot = Join-Path $repoRoot ".vcpkg" +$vcpkg = Join-Path $VcpkgRoot "vcpkg.exe" +$baseline = (Get-Content (Join-Path $repoRoot "vcpkg.json") -Raw | ConvertFrom-Json).'builtin-baseline' + +function Invoke-Checked([string]$Program, [string[]]$Arguments) { + & $Program @Arguments + if ($LASTEXITCODE -ne 0) { + throw "'$Program $($Arguments -join ' ')' failed with exit code $LASTEXITCODE." + } +} + +if (!(Test-Path -LiteralPath $vcpkg)) { + if ($VcpkgRoot -ne $localRoot) { + throw "vcpkg.exe was not found at '$VcpkgRoot'. Bootstrap that installation or omit FlatBuffersVcpkgRoot to use automatic discovery." + } + + if (!(Test-Path -LiteralPath $VcpkgRoot)) { + Invoke-Checked "git" @("init", $VcpkgRoot) + Invoke-Checked "git" @("-C", $VcpkgRoot, "remote", "add", "origin", "https://github.com/microsoft/vcpkg.git") + } + + $remote = & git -C $VcpkgRoot remote get-url origin + if ($LASTEXITCODE -ne 0 -or $remote -ne "https://github.com/microsoft/vcpkg.git") { + throw "'$VcpkgRoot' must be a checkout of https://github.com/microsoft/vcpkg.git." + } + + Invoke-Checked "git" @("-C", $VcpkgRoot, "fetch", "origin", $baseline) + Invoke-Checked "git" @("-C", $VcpkgRoot, "checkout", "--detach", $baseline) + Invoke-Checked (Join-Path $VcpkgRoot "bootstrap-vcpkg.bat") @("-disableMetrics") +} + +if ($VcpkgRoot -eq $localRoot) { + $shallow = & git -C $VcpkgRoot rev-parse --is-shallow-repository + if ($LASTEXITCODE -ne 0) { + throw "Could not inspect the repo-local vcpkg checkout at '$VcpkgRoot'." + } + if ($shallow -eq "true") { + Invoke-Checked "git" @("-C", $VcpkgRoot, "fetch", "--unshallow", "origin", $baseline) + } +} + +Invoke-Checked $vcpkg @( + "install", + "--triplet=$Triplet", + "--host-triplet=$HostTriplet", + "--x-wait-for-lock", + "--x-manifest-root=$repoRoot", + "--x-install-root=$InstalledDir" +) diff --git a/build/build.cake b/build/build.cake index 1c27469a..438cb353 100644 --- a/build/build.cake +++ b/build/build.cake @@ -101,6 +101,8 @@ static bool IsExcludedDirectory(FilePath path) return segments.Contains("bin") || segments.Contains("external") || + segments.Contains(".vcpkg") || + segments.Contains("vcpkg_installed") || segments.Contains("internal") || segments.Contains("obj"); } diff --git a/dlls/CompDataFlatbuffer/CompDataFlatbuffer.dll.csproj b/dlls/CompDataFlatbuffer/CompDataFlatbuffer.dll.csproj new file mode 100644 index 00000000..08da3387 --- /dev/null +++ b/dlls/CompDataFlatbuffer/CompDataFlatbuffer.dll.csproj @@ -0,0 +1,25 @@ + + + + net9.0 + Debug;Release + latest + PUBLIC_CompDataFlatbuffer + + + + + + + + + + + + + + + + + diff --git a/source/CompDataFlatbuffer/CompDataFlatbuffer.projitems b/source/CompDataFlatbuffer/CompDataFlatbuffer.projitems new file mode 100644 index 00000000..69bfe016 --- /dev/null +++ b/source/CompDataFlatbuffer/CompDataFlatbuffer.projitems @@ -0,0 +1,20 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + 5a3f2c41-9a2e-4c2d-9f4a-1d1a0f6b3c77 + + + CompDataFlatbuffer + + + + + + + + diff --git a/source/CompDataFlatbuffer/CompDataFlatbuffer.shproj b/source/CompDataFlatbuffer/CompDataFlatbuffer.shproj new file mode 100644 index 00000000..5a214f6b --- /dev/null +++ b/source/CompDataFlatbuffer/CompDataFlatbuffer.shproj @@ -0,0 +1,13 @@ + + + + 5a3f2c41-9a2e-4c2d-9f4a-1d1a0f6b3c77 + 14.0 + + + + + + + + diff --git a/source/CompDataFlatbuffer/CompDataFlatbufferRuntime.projitems b/source/CompDataFlatbuffer/CompDataFlatbufferRuntime.projitems new file mode 100644 index 00000000..01949a2a --- /dev/null +++ b/source/CompDataFlatbuffer/CompDataFlatbufferRuntime.projitems @@ -0,0 +1,18 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + true + + + CompDataFlatbuffer + + + + + + + + diff --git a/source/CompDataFlatbuffer/CompositionDeserializer.cs b/source/CompDataFlatbuffer/CompositionDeserializer.cs new file mode 100644 index 00000000..efda0849 --- /dev/null +++ b/source/CompDataFlatbuffer/CompositionDeserializer.cs @@ -0,0 +1,1329 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable enable + +using System; +using System.Collections.Generic; +using System.Numerics; +using CommunityToolkit.WinUI.Lottie.WinCompData; +using CommunityToolkit.WinUI.Lottie.WinCompData.MetaData; +using CommunityToolkit.WinUI.Lottie.WinCompData.Mgc; +using CommunityToolkit.WinUI.Lottie.WinCompData.Mgce; +using CommunityToolkit.WinUI.Lottie.WinCompData.Mgcg; +using CommunityToolkit.WinUI.Lottie.WinUIXamlMediaData; +using Google.FlatBuffers; +using Expressions = CommunityToolkit.WinUI.Lottie.WinCompData.Expressions; +using Fb = CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema; +using Wui = CommunityToolkit.WinUI.Lottie.WinCompData.Wui; + +namespace CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer +{ + /// + /// Rebuilds a WinCompData object graph from a FlatBuffer produced by + /// . + /// + /// + /// This is the managed counterpart of the native interpreter. It exists so that the + /// wire format can be tested by round tripping a graph through it and comparing the + /// result with the original, which is a much stronger check than testing the + /// serializer alone. + /// + /// Expressions are stored in the buffer as text - which is all that + /// Windows.UI.Composition itself accepts - so the static type of an expression tree + /// is not preserved. Rebuilt expressions are "asserted" expressions with the same + /// text, which compare equal to the originals. + /// +#if PUBLIC_CompDataFlatbuffer + public +#endif + sealed class CompositionDeserializer + { + // The smallest buffer that could possibly be a composition: a root offset + // followed by the four byte file identifier. Checked before the identifier is + // read so that a short buffer is reported as a format error. + const int MinimumBufferLength = 8; + + readonly Compositor _compositor = new Compositor(); + readonly Fb.LottieComposition _root; + readonly string[] _strings; + + // Realization caches. These are indexed identically to the node vectors in the + // buffer, so looking up an already realized node is an array index rather than a + // hash lookup, and shared nodes are realized exactly once. + readonly Visual?[] _visuals; + readonly CompositionShape?[] _shapes; + readonly CompositionGeometry?[] _geometries; + readonly CanvasGeometry?[] _canvasGeometries; + readonly CompositionBrush?[] _brushes; + readonly CompositionColorGradientStop?[] _gradientStops; + readonly CompositionViewBox?[] _viewBoxes; + readonly CompositionClip?[] _clips; + readonly CompositionShadow?[] _shadows; + readonly ICompositionSurface?[] _surfaces; + readonly GraphicsEffectBase?[] _effects; + readonly CompositionEasingFunction?[] _easings; + readonly CompositionAnimation?[] _animations; + readonly CompositionPropertySet?[] _propertySets; + readonly AnimationController?[] _controllers; + + CompositionDeserializer(Fb.LottieComposition root) + { + _root = root; + + _strings = new string[root.StringsLength]; + for (var i = 0; i < _strings.Length; i++) + { + _strings[i] = root.Strings(i) ?? string.Empty; + } + + _visuals = new Visual?[root.VisualsLength]; + _shapes = new CompositionShape?[root.ShapesLength]; + _geometries = new CompositionGeometry?[root.GeometriesLength]; + _canvasGeometries = new CanvasGeometry?[root.CanvasGeometriesLength]; + _brushes = new CompositionBrush?[root.BrushesLength]; + _gradientStops = new CompositionColorGradientStop?[root.GradientStopsLength]; + _viewBoxes = new CompositionViewBox?[root.ViewBoxesLength]; + _clips = new CompositionClip?[root.ClipsLength]; + _shadows = new CompositionShadow?[root.ShadowsLength]; + _surfaces = new ICompositionSurface?[root.SurfacesLength]; + _effects = new GraphicsEffectBase?[root.EffectsLength]; + _easings = new CompositionEasingFunction?[root.EasingsLength]; + _animations = new CompositionAnimation?[root.AnimationsLength]; + _propertySets = new CompositionPropertySet?[root.PropertySetsLength]; + _controllers = new AnimationController?[root.ControllersLength]; + } + + /// + /// Rebuilds the graph described by a FlatBuffer. + /// + /// A buffer produced by . + /// The root visual of the rebuilt graph. + /// The buffer is not a well formed composition. + public static Visual Deserialize(ReadOnlySpan bytes) + { + // The buffer is untrusted, so it is fully verified before any of it is read. + var buffer = new ByteBuffer(bytes.ToArray()); + + if (bytes.Length < MinimumBufferLength || + !Fb.LottieComposition.LottieCompositionBufferHasIdentifier(buffer)) + { + throw new FlatBufferFormatException("The buffer is not a composition."); + } + + // Verification proves that the buffer is structurally sound, but it cannot + // prove that the indices stored in it point at the right things. Neither the + // verifier nor the reader reports a malformed buffer purely by returning + // false; both also throw. Everything is therefore done inside this handler so + // that a corrupt buffer always surfaces as a format error and never as an + // exception that a caller could not have anticipated. Reading past the end of + // the buffer is not a safety problem because ByteBuffer is bounds checked; + // the only thing being corrected here is the type of the exception. + try + { + if (!Fb.LottieComposition.VerifyLottieComposition(buffer)) + { + throw new FlatBufferFormatException("The buffer is not a valid composition."); + } + + var root = Fb.LottieComposition.GetRootAsLottieComposition(buffer); + + if (root.SchemaVersion > Format.Version) + { + throw new FlatBufferFormatException( + $"Schema version {root.SchemaVersion} is newer than the supported version {Format.Version}."); + } + + var deserializer = new CompositionDeserializer(root); + var rootVisual = deserializer.GetVisual(root.RootVisual); + + return rootVisual ?? throw new FlatBufferFormatException("The composition has no root visual."); + } + catch (Exception e) when (e is ArgumentException or IndexOutOfRangeException or + InvalidOperationException or OverflowException or + FormatException or NullReferenceException) + { + throw new FlatBufferFormatException("The buffer is malformed.", e); + } + } + + // --------------------------------------------------------------------- + // Table accessors. Every index is bounds checked, because a buffer that + // passes verification can still contain an out of range index. + // --------------------------------------------------------------------- + static T Require(T? value, string what) + where T : struct + => value ?? throw new FlatBufferFormatException($"A {what} is missing."); + + string? GetString(uint index) + => index == Format.NullIndex + ? null + : index < (uint)_strings.Length + ? _strings[index] + : throw new FlatBufferFormatException($"String index {index} is out of range."); + + string GetRequiredString(uint index) + => GetString(index) ?? throw new FlatBufferFormatException("A required string is missing."); + + // --------------------------------------------------------------------- + // Shared state. + // --------------------------------------------------------------------- + // Applies the state that is common to every CompositionObject. Called after the + // object has been placed in its realization cache, so that a cycle through a + // reference parameter terminates. + void InitializeCompositionObject(CompositionObject target, Fb.CompObj? source) + { + if (source is null) + { + return; + } + + var value = source.Value; + + target.Comment = GetString(value.Comment); + + // The property set is realized through the object that owns it, so that the + // owner and its property set can never be created twice. + if (value.Properties != Format.NullIndex) + { + RealizePropertySet(value.Properties, target.Properties); + } + + // Animations are started last, because setting a property stops any animation + // that is running on it. + for (var i = 0; i < value.AnimatorsLength; i++) + { + var animator = Require(value.Animators(i), "animator"); + var property = GetRequiredString(animator.Property); + var animation = GetAnimation(animator.Animation) + ?? throw new FlatBufferFormatException($"Animator '{property}' has no animation."); + + // A non custom controller is created by StartAnimation, so only a custom + // one is passed in. Either way the resulting controller is cached under + // the index that the buffer gave it. + var controllerIndex = animator.Controller; + var customController = controllerIndex != Format.NullIndex && IsCustomController(controllerIndex) + ? GetController(controllerIndex) + : null; + + // An expression animation is driven by its inputs and so cannot have a + // controller. StartAnimation only asserts this, so it is checked here in + // order to reject the buffer rather than build an unusable graph. + if (customController is not null && animation is ExpressionAnimation) + { + throw new FlatBufferFormatException( + $"Animator '{property}' gives a controller to an expression animation."); + } + + var created = target.StartAnimation(property, animation, customController); + + if (controllerIndex != Format.NullIndex && created.Controller is not null) + { + RealizeController(controllerIndex, created.Controller); + } + } + } + + bool IsCustomController(uint index) + => GetControllerTable(index).IsCustom; + + Fb.Controller GetControllerTable(uint index) + => index < (uint)_controllers.Length + ? Require(_root.Controllers((int)index), "controller") + : throw new FlatBufferFormatException($"Controller index {index} is out of range."); + + void RealizeController(uint index, AnimationController controller) + { + if (_controllers[index] is not null) + { + return; + } + + _controllers[index] = controller; + + var table = GetControllerTable(index); + + if (table.IsPaused) + { + controller.Pause(); + } + + InitializeCompositionObject(controller, table.Base); + } + + AnimationController? GetController(uint index) + { + if (index == Format.NullIndex) + { + return null; + } + + var table = GetControllerTable(index); + + if (_controllers[index] is null) + { + if (table.IsCustom) + { + RealizeController(index, _compositor.CreateAnimationController()); + } + else + { + // A non custom controller comes into existence when its target object + // starts the animation, so realizing the target realizes the controller. + GetObjectReference(table.TargetObject); + } + } + + return _controllers[index] + ?? throw new FlatBufferFormatException($"Controller {index} could not be realized."); + } + + void RealizePropertySet(uint index, CompositionPropertySet propertySet) + { + if (index >= (uint)_propertySets.Length) + { + throw new FlatBufferFormatException($"Property set index {index} is out of range."); + } + + if (_propertySets[index] is not null) + { + return; + } + + _propertySets[index] = propertySet; + + var table = Require(_root.PropertySets((int)index), "property set"); + + for (var i = 0; i < table.ValuesLength; i++) + { + var value = Require(table.Values(i), "property value"); + var name = GetRequiredString(value.Name); + + switch (value.Type) + { + case Fb.PropertyValueType.Color: + propertySet.InsertColor(name, ToColor(Require(value.Color, "color"))); + break; + case Fb.PropertyValueType.Scalar: + propertySet.InsertScalar(name, value.Scalar); + break; + case Fb.PropertyValueType.Vector2: + propertySet.InsertVector2(name, ToVector2(value.Vector)); + break; + case Fb.PropertyValueType.Vector3: + propertySet.InsertVector3(name, ToVector3(value.Vector)); + break; + case Fb.PropertyValueType.Vector4: + propertySet.InsertVector4(name, ToVector4(value.Vector)); + break; + } + } + + InitializeCompositionObject(propertySet, table.Base); + } + + CompositionPropertySet? GetPropertySet(uint index) + { + if (index == Format.NullIndex) + { + return null; + } + + if (index >= (uint)_propertySets.Length) + { + throw new FlatBufferFormatException($"Property set index {index} is out of range."); + } + + if (_propertySets[index] is null) + { + var table = Require(_root.PropertySets((int)index), "property set"); + + if (table.Owner == Format.NullIndex) + { + RealizePropertySet(index, _compositor.CreatePropertySet()); + } + else + { + // Realizing the owner realizes its property set as a side effect. + GetObjectReference(table.Owner); + } + } + + return _propertySets[index] + ?? throw new FlatBufferFormatException($"Property set {index} could not be realized."); + } + + // Resolves a packed (category, index) reference. Only used by the three fields + // that can point at an object of any category. + CompositionObject? GetObjectReference(uint reference) + { + if (reference == Format.NullIndex) + { + return null; + } + + var category = Format.UnpackCategory(reference); + var index = (uint)Format.UnpackIndex(reference); + + return category switch + { + Fb.ObjectCategory.Visual => GetVisual(index), + Fb.ObjectCategory.Shape => GetShape(index), + Fb.ObjectCategory.Geometry => GetGeometry(index), + Fb.ObjectCategory.Brush => GetBrush(index), + Fb.ObjectCategory.Animation => GetAnimation(index), + Fb.ObjectCategory.Easing => GetEasing(index), + Fb.ObjectCategory.PropertySet => GetPropertySet(index), + Fb.ObjectCategory.Surface => GetSurface(index) as CompositionObject, + Fb.ObjectCategory.Clip => GetClip(index), + Fb.ObjectCategory.Controller => GetController(index), + Fb.ObjectCategory.Shadow => GetShadow(index), + Fb.ObjectCategory.GradientStop => GetGradientStop(index), + Fb.ObjectCategory.ViewBox => GetViewBox(index), + _ => throw new FlatBufferFormatException($"Unsupported object category {category}."), + }; + } + + // --------------------------------------------------------------------- + // Nodes. + // --------------------------------------------------------------------- + Visual? GetVisual(uint index) + { + if (index == Format.NullIndex) + { + return null; + } + + if (index >= (uint)_visuals.Length) + { + throw new FlatBufferFormatException($"Visual index {index} is out of range."); + } + + if (_visuals[index] is Visual cached) + { + return cached; + } + + var table = Require(_root.Visuals((int)index), "visual"); + + Visual result = table.Kind switch + { + Fb.VisualKind.Shape => _compositor.CreateShapeVisual(), + Fb.VisualKind.Sprite => _compositor.CreateSpriteVisual(), + Fb.VisualKind.Layer => _compositor.CreateLayerVisual(), + Fb.VisualKind.Container => _compositor.CreateContainerVisual(), + _ => throw new FlatBufferFormatException($"Unsupported visual kind {table.Kind}."), + }; + + _visuals[index] = result; + + if (table.BorderMode.HasValue) + { + result.BorderMode = (CompositionBorderMode)table.BorderMode.Value; + } + + result.CenterPoint = ToVector3(table.CenterPoint); + result.Clip = GetClip(table.Clip); + result.IsVisible = table.IsVisible; + result.Offset = ToVector3(table.Offset); + result.Opacity = table.Opacity; + result.RotationAngleInDegrees = table.RotationAngleInDegrees; + result.RotationAxis = ToVector3(table.RotationAxis); + result.Scale = ToVector3(table.Scale); + result.Size = ToVector2(table.Size); + result.TransformMatrix = ToMatrix4x4(table.TransformMatrix); + + if (result is ContainerVisual container) + { + for (var i = 0; i < table.ChildrenLength; i++) + { + container.Children.Add( + GetVisual(table.Children(i)) + ?? throw new FlatBufferFormatException("A visual child is missing.")); + } + } + + switch (result) + { + case ShapeVisual shapeVisual: + for (var i = 0; i < table.ShapesLength; i++) + { + shapeVisual.Shapes.Add( + GetShape(table.Shapes(i)) + ?? throw new FlatBufferFormatException("A shape is missing.")); + } + + shapeVisual.ViewBox = GetViewBox(table.ViewBox); + break; + case SpriteVisual spriteVisual: + spriteVisual.Brush = GetBrush(table.Brush); + spriteVisual.Shadow = GetShadow(table.Shadow); + break; + case LayerVisual layerVisual: + layerVisual.Shadow = GetShadow(table.Shadow); + break; + } + + InitializeCompositionObject(result, table.Base); + return result; + } + + CompositionShape? GetShape(uint index) + { + if (index == Format.NullIndex) + { + return null; + } + + if (index >= (uint)_shapes.Length) + { + throw new FlatBufferFormatException($"Shape index {index} is out of range."); + } + + if (_shapes[index] is CompositionShape cached) + { + return cached; + } + + var table = Require(_root.Shapes((int)index), "shape"); + + CompositionShape result = table.Kind switch + { + Fb.ShapeKind.Sprite => _compositor.CreateSpriteShape(), + Fb.ShapeKind.Container => _compositor.CreateContainerShape(), + _ => throw new FlatBufferFormatException($"Unsupported shape kind {table.Kind}."), + }; + + _shapes[index] = result; + + result.CenterPoint = ToVector2(table.CenterPoint); + result.Offset = ToVector2(table.Offset); + result.RotationAngleInDegrees = table.RotationAngleInDegrees; + result.Scale = ToVector2(table.Scale); + result.TransformMatrix = ToMatrix3x2(table.TransformMatrix); + + switch (result) + { + case CompositionContainerShape containerShape: + for (var i = 0; i < table.ShapesLength; i++) + { + containerShape.Shapes.Add( + GetShape(table.Shapes(i)) + ?? throw new FlatBufferFormatException("A shape is missing.")); + } + + break; + case CompositionSpriteShape spriteShape: + spriteShape.FillBrush = GetBrush(table.FillBrush); + spriteShape.StrokeBrush = GetBrush(table.StrokeBrush); + spriteShape.Geometry = GetGeometry(table.Geometry); + spriteShape.IsStrokeNonScaling = table.IsStrokeNonScaling; + spriteShape.StrokeDashOffset = table.StrokeDashOffset; + + for (var i = 0; i < table.StrokeDashArrayLength; i++) + { + spriteShape.StrokeDashArray.Add(table.StrokeDashArray(i)); + } + + if (table.StrokeDashCap.HasValue) + { + spriteShape.StrokeDashCap = (CompositionStrokeCap)table.StrokeDashCap.Value; + } + + if (table.StrokeStartCap.HasValue) + { + spriteShape.StrokeStartCap = (CompositionStrokeCap)table.StrokeStartCap.Value; + } + + if (table.StrokeEndCap.HasValue) + { + spriteShape.StrokeEndCap = (CompositionStrokeCap)table.StrokeEndCap.Value; + } + + if (table.StrokeLineJoin.HasValue) + { + spriteShape.StrokeLineJoin = (CompositionStrokeLineJoin)table.StrokeLineJoin.Value; + } + + spriteShape.StrokeMiterLimit = table.StrokeMiterLimit; + spriteShape.StrokeThickness = table.StrokeThickness; + break; + } + + InitializeCompositionObject(result, table.Base); + return result; + } + + CompositionGeometry? GetGeometry(uint index) + { + if (index == Format.NullIndex) + { + return null; + } + + if (index >= (uint)_geometries.Length) + { + throw new FlatBufferFormatException($"Geometry index {index} is out of range."); + } + + if (_geometries[index] is CompositionGeometry cached) + { + return cached; + } + + var table = Require(_root.Geometries((int)index), "geometry"); + + CompositionGeometry result = table.Kind switch + { + Fb.GeometryKind.Rectangle => _compositor.CreateRectangleGeometry(), + Fb.GeometryKind.RoundedRectangle => _compositor.CreateRoundedRectangleGeometry(), + Fb.GeometryKind.Ellipse => _compositor.CreateEllipseGeometry(), + Fb.GeometryKind.Path => _compositor.CreatePathGeometry(), + _ => throw new FlatBufferFormatException($"Unsupported geometry kind {table.Kind}."), + }; + + _geometries[index] = result; + + result.TrimStart = table.TrimStart; + result.TrimEnd = table.TrimEnd; + result.TrimOffset = table.TrimOffset; + + switch (result) + { + case CompositionPathGeometry pathGeometry: + var path = GetCanvasGeometry(table.Path); + pathGeometry.Path = path is null ? null : new CompositionPath(path); + break; + case CompositionRoundedRectangleGeometry roundedRectangle: + roundedRectangle.Offset = ToVector2(table.Offset); + roundedRectangle.Size = ToVector2(table.Size); + roundedRectangle.CornerRadius = ToVector2(table.CornerRadius) ?? Vector2.Zero; + break; + case CompositionRectangleGeometry rectangle: + rectangle.Offset = ToVector2(table.Offset); + rectangle.Size = ToVector2(table.Size); + break; + case CompositionEllipseGeometry ellipse: + ellipse.Center = ToVector2(table.Center) ?? Vector2.Zero; + ellipse.Radius = ToVector2(table.Radius) ?? Vector2.Zero; + break; + } + + InitializeCompositionObject(result, table.Base); + return result; + } + + CompositionBrush? GetBrush(uint index) + { + if (index == Format.NullIndex) + { + return null; + } + + if (index >= (uint)_brushes.Length) + { + throw new FlatBufferFormatException($"Brush index {index} is out of range."); + } + + if (_brushes[index] is CompositionBrush cached) + { + return cached; + } + + var table = Require(_root.Brushes((int)index), "brush"); + + CompositionBrush result; + switch (table.Kind) + { + case Fb.BrushKind.Color: + result = _compositor.CreateColorBrush(); + break; + case Fb.BrushKind.LinearGradient: + result = _compositor.CreateLinearGradientBrush(); + break; + case Fb.BrushKind.RadialGradient: + result = _compositor.CreateRadialGradientBrush(); + break; + case Fb.BrushKind.Mask: + result = _compositor.CreateMaskBrush(); + break; + case Fb.BrushKind.Surface: + // The surface is needed to construct the brush, so it is realized + // before the brush is placed in the cache. + result = _compositor.CreateSurfaceBrush( + GetSurface(table.Surface) + ?? throw new FlatBufferFormatException("A surface brush has no surface.")); + break; + case Fb.BrushKind.Effect: + var effect = GetEffect(table.Effect) + ?? throw new FlatBufferFormatException("An effect brush has no effect."); + result = CompositionEffectFactory.GetFactoryCached(effect).CreateBrush(); + break; + default: + throw new FlatBufferFormatException($"Unsupported brush kind {table.Kind}."); + } + + _brushes[index] = result; + + switch (result) + { + case CompositionColorBrush colorBrush: + colorBrush.Color = ToColorOrNull(table.Color); + break; + case CompositionMaskBrush maskBrush: + maskBrush.Source = GetBrush(table.Source); + maskBrush.Mask = GetBrush(table.Mask); + break; + case CompositionEffectBrush effectBrush: + for (var i = 0; i < table.SourceParametersLength; i++) + { + var parameter = Require(table.SourceParameters(i), "source parameter"); + effectBrush.SetSourceParameter( + GetRequiredString(parameter.Name), + GetBrush(parameter.Brush) + ?? throw new FlatBufferFormatException("An effect source has no brush.")); + } + + break; + } + + if (result is CompositionGradientBrush gradientBrush) + { + gradientBrush.AnchorPoint = ToVector2(table.AnchorPoint); + gradientBrush.CenterPoint = ToVector2(table.CenterPoint); + + for (var i = 0; i < table.ColorStopsLength; i++) + { + gradientBrush.ColorStops.Add( + GetGradientStop(table.ColorStops(i)) + ?? throw new FlatBufferFormatException("A gradient stop is missing.")); + } + + if (table.ExtendMode.HasValue) + { + gradientBrush.ExtendMode = (CompositionGradientExtendMode)table.ExtendMode.Value; + } + + if (table.InterpolationSpace.HasValue) + { + gradientBrush.InterpolationSpace = (CompositionColorSpace)table.InterpolationSpace.Value; + } + + if (table.MappingMode.HasValue) + { + gradientBrush.MappingMode = (CompositionMappingMode)table.MappingMode.Value; + } + + gradientBrush.Offset = ToVector2(table.Offset); + gradientBrush.RotationAngleInDegrees = table.RotationAngleInDegrees; + gradientBrush.Scale = ToVector2(table.Scale); + gradientBrush.TransformMatrix = ToMatrix3x2(table.TransformMatrix); + + switch (gradientBrush) + { + case CompositionLinearGradientBrush linear: + linear.StartPoint = ToVector2(table.StartPoint); + linear.EndPoint = ToVector2(table.EndPoint); + break; + case CompositionRadialGradientBrush radial: + radial.EllipseCenter = ToVector2(table.EllipseCenter); + radial.EllipseRadius = ToVector2(table.EllipseRadius); + radial.GradientOriginOffset = ToVector2(table.GradientOriginOffset); + break; + } + } + + InitializeCompositionObject(result, table.Base); + return result; + } + + CompositionColorGradientStop? GetGradientStop(uint index) + { + if (index == Format.NullIndex) + { + return null; + } + + if (index >= (uint)_gradientStops.Length) + { + throw new FlatBufferFormatException($"Gradient stop index {index} is out of range."); + } + + if (_gradientStops[index] is CompositionColorGradientStop cached) + { + return cached; + } + + var table = Require(_root.GradientStops((int)index), "gradient stop"); + var result = _compositor.CreateColorGradientStop(); + _gradientStops[index] = result; + + result.Color = ToColor(Require(table.Color, "color")); + result.Offset = table.Offset; + + InitializeCompositionObject(result, table.Base); + return result; + } + + CompositionViewBox? GetViewBox(uint index) + { + if (index == Format.NullIndex) + { + return null; + } + + if (index >= (uint)_viewBoxes.Length) + { + throw new FlatBufferFormatException($"View box index {index} is out of range."); + } + + if (_viewBoxes[index] is CompositionViewBox cached) + { + return cached; + } + + var table = Require(_root.ViewBoxes((int)index), "view box"); + var result = _compositor.CreateViewBox(); + _viewBoxes[index] = result; + + result.Size = ToVector2(table.Size) ?? Vector2.Zero; + + InitializeCompositionObject(result, table.Base); + return result; + } + + CompositionClip? GetClip(uint index) + { + if (index == Format.NullIndex) + { + return null; + } + + if (index >= (uint)_clips.Length) + { + throw new FlatBufferFormatException($"Clip index {index} is out of range."); + } + + if (_clips[index] is CompositionClip cached) + { + return cached; + } + + var table = Require(_root.Clips((int)index), "clip"); + + CompositionClip result = table.Kind switch + { + Fb.ClipKind.Geometric => _compositor.CreateGeometricClip(), + Fb.ClipKind.Inset => _compositor.CreateInsetClip(), + _ => throw new FlatBufferFormatException($"Unsupported clip kind {table.Kind}."), + }; + + _clips[index] = result; + + result.CenterPoint = ToVector2(table.CenterPoint); + result.Scale = ToVector2(table.Scale); + + switch (result) + { + case InsetClip inset: + inset.LeftInset = table.LeftInset; + inset.RightInset = table.RightInset; + inset.TopInset = table.TopInset; + inset.BottomInset = table.BottomInset; + break; + case CompositionGeometricClip geometric: + geometric.Geometry = GetGeometry(table.Geometry); + break; + } + + InitializeCompositionObject(result, table.Base); + return result; + } + + CompositionShadow? GetShadow(uint index) + { + if (index == Format.NullIndex) + { + return null; + } + + if (index >= (uint)_shadows.Length) + { + throw new FlatBufferFormatException($"Shadow index {index} is out of range."); + } + + if (_shadows[index] is CompositionShadow cached) + { + return cached; + } + + var table = Require(_root.Shadows((int)index), "shadow"); + + CompositionShadow result = table.Kind switch + { + Fb.ShadowKind.Drop => _compositor.CreateDropShadow(), + _ => throw new FlatBufferFormatException($"Unsupported shadow kind {table.Kind}."), + }; + + _shadows[index] = result; + + if (result is DropShadow dropShadow) + { + dropShadow.BlurRadius = table.BlurRadius; + dropShadow.Color = ToColorOrNull(table.Color); + dropShadow.Mask = GetBrush(table.Mask); + dropShadow.Offset = ToVector3(table.Offset); + dropShadow.Opacity = table.Opacity; + + if (table.SourcePolicy.HasValue) + { + dropShadow.SourcePolicy = (CompositionDropShadowSourcePolicy)table.SourcePolicy.Value; + } + } + + InitializeCompositionObject(result, table.Base); + return result; + } + + ICompositionSurface? GetSurface(uint index) + { + if (index == Format.NullIndex) + { + return null; + } + + if (index >= (uint)_surfaces.Length) + { + throw new FlatBufferFormatException($"Surface index {index} is out of range."); + } + + if (_surfaces[index] is ICompositionSurface cached) + { + return cached; + } + + var table = Require(_root.Surfaces((int)index), "surface"); + + switch (table.Kind) + { + case Fb.SurfaceKind.VisualSurface: + var visualSurface = _compositor.CreateVisualSurface(); + _surfaces[index] = visualSurface; + visualSurface.SourceVisual = GetVisual(table.SourceVisual); + visualSurface.SourceSize = ToVector2(table.SourceSize); + visualSurface.SourceOffset = ToVector2(table.SourceOffset); + InitializeCompositionObject(visualSurface, table.Base); + return visualSurface; + + case Fb.SurfaceKind.LoadedImageFromUri: + var uri = GetRequiredString(table.Uri); + var fromUri = LoadedImageSurface.StartLoadFromUri(new Uri(uri, UriKind.RelativeOrAbsolute)); + _surfaces[index] = fromUri; + return fromUri; + + case Fb.SurfaceKind.LoadedImageFromStream: + var bytes = new byte[table.BytesLength]; + for (var i = 0; i < bytes.Length; i++) + { + bytes[i] = table.Bytes(i); + } + + var fromStream = LoadedImageSurface.StartLoadFromStream(bytes); + _surfaces[index] = fromStream; + return fromStream; + + default: + throw new FlatBufferFormatException($"Unsupported surface kind {table.Kind}."); + } + } + + GraphicsEffectBase? GetEffect(uint index) + { + if (index == Format.NullIndex) + { + return null; + } + + if (index >= (uint)_effects.Length) + { + throw new FlatBufferFormatException($"Effect index {index} is out of range."); + } + + if (_effects[index] is GraphicsEffectBase cached) + { + return cached; + } + + var table = Require(_root.Effects((int)index), "effect"); + + var sources = new List(table.SourcesLength); + for (var i = 0; i < table.SourcesLength; i++) + { + sources.Add(new CompositionEffectSourceParameter(GetRequiredString(table.Sources(i)))); + } + + GraphicsEffectBase result = table.Kind switch + { + Fb.EffectKind.Composite => new CompositeEffect((CanvasComposite)table.Mode, sources), + Fb.EffectKind.GaussianBlur => new GaussianBlurEffect( + table.BlurAmount, + sources.Count == 1 + ? sources[0] + : throw new FlatBufferFormatException("A blur effect must have exactly one source.")), + _ => throw new FlatBufferFormatException($"Unsupported effect kind {table.Kind}."), + }; + + _effects[index] = result; + return result; + } + + CompositionEasingFunction? GetEasing(uint index) + { + if (index == Format.NullIndex) + { + return null; + } + + if (index >= (uint)_easings.Length) + { + throw new FlatBufferFormatException($"Easing index {index} is out of range."); + } + + if (_easings[index] is CompositionEasingFunction cached) + { + return cached; + } + + var table = Require(_root.Easings((int)index), "easing"); + + CompositionEasingFunction result; + switch (table.Kind) + { + case Fb.EasingKind.Linear: + result = _compositor.CreateLinearEasingFunction(); + break; + case Fb.EasingKind.CubicBezier: + result = _compositor.CreateCubicBezierEasingFunction( + ToVector2(table.ControlPoint1) ?? Vector2.Zero, + ToVector2(table.ControlPoint2) ?? Vector2.Zero); + break; + case Fb.EasingKind.Step: + var step = _compositor.CreateStepEasingFunction(); + step.StepCount = table.StepCount; + step.InitialStep = table.InitialStep; + step.FinalStep = table.FinalStep; + step.IsInitialStepSingleFrame = table.IsInitialStepSingleFrame; + step.IsFinalStepSingleFrame = table.IsFinalStepSingleFrame; + result = step; + break; + default: + throw new FlatBufferFormatException($"Unsupported easing kind {table.Kind}."); + } + + _easings[index] = result; + + InitializeCompositionObject(result, table.Base); + return result; + } + + CompositionAnimation? GetAnimation(uint index) + { + if (index == Format.NullIndex) + { + return null; + } + + if (index >= (uint)_animations.Length) + { + throw new FlatBufferFormatException($"Animation index {index} is out of range."); + } + + if (_animations[index] is CompositionAnimation cached) + { + return cached; + } + + var table = Require(_root.Animations((int)index), "animation"); + + var result = table.Kind == Fb.AnimationKind.Expression + ? (CompositionAnimation)_compositor.CreateExpressionAnimation( + Expressions.Expression.Scalar(GetRequiredString(table.Expression))) + : CreateKeyFrameAnimation(table); + + _animations[index] = result; + + result.Target = GetString(table.Target); + + for (var i = 0; i < table.ReferenceParametersLength; i++) + { + var parameter = Require(table.ReferenceParameters(i), "reference parameter"); + result.SetReferenceParameter( + GetRequiredString(parameter.Name), + GetObjectReference(parameter.Target) + ?? throw new FlatBufferFormatException("A reference parameter has no target.")); + } + + InitializeCompositionObject(result, table.Base); + return result; + } + + CompositionAnimation CreateKeyFrameAnimation(Fb.Animation table) + { + KeyFrameAnimation_ result = table.Kind switch + { + Fb.AnimationKind.Scalar => _compositor.CreateScalarKeyFrameAnimation(), + Fb.AnimationKind.Vector2 => _compositor.CreateVector2KeyFrameAnimation(), + Fb.AnimationKind.Vector3 => _compositor.CreateVector3KeyFrameAnimation(), + Fb.AnimationKind.Vector4 => _compositor.CreateVector4KeyFrameAnimation(), + Fb.AnimationKind.Color => _compositor.CreateColorKeyFrameAnimation(), + Fb.AnimationKind.Boolean => _compositor.CreateBooleanKeyFrameAnimation(), + Fb.AnimationKind.Path => _compositor.CreatePathKeyFrameAnimation(), + _ => throw new FlatBufferFormatException($"Unsupported animation kind {table.Kind}."), + }; + + result.Duration = TimeSpan.FromTicks(table.DurationTicks); + + if (result is ColorKeyFrameAnimation colorAnimation && table.InterpolationColorSpace.HasValue) + { + colorAnimation.InterpolationColorSpace = + (CompositionColorSpace)table.InterpolationColorSpace.Value; + } + + for (var i = 0; i < table.KeyFramesLength; i++) + { + InsertKeyFrame(result, Require(table.KeyFrames(i), "key frame")); + } + + return result; + } + + void InsertKeyFrame(KeyFrameAnimation_ animation, Fb.KeyFrame frame) + { + var progress = frame.Progress; + var easing = GetEasing(frame.Easing); + + if (frame.Kind == Fb.KeyFrameKind.Expression) + { + var text = GetRequiredString(frame.Expression); + + switch (animation) + { + case ScalarKeyFrameAnimation scalar: + scalar.InsertExpressionKeyFrame(progress, Expressions.Expression.Scalar(text), easing); + break; + case Vector2KeyFrameAnimation vector2: + vector2.InsertExpressionKeyFrame(progress, Expressions.Expression.Vector2(text), easing); + break; + case Vector3KeyFrameAnimation vector3: + vector3.InsertExpressionKeyFrame(progress, Expressions.Expression.Vector3(text), easing); + break; + case Vector4KeyFrameAnimation vector4: + vector4.InsertExpressionKeyFrame(progress, Expressions.Expression.Vector4(text), easing); + break; + case ColorKeyFrameAnimation color: + color.InsertExpressionKeyFrame(progress, Expressions.Expression.Color(text), easing); + break; + case BooleanKeyFrameAnimation boolean: + boolean.InsertExpressionKeyFrame(progress, Expressions.Expression.Boolean(text), easing); + break; + default: + throw new FlatBufferFormatException( + $"{animation.Type} does not support expression key frames."); + } + + return; + } + + switch (animation) + { + case ScalarKeyFrameAnimation scalar: + scalar.InsertKeyFrame(progress, frame.Scalar, easing); + break; + case Vector2KeyFrameAnimation vector2: + vector2.InsertKeyFrame(progress, ToVector2(frame.Vector), easing); + break; + case Vector3KeyFrameAnimation vector3: + vector3.InsertKeyFrame(progress, ToVector3(frame.Vector), easing); + break; + case Vector4KeyFrameAnimation vector4: + vector4.InsertKeyFrame(progress, ToVector4(frame.Vector), easing); + break; + case ColorKeyFrameAnimation color: + color.InsertKeyFrame(progress, ToColor(Require(frame.Color, "color")), easing); + break; + case BooleanKeyFrameAnimation boolean: + boolean.InsertKeyFrame(progress, frame.Scalar != 0, easing); + break; + case PathKeyFrameAnimation path: + path.InsertKeyFrame( + progress, + new CompositionPath( + GetCanvasGeometry(frame.Path) + ?? throw new FlatBufferFormatException("A path key frame has no path.")), + easing); + break; + default: + throw new FlatBufferFormatException($"Unsupported animation {animation.Type}."); + } + } + + CanvasGeometry? GetCanvasGeometry(uint index) + { + if (index == Format.NullIndex) + { + return null; + } + + if (index >= (uint)_canvasGeometries.Length) + { + throw new FlatBufferFormatException($"Canvas geometry index {index} is out of range."); + } + + if (_canvasGeometries[index] is CanvasGeometry cached) + { + return cached; + } + + var table = Require(_root.CanvasGeometries((int)index), "canvas geometry"); + + CanvasGeometry result; + switch (table.Kind) + { + case Fb.CanvasGeometryKind.Combination: + var a = GetCanvasGeometry(table.A) + ?? throw new FlatBufferFormatException("A combination has no first geometry."); + var b = GetCanvasGeometry(table.B) + ?? throw new FlatBufferFormatException("A combination has no second geometry."); + result = a.CombineWith( + b, + ToMatrix3x2(table.Matrix) ?? Matrix3x2.Identity, + (CanvasGeometryCombine)table.CombineMode); + break; + + case Fb.CanvasGeometryKind.TransformedGeometry: + var source = GetCanvasGeometry(table.Source) + ?? throw new FlatBufferFormatException("A transformed geometry has no source."); + result = source.Transform(ToMatrix3x2(table.Matrix) ?? Matrix3x2.Identity); + break; + + case Fb.CanvasGeometryKind.Group: + var geometries = new CanvasGeometry[table.GeometriesLength]; + for (var i = 0; i < geometries.Length; i++) + { + geometries[i] = GetCanvasGeometry(table.Geometries(i)) + ?? throw new FlatBufferFormatException("A grouped geometry is missing."); + } + + result = CanvasGeometry.CreateGroup( + null, + geometries, + (CanvasFilledRegionDetermination)table.FillRule); + break; + + case Fb.CanvasGeometryKind.Path: + result = CreatePath(table); + break; + + case Fb.CanvasGeometryKind.Ellipse: + result = CanvasGeometry.CreateEllipse(null, table.X, table.Y, table.RadiusX, table.RadiusY); + break; + + case Fb.CanvasGeometryKind.RoundedRectangle: + result = CanvasGeometry.CreateRoundedRectangle( + null, table.X, table.Y, table.W, table.H, table.RadiusX, table.RadiusY); + break; + + default: + throw new FlatBufferFormatException($"Unsupported canvas geometry kind {table.Kind}."); + } + + _canvasGeometries[index] = result; + return result; + } + + // Replays the flattened opcode and operand streams of a path. + static CanvasGeometry CreatePath(Fb.CanvasGeometry table) + { + using var builder = new CanvasPathBuilder(null); + builder.SetFilledRegionDetermination((CanvasFilledRegionDetermination)table.FillRule); + + var operand = 0; + + float Next() + => operand < table.OperandsLength + ? table.Operands(operand++) + : throw new FlatBufferFormatException("A path ran out of operands."); + + for (var i = 0; i < table.OpsLength; i++) + { + switch ((Fb.PathOp)table.Ops(i)) + { + case Fb.PathOp.BeginFigure: + builder.BeginFigure(new Vector2(Next(), Next())); + break; + case Fb.PathOp.EndFigure: + builder.EndFigure((CanvasFigureLoop)Next()); + break; + case Fb.PathOp.AddLine: + builder.AddLine(new Vector2(Next(), Next())); + break; + case Fb.PathOp.AddCubicBezier: + builder.AddCubicBezier( + new Vector2(Next(), Next()), + new Vector2(Next(), Next()), + new Vector2(Next(), Next())); + break; + default: + throw new FlatBufferFormatException($"Unsupported path opcode {table.Ops(i)}."); + } + } + + return CanvasGeometry.CreatePath(builder); + } + + // --------------------------------------------------------------------- + // Value helpers. An absent struct field means the property was never set, + // so these return null rather than a default value. + // --------------------------------------------------------------------- + static Wui.Color ToColor(Fb.Color value) + => Wui.Color.FromArgb(value.A, value.R, value.G, value.B); + + static Wui.Color? ToColorOrNull(Fb.Color? value) + => value.HasValue ? ToColor(value.Value) : null; + + static Vector2? ToVector2(Fb.Vec2? value) + => value.HasValue ? new Vector2(value.Value.X, value.Value.Y) : null; + + static Vector3? ToVector3(Fb.Vec3? value) + => value.HasValue ? new Vector3(value.Value.X, value.Value.Y, value.Value.Z) : null; + + static Vector2 ToVector2(Fb.Vec4? value) + => value.HasValue ? new Vector2(value.Value.X, value.Value.Y) : Vector2.Zero; + + static Vector3 ToVector3(Fb.Vec4? value) + => value.HasValue ? new Vector3(value.Value.X, value.Value.Y, value.Value.Z) : Vector3.Zero; + + static Vector4 ToVector4(Fb.Vec4? value) + => value.HasValue + ? new Vector4(value.Value.X, value.Value.Y, value.Value.Z, value.Value.W) + : Vector4.Zero; + + static Matrix3x2? ToMatrix3x2(Fb.Mat3x2? value) + => value.HasValue + ? new Matrix3x2( + value.Value.M11, value.Value.M12, + value.Value.M21, value.Value.M22, + value.Value.M31, value.Value.M32) + : null; + + static Matrix4x4? ToMatrix4x4(Fb.Mat4x4? value) + => value.HasValue + ? new Matrix4x4( + value.Value.M11, value.Value.M12, value.Value.M13, value.Value.M14, + value.Value.M21, value.Value.M22, value.Value.M23, value.Value.M24, + value.Value.M31, value.Value.M32, value.Value.M33, value.Value.M34, + value.Value.M41, value.Value.M42, value.Value.M43, value.Value.M44) + : null; + } +} diff --git a/source/CompDataFlatbuffer/CompositionSerializer.cs b/source/CompDataFlatbuffer/CompositionSerializer.cs new file mode 100644 index 00000000..db618fbf --- /dev/null +++ b/source/CompDataFlatbuffer/CompositionSerializer.cs @@ -0,0 +1,1159 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable enable + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using CommunityToolkit.WinUI.Lottie.CompMetadata; +using CommunityToolkit.WinUI.Lottie.LottieMetadata; +using CommunityToolkit.WinUI.Lottie.WinCompData; +using CommunityToolkit.WinUI.Lottie.WinCompData.MetaData; +using CommunityToolkit.WinUI.Lottie.WinCompData.Mgce; +using CommunityToolkit.WinUI.Lottie.WinCompData.Mgcg; +using CommunityToolkit.WinUI.Lottie.WinUIXamlMediaData; +using Google.FlatBuffers; +using Expressions = CommunityToolkit.WinUI.Lottie.WinCompData.Expressions; +using Fb = CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema; +using Wui = CommunityToolkit.WinUI.Lottie.WinCompData.Wui; + +namespace CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer +{ + /// + /// Serializes a translated Lottie animation - a WinCompData object graph - into the + /// FlatBuffers format described by lottie_comp.fbs. + /// + /// + /// The output is deterministic: serializing the same graph twice produces byte + /// identical results. + /// +#if PUBLIC_CompDataFlatbuffer + public +#endif + static class CompositionSerializer + { + /// + /// Serializes a WinCompData graph into a FlatBuffer. + /// + /// The root visual of the graph. + /// The minimum UAP version required to instantiate the graph. + /// Metadata describing the source Lottie animation, or null. + /// The property bindings exposed by the graph, or null. + /// The width of the source Lottie animation. + /// The height of the source Lottie animation. + /// The serialized graph. + public static byte[] Serialize( + Visual root, + ushort requiredUapVersion, + LottieCompositionMetadata? metadata = null, + IReadOnlyList? propertyBindings = null, + float width = 0, + float height = 0) + { + if (root is null) + { + throw new ArgumentNullException(nameof(root)); + } + + var graph = GraphIndexer.Index(root); + + // 1024 is a starting size only - the builder grows as needed. + var builder = new FlatBufferBuilder(1024); + + // Metadata strings are interned before the table is written, because the + // metadata is serialized last but its strings must be in the table. + InternMetadataStrings(graph, metadata, propertyBindings); + + // Strings are created first because a string cannot be created while a table + // is under construction, and almost every table refers to one. + var strings = new StringOffset[graph.StringList.Count]; + for (var i = 0; i < strings.Length; i++) + { + strings[i] = builder.CreateString(graph.StringList[i]); + } + + // From here on, interning a new string would produce an index past the end of + // the table that was just written, so the table is closed to additions. + graph.FreezeStrings(); + + // The node lists grow as the graph is walked, so they are indexed by position + // rather than iterated, and the walk is complete before serialization starts. + var visuals = Map(graph.VisualList, v => WriteVisual(builder, graph, v)); + var shapes = Map(graph.ShapeList, v => WriteShape(builder, graph, v)); + var geometries = Map(graph.GeometryList, v => WriteGeometry(builder, graph, v)); + var canvasGeometries = Map(graph.CanvasGeometryList, v => WriteCanvasGeometry(builder, graph, v)); + var brushes = Map(graph.BrushList, v => WriteBrush(builder, graph, v)); + var gradientStops = Map(graph.GradientStopList, v => WriteGradientStop(builder, graph, v)); + var viewBoxes = Map(graph.ViewBoxList, v => WriteViewBox(builder, graph, v)); + var clips = Map(graph.ClipList, v => WriteClip(builder, graph, v)); + var shadows = Map(graph.ShadowList, v => WriteShadow(builder, graph, v)); + var surfaces = Map(graph.SurfaceList, v => WriteSurface(builder, graph, v, strings)); + var effects = Map(graph.EffectList, v => WriteEffect(builder, graph, v)); + var easings = Map(graph.EasingList, v => WriteEasing(builder, graph, v)); + var animations = Map(graph.AnimationList, v => WriteAnimation(builder, graph, v)); + var propertySets = Map(graph.PropertySetList, v => WritePropertySet(builder, graph, v)); + var controllers = Map(graph.ControllerList, v => WriteController(builder, graph, v)); + + var metadataOffset = WriteMetadata(builder, graph, metadata, propertyBindings, width, height); + + // The indices of the controllers that a host must supply, in index order. + var customControllers = graph.ControllerList + .Select((controller, index) => (controller, index)) + .Where(x => x.controller.IsCustom) + .Select(x => (uint)x.index) + .ToArray(); + + var stringsVector = Fb.LottieComposition.CreateStringsVector(builder, strings); + var visualsVector = Fb.LottieComposition.CreateVisualsVector(builder, visuals); + var shapesVector = Fb.LottieComposition.CreateShapesVector(builder, shapes); + var geometriesVector = Fb.LottieComposition.CreateGeometriesVector(builder, geometries); + var canvasGeometriesVector = Fb.LottieComposition.CreateCanvasGeometriesVector(builder, canvasGeometries); + var brushesVector = Fb.LottieComposition.CreateBrushesVector(builder, brushes); + var gradientStopsVector = Fb.LottieComposition.CreateGradientStopsVector(builder, gradientStops); + var viewBoxesVector = Fb.LottieComposition.CreateViewBoxesVector(builder, viewBoxes); + var clipsVector = Fb.LottieComposition.CreateClipsVector(builder, clips); + var shadowsVector = Fb.LottieComposition.CreateShadowsVector(builder, shadows); + var surfacesVector = Fb.LottieComposition.CreateSurfacesVector(builder, surfaces); + var effectsVector = Fb.LottieComposition.CreateEffectsVector(builder, effects); + var easingsVector = Fb.LottieComposition.CreateEasingsVector(builder, easings); + var animationsVector = Fb.LottieComposition.CreateAnimationsVector(builder, animations); + var propertySetsVector = Fb.LottieComposition.CreatePropertySetsVector(builder, propertySets); + var controllersVector = Fb.LottieComposition.CreateControllersVector(builder, controllers); + var customControllersVector = Fb.LottieComposition.CreateCustomControllersVector(builder, customControllers); + + Fb.LottieComposition.StartLottieComposition(builder); + Fb.LottieComposition.AddSchemaVersion(builder, Format.Version); + Fb.LottieComposition.AddRequiredUapVersion(builder, requiredUapVersion); + Fb.LottieComposition.AddMetadata(builder, metadataOffset); + Fb.LottieComposition.AddRootVisual(builder, graph.GetVisual(root)); + Fb.LottieComposition.AddStrings(builder, stringsVector); + Fb.LottieComposition.AddVisuals(builder, visualsVector); + Fb.LottieComposition.AddShapes(builder, shapesVector); + Fb.LottieComposition.AddGeometries(builder, geometriesVector); + Fb.LottieComposition.AddCanvasGeometries(builder, canvasGeometriesVector); + Fb.LottieComposition.AddBrushes(builder, brushesVector); + Fb.LottieComposition.AddGradientStops(builder, gradientStopsVector); + Fb.LottieComposition.AddViewBoxes(builder, viewBoxesVector); + Fb.LottieComposition.AddClips(builder, clipsVector); + Fb.LottieComposition.AddShadows(builder, shadowsVector); + Fb.LottieComposition.AddSurfaces(builder, surfacesVector); + Fb.LottieComposition.AddEffects(builder, effectsVector); + Fb.LottieComposition.AddEasings(builder, easingsVector); + Fb.LottieComposition.AddAnimations(builder, animationsVector); + Fb.LottieComposition.AddPropertySets(builder, propertySetsVector); + Fb.LottieComposition.AddControllers(builder, controllersVector); + Fb.LottieComposition.AddCustomControllers(builder, customControllersVector); + var composition = Fb.LottieComposition.EndLottieComposition(builder); + + Fb.LottieComposition.FinishLottieCompositionBuffer(builder, composition); + + return builder.SizedByteArray(); + } + + // Interns every string that WriteMetadata will need. Kept adjacent to + // WriteMetadata so that the two stay in step. + static void InternMetadataStrings( + GraphIndexer graph, + LottieCompositionMetadata? metadata, + IReadOnlyList? propertyBindings) + { + graph.GetString(metadata?.CompositionName); + + if (metadata is not null) + { + foreach (var marker in metadata.Markers) + { + graph.GetString(marker.Name); + } + } + + if (propertyBindings is not null) + { + foreach (var binding in propertyBindings) + { + graph.GetString(binding.BindingName); + graph.GetString(binding.DisplayName); + } + } + } + + static TResult[] Map(List source, Func selector) + { + // The list is indexed rather than enumerated because writing a node can + // never add to it - the graph walk completed before serialization started. + var result = new TResult[source.Count]; + for (var i = 0; i < source.Count; i++) + { + result[i] = selector(source[i]); + } + + return result; + } + + // --------------------------------------------------------------------- + // Shared state. + // --------------------------------------------------------------------- + // Writes the CompositionObject state shared by every node, or returns a null + // offset if the object carries none of it. + static Offset WriteCompObj(FlatBufferBuilder builder, GraphIndexer graph, CompositionObject value) + { + var comment = graph.GetString(value.Comment); + + var animators = value.Animators.ToArray(); + var animatorOffsets = new Offset[animators.Length]; + for (var i = 0; i < animators.Length; i++) + { + var animator = animators[i]; + Fb.Animator.StartAnimator(builder); + Fb.Animator.AddProperty(builder, graph.GetString(animator.AnimatedProperty)); + Fb.Animator.AddAnimation(builder, graph.GetAnimation(animator.Animation)); + Fb.Animator.AddController(builder, graph.GetController(animator.Controller)); + animatorOffsets[i] = Fb.Animator.EndAnimator(builder); + } + + // The property set of a property set is itself, so it is never written as a + // nested reference. + var properties = value.Type != CompositionObjectType.CompositionPropertySet && GraphIndexer.HasState(value.Properties) + ? graph.GetPropertySet(value.Properties) + : Format.NullIndex; + + if (comment == Format.NullIndex && animators.Length == 0 && properties == Format.NullIndex) + { + return default; + } + + var animatorsVector = animators.Length == 0 + ? default + : Fb.CompObj.CreateAnimatorsVector(builder, animatorOffsets); + + Fb.CompObj.StartCompObj(builder); + Fb.CompObj.AddComment(builder, comment); + + if (animators.Length > 0) + { + Fb.CompObj.AddAnimators(builder, animatorsVector); + } + + Fb.CompObj.AddProperties(builder, properties); + return Fb.CompObj.EndCompObj(builder); + } + + static void AddBase(FlatBufferBuilder builder, Offset value, Action> add) + { + if (value.Value != 0) + { + add(builder, value); + } + } + + // --------------------------------------------------------------------- + // Nodes. + // --------------------------------------------------------------------- + static Offset WriteVisual(FlatBufferBuilder builder, GraphIndexer graph, Visual value) + { + var compObj = WriteCompObj(builder, graph, value); + + var children = value is ContainerVisual container && container.Children.Count > 0 + ? Fb.Visual.CreateChildrenVector(builder, container.Children.Select(graph.GetVisual).ToArray()) + : default; + + var shapes = value is ShapeVisual shapeVisual && shapeVisual.Shapes.Count > 0 + ? Fb.Visual.CreateShapesVector(builder, shapeVisual.Shapes.Select(graph.GetShape).ToArray()) + : default; + + Fb.Visual.StartVisual(builder); + AddBase(builder, compObj, Fb.Visual.AddBase); + Fb.Visual.AddKind(builder, value switch + { + ShapeVisual _ => Fb.VisualKind.Shape, + SpriteVisual _ => Fb.VisualKind.Sprite, + LayerVisual _ => Fb.VisualKind.Layer, + _ => Fb.VisualKind.Container, + }); + + Fb.Visual.AddBorderMode(builder, (byte?)value.BorderMode); + AddVec3(builder, value.CenterPoint, Fb.Visual.AddCenterPoint); + Fb.Visual.AddClip(builder, graph.GetClip(value.Clip)); + Fb.Visual.AddIsVisible(builder, value.IsVisible); + AddVec3(builder, value.Offset, Fb.Visual.AddOffset); + Fb.Visual.AddOpacity(builder, value.Opacity); + Fb.Visual.AddRotationAngleInDegrees(builder, value.RotationAngleInDegrees); + AddVec3(builder, value.RotationAxis, Fb.Visual.AddRotationAxis); + AddVec3(builder, value.Scale, Fb.Visual.AddScale); + AddVec2(builder, value.Size, Fb.Visual.AddSize); + AddMat4x4(builder, value.TransformMatrix, Fb.Visual.AddTransformMatrix); + + if (children.Value != 0) + { + Fb.Visual.AddChildren(builder, children); + } + + if (shapes.Value != 0) + { + Fb.Visual.AddShapes(builder, shapes); + } + + switch (value) + { + case ShapeVisual shape: + Fb.Visual.AddViewBox(builder, graph.GetViewBox(shape.ViewBox)); + break; + case SpriteVisual sprite: + Fb.Visual.AddBrush(builder, graph.GetBrush(sprite.Brush)); + Fb.Visual.AddShadow(builder, graph.GetShadow(sprite.Shadow)); + break; + case LayerVisual layer: + Fb.Visual.AddShadow(builder, graph.GetShadow(layer.Shadow)); + break; + } + + return Fb.Visual.EndVisual(builder); + } + + static Offset WriteShape(FlatBufferBuilder builder, GraphIndexer graph, CompositionShape value) + { + var compObj = WriteCompObj(builder, graph, value); + + var shapes = value is CompositionContainerShape containerShape && containerShape.Shapes.Count > 0 + ? Fb.Shape.CreateShapesVector(builder, containerShape.Shapes.Select(graph.GetShape).ToArray()) + : default; + + var spriteShape = value as CompositionSpriteShape; + + var strokeDashArray = spriteShape is not null && spriteShape.StrokeDashArray.Count > 0 + ? Fb.Shape.CreateStrokeDashArrayVector(builder, spriteShape.StrokeDashArray.ToArray()) + : default; + + Fb.Shape.StartShape(builder); + AddBase(builder, compObj, Fb.Shape.AddBase); + Fb.Shape.AddKind(builder, spriteShape is not null ? Fb.ShapeKind.Sprite : Fb.ShapeKind.Container); + + AddVec2(builder, value.CenterPoint, Fb.Shape.AddCenterPoint); + AddVec2(builder, value.Offset, Fb.Shape.AddOffset); + Fb.Shape.AddRotationAngleInDegrees(builder, value.RotationAngleInDegrees); + AddVec2(builder, value.Scale, Fb.Shape.AddScale); + AddMat3x2(builder, value.TransformMatrix, Fb.Shape.AddTransformMatrix); + + if (shapes.Value != 0) + { + Fb.Shape.AddShapes(builder, shapes); + } + + if (spriteShape is not null) + { + Fb.Shape.AddFillBrush(builder, graph.GetBrush(spriteShape.FillBrush)); + Fb.Shape.AddStrokeBrush(builder, graph.GetBrush(spriteShape.StrokeBrush)); + Fb.Shape.AddGeometry(builder, graph.GetGeometry(spriteShape.Geometry)); + Fb.Shape.AddIsStrokeNonScaling(builder, spriteShape.IsStrokeNonScaling); + Fb.Shape.AddStrokeDashOffset(builder, spriteShape.StrokeDashOffset); + + if (strokeDashArray.Value != 0) + { + Fb.Shape.AddStrokeDashArray(builder, strokeDashArray); + } + + Fb.Shape.AddStrokeDashCap(builder, (byte?)spriteShape.StrokeDashCap); + Fb.Shape.AddStrokeStartCap(builder, (byte?)spriteShape.StrokeStartCap); + Fb.Shape.AddStrokeEndCap(builder, (byte?)spriteShape.StrokeEndCap); + Fb.Shape.AddStrokeLineJoin(builder, (byte?)spriteShape.StrokeLineJoin); + Fb.Shape.AddStrokeMiterLimit(builder, spriteShape.StrokeMiterLimit); + Fb.Shape.AddStrokeThickness(builder, spriteShape.StrokeThickness); + } + + return Fb.Shape.EndShape(builder); + } + + static Offset WriteGeometry(FlatBufferBuilder builder, GraphIndexer graph, CompositionGeometry value) + { + var compObj = WriteCompObj(builder, graph, value); + + Fb.Geometry.StartGeometry(builder); + AddBase(builder, compObj, Fb.Geometry.AddBase); + Fb.Geometry.AddKind(builder, value switch + { + CompositionRectangleGeometry _ => Fb.GeometryKind.Rectangle, + CompositionRoundedRectangleGeometry _ => Fb.GeometryKind.RoundedRectangle, + CompositionEllipseGeometry _ => Fb.GeometryKind.Ellipse, + _ => Fb.GeometryKind.Path, + }); + + Fb.Geometry.AddTrimStart(builder, value.TrimStart); + Fb.Geometry.AddTrimEnd(builder, value.TrimEnd); + Fb.Geometry.AddTrimOffset(builder, value.TrimOffset); + + switch (value) + { + case CompositionPathGeometry path: + Fb.Geometry.AddPath( + builder, + path.Path is null + ? Format.NullIndex + : graph.GetCanvasGeometry((CanvasGeometry)path.Path.Source)); + break; + case CompositionRectangleGeometry rectangle: + AddVec2(builder, rectangle.Offset, Fb.Geometry.AddOffset); + AddVec2(builder, rectangle.Size, Fb.Geometry.AddSize); + break; + case CompositionRoundedRectangleGeometry roundedRectangle: + AddVec2(builder, roundedRectangle.Offset, Fb.Geometry.AddOffset); + AddVec2(builder, roundedRectangle.Size, Fb.Geometry.AddSize); + AddVec2(builder, roundedRectangle.CornerRadius, Fb.Geometry.AddCornerRadius); + break; + case CompositionEllipseGeometry ellipse: + AddVec2(builder, ellipse.Center, Fb.Geometry.AddCenter); + AddVec2(builder, ellipse.Radius, Fb.Geometry.AddRadius); + break; + } + + return Fb.Geometry.EndGeometry(builder); + } + + static Offset WriteBrush(FlatBufferBuilder builder, GraphIndexer graph, CompositionBrush value) + { + var compObj = WriteCompObj(builder, graph, value); + + var gradientBrush = value as CompositionGradientBrush; + + var colorStops = gradientBrush is not null && gradientBrush.ColorStops.Count > 0 + ? Fb.Brush.CreateColorStopsVector(builder, gradientBrush.ColorStops.Select(graph.GetGradientStop).ToArray()) + : default; + + var sourceParameters = default(VectorOffset); + if (value is CompositionEffectBrush effectBrush) + { + var sources = effectBrush.GetEffectFactory().Effect.Sources; + var offsets = new Offset[sources.Count]; + for (var i = 0; i < sources.Count; i++) + { + var name = sources[i].Name; + Fb.SourceParameter.StartSourceParameter(builder); + Fb.SourceParameter.AddName(builder, graph.GetString(name)); + Fb.SourceParameter.AddBrush(builder, graph.GetBrush(effectBrush.GetSourceParameter(name))); + offsets[i] = Fb.SourceParameter.EndSourceParameter(builder); + } + + if (offsets.Length > 0) + { + sourceParameters = Fb.Brush.CreateSourceParametersVector(builder, offsets); + } + } + + Fb.Brush.StartBrush(builder); + AddBase(builder, compObj, Fb.Brush.AddBase); + Fb.Brush.AddKind(builder, value switch + { + CompositionLinearGradientBrush _ => Fb.BrushKind.LinearGradient, + CompositionRadialGradientBrush _ => Fb.BrushKind.RadialGradient, + CompositionSurfaceBrush _ => Fb.BrushKind.Surface, + CompositionMaskBrush _ => Fb.BrushKind.Mask, + CompositionEffectBrush _ => Fb.BrushKind.Effect, + _ => Fb.BrushKind.Color, + }); + + switch (value) + { + case CompositionColorBrush colorBrush: + AddColor(builder, colorBrush.Color, Fb.Brush.AddColor); + break; + case CompositionSurfaceBrush surfaceBrush: + Fb.Brush.AddSurface(builder, graph.GetSurface(surfaceBrush.Surface)); + break; + case CompositionMaskBrush maskBrush: + Fb.Brush.AddSource(builder, graph.GetBrush(maskBrush.Source)); + Fb.Brush.AddMask(builder, graph.GetBrush(maskBrush.Mask)); + break; + case CompositionEffectBrush effect: + Fb.Brush.AddEffect(builder, graph.GetEffect(effect.GetEffectFactory().Effect)); + + if (sourceParameters.Value != 0) + { + Fb.Brush.AddSourceParameters(builder, sourceParameters); + } + + break; + } + + if (gradientBrush is not null) + { + AddVec2(builder, gradientBrush.AnchorPoint, Fb.Brush.AddAnchorPoint); + AddVec2(builder, gradientBrush.CenterPoint, Fb.Brush.AddCenterPoint); + + if (colorStops.Value != 0) + { + Fb.Brush.AddColorStops(builder, colorStops); + } + + Fb.Brush.AddExtendMode(builder, (byte?)gradientBrush.ExtendMode); + Fb.Brush.AddInterpolationSpace(builder, (byte?)gradientBrush.InterpolationSpace); + Fb.Brush.AddMappingMode(builder, (byte?)gradientBrush.MappingMode); + AddVec2(builder, gradientBrush.Offset, Fb.Brush.AddOffset); + Fb.Brush.AddRotationAngleInDegrees(builder, gradientBrush.RotationAngleInDegrees); + AddVec2(builder, gradientBrush.Scale, Fb.Brush.AddScale); + AddMat3x2(builder, gradientBrush.TransformMatrix, Fb.Brush.AddTransformMatrix); + + switch (gradientBrush) + { + case CompositionLinearGradientBrush linear: + AddVec2(builder, linear.StartPoint, Fb.Brush.AddStartPoint); + AddVec2(builder, linear.EndPoint, Fb.Brush.AddEndPoint); + break; + case CompositionRadialGradientBrush radial: + AddVec2(builder, radial.EllipseCenter, Fb.Brush.AddEllipseCenter); + AddVec2(builder, radial.EllipseRadius, Fb.Brush.AddEllipseRadius); + AddVec2(builder, radial.GradientOriginOffset, Fb.Brush.AddGradientOriginOffset); + break; + } + } + + return Fb.Brush.EndBrush(builder); + } + + static Offset WriteGradientStop(FlatBufferBuilder builder, GraphIndexer graph, CompositionColorGradientStop value) + { + var compObj = WriteCompObj(builder, graph, value); + + Fb.GradientStop.StartGradientStop(builder); + AddBase(builder, compObj, Fb.GradientStop.AddBase); + AddColor(builder, value.Color, Fb.GradientStop.AddColor); + Fb.GradientStop.AddOffset(builder, value.Offset); + return Fb.GradientStop.EndGradientStop(builder); + } + + static Offset WriteViewBox(FlatBufferBuilder builder, GraphIndexer graph, CompositionViewBox value) + { + var compObj = WriteCompObj(builder, graph, value); + + Fb.ViewBox.StartViewBox(builder); + AddBase(builder, compObj, Fb.ViewBox.AddBase); + AddVec2(builder, value.Size, Fb.ViewBox.AddSize); + return Fb.ViewBox.EndViewBox(builder); + } + + static Offset WriteClip(FlatBufferBuilder builder, GraphIndexer graph, CompositionClip value) + { + var compObj = WriteCompObj(builder, graph, value); + + Fb.Clip.StartClip(builder); + AddBase(builder, compObj, Fb.Clip.AddBase); + Fb.Clip.AddKind(builder, value is CompositionGeometricClip ? Fb.ClipKind.Geometric : Fb.ClipKind.Inset); + AddVec2(builder, value.CenterPoint, Fb.Clip.AddCenterPoint); + AddVec2(builder, value.Scale, Fb.Clip.AddScale); + + switch (value) + { + case InsetClip inset: + Fb.Clip.AddLeftInset(builder, inset.LeftInset); + Fb.Clip.AddRightInset(builder, inset.RightInset); + Fb.Clip.AddTopInset(builder, inset.TopInset); + Fb.Clip.AddBottomInset(builder, inset.BottomInset); + break; + case CompositionGeometricClip geometric: + Fb.Clip.AddGeometry(builder, graph.GetGeometry(geometric.Geometry)); + break; + } + + return Fb.Clip.EndClip(builder); + } + + static Offset WriteShadow(FlatBufferBuilder builder, GraphIndexer graph, CompositionShadow value) + { + var compObj = WriteCompObj(builder, graph, value); + + Fb.Shadow.StartShadow(builder); + AddBase(builder, compObj, Fb.Shadow.AddBase); + Fb.Shadow.AddKind(builder, Fb.ShadowKind.Drop); + + if (value is DropShadow dropShadow) + { + Fb.Shadow.AddBlurRadius(builder, dropShadow.BlurRadius); + AddColor(builder, dropShadow.Color, Fb.Shadow.AddColor); + Fb.Shadow.AddMask(builder, graph.GetBrush(dropShadow.Mask)); + AddVec3(builder, dropShadow.Offset, Fb.Shadow.AddOffset); + Fb.Shadow.AddOpacity(builder, dropShadow.Opacity); + Fb.Shadow.AddSourcePolicy(builder, (byte?)dropShadow.SourcePolicy); + } + + return Fb.Shadow.EndShadow(builder); + } + + static Offset WriteSurface(FlatBufferBuilder builder, GraphIndexer graph, ICompositionSurface value, StringOffset[] strings) + { + var compObj = value is CompositionObject compositionObject + ? WriteCompObj(builder, graph, compositionObject) + : default; + + var bytes = value is LoadedImageSurfaceFromStream fromStream + ? Fb.Surface.CreateBytesVector(builder, fromStream.Bytes) + : default; + + Fb.Surface.StartSurface(builder); + AddBase(builder, compObj, Fb.Surface.AddBase); + Fb.Surface.AddKind(builder, value switch + { + LoadedImageSurfaceFromUri _ => Fb.SurfaceKind.LoadedImageFromUri, + LoadedImageSurfaceFromStream _ => Fb.SurfaceKind.LoadedImageFromStream, + _ => Fb.SurfaceKind.VisualSurface, + }); + + switch (value) + { + case CompositionVisualSurface visualSurface: + Fb.Surface.AddSourceVisual(builder, graph.GetVisual(visualSurface.SourceVisual)); + AddVec2(builder, visualSurface.SourceSize, Fb.Surface.AddSourceSize); + AddVec2(builder, visualSurface.SourceOffset, Fb.Surface.AddSourceOffset); + break; + case LoadedImageSurfaceFromUri fromUri: + Fb.Surface.AddUri(builder, graph.GetString(fromUri.Uri.ToString())); + break; + case LoadedImageSurfaceFromStream _: + Fb.Surface.AddBytes(builder, bytes); + break; + } + + return Fb.Surface.EndSurface(builder); + } + + static Offset WriteEffect(FlatBufferBuilder builder, GraphIndexer graph, GraphicsEffectBase value) + { + var sources = Fb.Effect.CreateSourcesVector( + builder, + value.Sources.Select(s => graph.GetString(s.Name)).ToArray()); + + Fb.Effect.StartEffect(builder); + Fb.Effect.AddKind(builder, value switch + { + GaussianBlurEffect _ => Fb.EffectKind.GaussianBlur, + _ => Fb.EffectKind.Composite, + }); + + Fb.Effect.AddSources(builder, sources); + + switch (value) + { + case CompositeEffect composite: + Fb.Effect.AddMode(builder, (byte)composite.Mode); + break; + case GaussianBlurEffect blur: + Fb.Effect.AddBlurAmount(builder, blur.BlurAmount); + break; + } + + return Fb.Effect.EndEffect(builder); + } + + static Offset WriteEasing(FlatBufferBuilder builder, GraphIndexer graph, CompositionEasingFunction value) + { + var compObj = WriteCompObj(builder, graph, value); + + Fb.Easing.StartEasing(builder); + AddBase(builder, compObj, Fb.Easing.AddBase); + Fb.Easing.AddKind(builder, value switch + { + CubicBezierEasingFunction _ => Fb.EasingKind.CubicBezier, + StepEasingFunction _ => Fb.EasingKind.Step, + _ => Fb.EasingKind.Linear, + }); + + switch (value) + { + case CubicBezierEasingFunction cubicBezier: + AddVec2(builder, cubicBezier.ControlPoint1, Fb.Easing.AddControlPoint1); + AddVec2(builder, cubicBezier.ControlPoint2, Fb.Easing.AddControlPoint2); + break; + case StepEasingFunction step: + Fb.Easing.AddStepCount(builder, step.StepCount); + Fb.Easing.AddInitialStep(builder, step.InitialStep); + Fb.Easing.AddFinalStep(builder, step.FinalStep); + Fb.Easing.AddIsInitialStepSingleFrame(builder, step.IsInitialStepSingleFrame); + Fb.Easing.AddIsFinalStepSingleFrame(builder, step.IsFinalStepSingleFrame); + break; + } + + return Fb.Easing.EndEasing(builder); + } + + static Offset WriteAnimation(FlatBufferBuilder builder, GraphIndexer graph, CompositionAnimation value) + { + var compObj = WriteCompObj(builder, graph, value); + + // ReferenceParameters is a dictionary, so it is sorted by name to keep the + // output deterministic. + var parameters = value.ReferenceParameters.OrderBy(p => p.Key, StringComparer.Ordinal).ToArray(); + var parameterOffsets = new Offset[parameters.Length]; + for (var i = 0; i < parameters.Length; i++) + { + Fb.ReferenceParameter.StartReferenceParameter(builder); + Fb.ReferenceParameter.AddName(builder, graph.GetString(parameters[i].Key)); + Fb.ReferenceParameter.AddTarget(builder, graph.GetObjectReference(parameters[i].Value)); + parameterOffsets[i] = Fb.ReferenceParameter.EndReferenceParameter(builder); + } + + var parametersVector = parameters.Length == 0 + ? default + : Fb.Animation.CreateReferenceParametersVector(builder, parameterOffsets); + + var keyFramesVector = default(VectorOffset); + if (value is KeyFrameAnimation_ keyFrameAnimation) + { + var keyFrames = keyFrameAnimation.KeyFrames.ToArray(); + var keyFrameOffsets = new Offset[keyFrames.Length]; + for (var i = 0; i < keyFrames.Length; i++) + { + keyFrameOffsets[i] = WriteKeyFrame(builder, graph, keyFrames[i]); + } + + if (keyFrameOffsets.Length > 0) + { + keyFramesVector = Fb.Animation.CreateKeyFramesVector(builder, keyFrameOffsets); + } + } + + Fb.Animation.StartAnimation(builder); + AddBase(builder, compObj, Fb.Animation.AddBase); + Fb.Animation.AddKind(builder, value switch + { + ExpressionAnimation _ => Fb.AnimationKind.Expression, + ColorKeyFrameAnimation _ => Fb.AnimationKind.Color, + BooleanKeyFrameAnimation _ => Fb.AnimationKind.Boolean, + PathKeyFrameAnimation _ => Fb.AnimationKind.Path, + ScalarKeyFrameAnimation _ => Fb.AnimationKind.Scalar, + Vector2KeyFrameAnimation _ => Fb.AnimationKind.Vector2, + Vector3KeyFrameAnimation _ => Fb.AnimationKind.Vector3, + Vector4KeyFrameAnimation _ => Fb.AnimationKind.Vector4, + _ => throw new InvalidOperationException($"Unsupported animation {value.Type}."), + }); + + Fb.Animation.AddTarget(builder, graph.GetString(value.Target)); + + if (parametersVector.Value != 0) + { + Fb.Animation.AddReferenceParameters(builder, parametersVector); + } + + if (value is ExpressionAnimation expressionAnimation) + { + Fb.Animation.AddExpression(builder, graph.GetString(expressionAnimation.Expression.ToText())); + } + + if (value is KeyFrameAnimation_ keyFrames_) + { + Fb.Animation.AddDurationTicks(builder, keyFrames_.Duration.Ticks); + + if (keyFramesVector.Value != 0) + { + Fb.Animation.AddKeyFrames(builder, keyFramesVector); + } + } + + if (value is ColorKeyFrameAnimation color) + { + Fb.Animation.AddInterpolationColorSpace(builder, (byte)color.InterpolationColorSpace); + } + + return Fb.Animation.EndAnimation(builder); + } + + static Offset WriteKeyFrame(FlatBufferBuilder builder, GraphIndexer graph, KeyFrameAnimation_.KeyFrame value) + { + Fb.KeyFrame.StartKeyFrame(builder); + Fb.KeyFrame.AddProgress(builder, value.Progress); + Fb.KeyFrame.AddEasing(builder, graph.GetEasing(value.Easing)); + Fb.KeyFrame.AddKind(builder, value.Type == KeyFrameType.Expression ? Fb.KeyFrameKind.Expression : Fb.KeyFrameKind.Value); + + switch (value) + { + case KeyFrameAnimation_.ExpressionKeyFrame expression: + Fb.KeyFrame.AddExpression(builder, graph.GetString(expression.Expression.ToText())); + break; + case KeyFrameAnimation.ValueKeyFrame scalar: + Fb.KeyFrame.AddScalar(builder, scalar.Value); + break; + case KeyFrameAnimation.ValueKeyFrame boolean: + Fb.KeyFrame.AddScalar(builder, boolean.Value ? 1f : 0f); + break; + case KeyFrameAnimation.ValueKeyFrame vector2: + Fb.KeyFrame.AddVector(builder, Fb.Vec4.CreateVec4(builder, vector2.Value.X, vector2.Value.Y, 0, 0)); + break; + case KeyFrameAnimation.ValueKeyFrame vector3: + Fb.KeyFrame.AddVector(builder, Fb.Vec4.CreateVec4(builder, vector3.Value.X, vector3.Value.Y, vector3.Value.Z, 0)); + break; + case KeyFrameAnimation.ValueKeyFrame vector4: + Fb.KeyFrame.AddVector(builder, Fb.Vec4.CreateVec4(builder, vector4.Value.X, vector4.Value.Y, vector4.Value.Z, vector4.Value.W)); + break; + case KeyFrameAnimation.ValueKeyFrame colorFrame: + Fb.KeyFrame.AddColor(builder, CreateColor(builder, colorFrame.Value)); + break; + case KeyFrameAnimation.ValueKeyFrame path: + Fb.KeyFrame.AddPath(builder, graph.GetCanvasGeometry((CanvasGeometry)path.Value.Source)); + break; + } + + return Fb.KeyFrame.EndKeyFrame(builder); + } + + static Offset WritePropertySet(FlatBufferBuilder builder, GraphIndexer graph, CompositionPropertySet value) + { + var compObj = WriteCompObj(builder, graph, value); + + // Names is a SortedDictionary, so enumeration order is already deterministic. + var names = value.Names.ToArray(); + var valueOffsets = new Offset[names.Length]; + for (var i = 0; i < names.Length; i++) + { + valueOffsets[i] = WritePropertyValue(builder, graph, value, names[i].Key, names[i].Value); + } + + var valuesVector = names.Length == 0 + ? default + : Fb.PropertySet.CreateValuesVector(builder, valueOffsets); + + Fb.PropertySet.StartPropertySet(builder); + AddBase(builder, compObj, Fb.PropertySet.AddBase); + Fb.PropertySet.AddOwner(builder, graph.GetObjectReference(value.Owner)); + + if (valuesVector.Value != 0) + { + Fb.PropertySet.AddValues(builder, valuesVector); + } + + return Fb.PropertySet.EndPropertySet(builder); + } + + static Offset WritePropertyValue( + FlatBufferBuilder builder, + GraphIndexer graph, + CompositionPropertySet propertySet, + string name, + PropertySetValueType type) + { + Fb.PropertyValue.StartPropertyValue(builder); + Fb.PropertyValue.AddName(builder, graph.GetString(name)); + Fb.PropertyValue.AddType(builder, (Fb.PropertyValueType)type); + + switch (type) + { + case PropertySetValueType.Color: + propertySet.TryGetColor(name, out var color); + Fb.PropertyValue.AddColor(builder, CreateColor(builder, color!.Value)); + break; + case PropertySetValueType.Scalar: + propertySet.TryGetScalar(name, out var scalar); + Fb.PropertyValue.AddScalar(builder, scalar!.Value); + break; + case PropertySetValueType.Vector2: + propertySet.TryGetVector2(name, out var vector2); + Fb.PropertyValue.AddVector(builder, Fb.Vec4.CreateVec4(builder, vector2!.Value.X, vector2.Value.Y, 0, 0)); + break; + case PropertySetValueType.Vector3: + propertySet.TryGetVector3(name, out var vector3); + Fb.PropertyValue.AddVector(builder, Fb.Vec4.CreateVec4(builder, vector3!.Value.X, vector3.Value.Y, vector3.Value.Z, 0)); + break; + case PropertySetValueType.Vector4: + propertySet.TryGetVector4(name, out var vector4); + Fb.PropertyValue.AddVector(builder, Fb.Vec4.CreateVec4(builder, vector4!.Value.X, vector4.Value.Y, vector4.Value.Z, vector4.Value.W)); + break; + } + + return Fb.PropertyValue.EndPropertyValue(builder); + } + + static Offset WriteController(FlatBufferBuilder builder, GraphIndexer graph, AnimationController value) + { + var compObj = WriteCompObj(builder, graph, value); + + Fb.Controller.StartController(builder); + AddBase(builder, compObj, Fb.Controller.AddBase); + Fb.Controller.AddTargetObject(builder, graph.GetObjectReference(value.TargetObject)); + Fb.Controller.AddTargetProperty(builder, graph.GetString(value.TargetProperty)); + Fb.Controller.AddIsPaused(builder, value.IsPaused); + Fb.Controller.AddIsCustom(builder, value.IsCustom); + return Fb.Controller.EndController(builder); + } + + static Offset WriteCanvasGeometry(FlatBufferBuilder builder, GraphIndexer graph, CanvasGeometry value) + { + var geometries = value is CanvasGeometry.Group group + ? Fb.CanvasGeometry.CreateGeometriesVector(builder, group.Geometries.Select(graph.GetCanvasGeometry).ToArray()) + : default; + + var ops = default(VectorOffset); + var operands = default(VectorOffset); + if (value is CanvasGeometry.Path pathGeometry) + { + var (opBytes, operandFloats) = FlattenPath(pathGeometry); + ops = Fb.CanvasGeometry.CreateOpsVector(builder, opBytes); + operands = Fb.CanvasGeometry.CreateOperandsVector(builder, operandFloats); + } + + Fb.CanvasGeometry.StartCanvasGeometry(builder); + Fb.CanvasGeometry.AddKind(builder, value.Type switch + { + CanvasGeometry.GeometryType.Combination => Fb.CanvasGeometryKind.Combination, + CanvasGeometry.GeometryType.Ellipse => Fb.CanvasGeometryKind.Ellipse, + CanvasGeometry.GeometryType.Group => Fb.CanvasGeometryKind.Group, + CanvasGeometry.GeometryType.RoundedRectangle => Fb.CanvasGeometryKind.RoundedRectangle, + CanvasGeometry.GeometryType.TransformedGeometry => Fb.CanvasGeometryKind.TransformedGeometry, + _ => Fb.CanvasGeometryKind.Path, + }); + + switch (value) + { + case CanvasGeometry.Combination combination: + Fb.CanvasGeometry.AddA(builder, graph.GetCanvasGeometry(combination.A)); + Fb.CanvasGeometry.AddB(builder, graph.GetCanvasGeometry(combination.B)); + Fb.CanvasGeometry.AddCombineMode(builder, (byte)combination.CombineMode); + AddMat3x2(builder, combination.Matrix, Fb.CanvasGeometry.AddMatrix); + break; + case CanvasGeometry.TransformedGeometry transformed: + Fb.CanvasGeometry.AddSource(builder, graph.GetCanvasGeometry(transformed.SourceGeometry)); + AddMat3x2(builder, transformed.TransformMatrix, Fb.CanvasGeometry.AddMatrix); + break; + case CanvasGeometry.Group groupGeometry: + Fb.CanvasGeometry.AddGeometries(builder, geometries); + Fb.CanvasGeometry.AddFillRule(builder, (byte)groupGeometry.FilledRegionDetermination); + break; + case CanvasGeometry.Path path: + Fb.CanvasGeometry.AddFillRule(builder, (byte)path.FilledRegionDetermination); + Fb.CanvasGeometry.AddOps(builder, ops); + Fb.CanvasGeometry.AddOperands(builder, operands); + break; + case CanvasGeometry.Ellipse ellipse: + Fb.CanvasGeometry.AddX(builder, ellipse.X); + Fb.CanvasGeometry.AddY(builder, ellipse.Y); + Fb.CanvasGeometry.AddRadiusX(builder, ellipse.RadiusX); + Fb.CanvasGeometry.AddRadiusY(builder, ellipse.RadiusY); + break; + case CanvasGeometry.RoundedRectangle roundedRectangle: + Fb.CanvasGeometry.AddX(builder, roundedRectangle.X); + Fb.CanvasGeometry.AddY(builder, roundedRectangle.Y); + Fb.CanvasGeometry.AddW(builder, roundedRectangle.W); + Fb.CanvasGeometry.AddH(builder, roundedRectangle.H); + Fb.CanvasGeometry.AddRadiusX(builder, roundedRectangle.RadiusX); + Fb.CanvasGeometry.AddRadiusY(builder, roundedRectangle.RadiusY); + break; + } + + return Fb.CanvasGeometry.EndCanvasGeometry(builder); + } + + // Flattens the command list of a path into an opcode stream and a parallel + // operand stream. This avoids a table per command, which would dominate the + // size of a typical animation. + static (byte[] Ops, float[] Operands) FlattenPath(CanvasGeometry.Path value) + { + var ops = new List(value.Commands.Length); + var operands = new List(value.Commands.Length * 2); + + foreach (var command in value.Commands) + { + switch (command) + { + case CanvasPathBuilder.Command.BeginFigure begin: + ops.Add((byte)Fb.PathOp.BeginFigure); + operands.Add(begin.StartPoint.X); + operands.Add(begin.StartPoint.Y); + break; + case CanvasPathBuilder.Command.EndFigure end: + ops.Add((byte)Fb.PathOp.EndFigure); + operands.Add((float)end.FigureLoop); + break; + case CanvasPathBuilder.Command.AddLine line: + ops.Add((byte)Fb.PathOp.AddLine); + operands.Add(line.EndPoint.X); + operands.Add(line.EndPoint.Y); + break; + case CanvasPathBuilder.Command.AddCubicBezier bezier: + ops.Add((byte)Fb.PathOp.AddCubicBezier); + operands.Add(bezier.ControlPoint1.X); + operands.Add(bezier.ControlPoint1.Y); + operands.Add(bezier.ControlPoint2.X); + operands.Add(bezier.ControlPoint2.Y); + operands.Add(bezier.EndPoint.X); + operands.Add(bezier.EndPoint.Y); + break; + default: + throw new InvalidOperationException($"Unsupported path command {command.Type}."); + } + } + + return (ops.ToArray(), operands.ToArray()); + } + + static Offset WriteMetadata( + FlatBufferBuilder builder, + GraphIndexer graph, + LottieCompositionMetadata? metadata, + IReadOnlyList? propertyBindings, + float width, + float height) + { + var bindings = propertyBindings ?? Array.Empty(); + var bindingOffsets = new Offset[bindings.Count]; + for (var i = 0; i < bindings.Count; i++) + { + var binding = bindings[i]; + Fb.PropertyBinding.StartPropertyBinding(builder); + Fb.PropertyBinding.AddName(builder, graph.GetString(binding.BindingName)); + Fb.PropertyBinding.AddDisplayName(builder, graph.GetString(binding.DisplayName)); + Fb.PropertyBinding.AddActualType(builder, (Fb.PropertyValueType)binding.ActualType); + Fb.PropertyBinding.AddExposedType(builder, (Fb.PropertyValueType)binding.ExposedType); + + switch (binding.DefaultValue) + { + case float scalar: + Fb.PropertyBinding.AddDefaultScalar(builder, scalar); + break; + case Vector2 vector2: + Fb.PropertyBinding.AddDefaultVector(builder, Fb.Vec4.CreateVec4(builder, vector2.X, vector2.Y, 0, 0)); + break; + case Vector3 vector3: + Fb.PropertyBinding.AddDefaultVector(builder, Fb.Vec4.CreateVec4(builder, vector3.X, vector3.Y, vector3.Z, 0)); + break; + case Vector4 vector4: + Fb.PropertyBinding.AddDefaultVector(builder, Fb.Vec4.CreateVec4(builder, vector4.X, vector4.Y, vector4.Z, vector4.W)); + break; + case Wui.Color color: + Fb.PropertyBinding.AddDefaultColor(builder, CreateColor(builder, color)); + break; + } + + bindingOffsets[i] = Fb.PropertyBinding.EndPropertyBinding(builder); + } + + var markers = metadata?.Markers ?? (IReadOnlyList)Array.Empty(); + var markerOffsets = new Offset[markers.Count]; + for (var i = 0; i < markers.Count; i++) + { + var marker = markers[i]; + Fb.Marker.StartMarker(builder); + Fb.Marker.AddName(builder, graph.GetString(marker.Name)); + Fb.Marker.AddProgress(builder, (float)marker.Frame.Progress); + + // Marker durations are stored as a proportion of the whole animation, to + // match Frame.Progress, so that a player needs no frame rate arithmetic. + var totalFrames = metadata!.Duration.Frames; + Fb.Marker.AddDurationProgress( + builder, + totalFrames == 0 ? 0f : (float)(marker.Duration.Frames / totalFrames)); + markerOffsets[i] = Fb.Marker.EndMarker(builder); + } + + var name = graph.GetString(metadata?.CompositionName); + + var bindingsVector = bindings.Count == 0 + ? default + : Fb.Metadata.CreatePropertyBindingsVector(builder, bindingOffsets); + + var markersVector = markers.Count == 0 + ? default + : Fb.Metadata.CreateMarkersVector(builder, markerOffsets); + + // The theming property set is the one that has no owner, i.e. the one that was + // created by Compositor.CreatePropertySet rather than by a composition object. + var themingPropertySet = Format.NullIndex; + for (var i = 0; i < graph.PropertySetList.Count; i++) + { + if (graph.PropertySetList[i].Owner is null) + { + themingPropertySet = (uint)i; + break; + } + } + + Fb.Metadata.StartMetadata(builder); + Fb.Metadata.AddName(builder, name); + Fb.Metadata.AddWidth(builder, width); + Fb.Metadata.AddHeight(builder, height); + Fb.Metadata.AddDurationTicks(builder, metadata is null ? 0L : metadata.Duration.Time.Ticks); + Fb.Metadata.AddFramesPerSecond(builder, (float)(metadata?.Duration.FPS ?? 0)); + + if (bindingsVector.Value != 0) + { + Fb.Metadata.AddPropertyBindings(builder, bindingsVector); + } + + if (markersVector.Value != 0) + { + Fb.Metadata.AddMarkers(builder, markersVector); + } + + Fb.Metadata.AddThemingPropertySet(builder, themingPropertySet); + return Fb.Metadata.EndMetadata(builder); + } + + // --------------------------------------------------------------------- + // Value helpers. A struct field is written only when the source property has a + // value, so that "never set" and "set to the default" stay distinguishable. + // --------------------------------------------------------------------- + static Offset CreateColor(FlatBufferBuilder builder, Wui.Color value) + => Fb.Color.CreateColor(builder, value.A, value.R, value.G, value.B); + + static void AddColor(FlatBufferBuilder builder, Wui.Color? value, Action> add) + { + if (value.HasValue) + { + add(builder, CreateColor(builder, value.Value)); + } + } + + static void AddVec2(FlatBufferBuilder builder, Vector2? value, Action> add) + { + if (value.HasValue) + { + add(builder, Fb.Vec2.CreateVec2(builder, value.Value.X, value.Value.Y)); + } + } + + static void AddVec2(FlatBufferBuilder builder, Vector2 value, Action> add) + { + // A non-nullable property always has a value, but writing a zero is the same + // as leaving the field out, so the zero case is skipped to save space. + if (value != Vector2.Zero) + { + add(builder, Fb.Vec2.CreateVec2(builder, value.X, value.Y)); + } + } + + static void AddVec3(FlatBufferBuilder builder, Vector3? value, Action> add) + { + if (value.HasValue) + { + add(builder, Fb.Vec3.CreateVec3(builder, value.Value.X, value.Value.Y, value.Value.Z)); + } + } + + static void AddMat3x2(FlatBufferBuilder builder, Matrix3x2? value, Action> add) + { + if (value.HasValue) + { + var m = value.Value; + add(builder, Fb.Mat3x2.CreateMat3x2(builder, m.M11, m.M12, m.M21, m.M22, m.M31, m.M32)); + } + } + + static void AddMat3x2(FlatBufferBuilder builder, Matrix3x2 value, Action> add) + { + if (!value.IsIdentity) + { + add(builder, Fb.Mat3x2.CreateMat3x2(builder, value.M11, value.M12, value.M21, value.M22, value.M31, value.M32)); + } + } + + static void AddMat4x4(FlatBufferBuilder builder, Matrix4x4? value, Action> add) + { + if (value.HasValue) + { + var m = value.Value; + add(builder, Fb.Mat4x4.CreateMat4x4( + builder, + m.M11, m.M12, m.M13, m.M14, + m.M21, m.M22, m.M23, m.M24, + m.M31, m.M32, m.M33, m.M34, + m.M41, m.M42, m.M43, m.M44)); + } + } + } +} diff --git a/source/CompDataFlatbuffer/FlatBufferFormatException.cs b/source/CompDataFlatbuffer/FlatBufferFormatException.cs new file mode 100644 index 00000000..3779041c --- /dev/null +++ b/source/CompDataFlatbuffer/FlatBufferFormatException.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable enable + +using System; + +namespace CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer +{ + /// + /// Thrown when a buffer is not a well formed serialized composition. + /// + /// + /// Buffers are untrusted input, so every failure to read one is reported as this + /// exception rather than being allowed to surface as an index or cast failure. + /// +#if PUBLIC_CompDataFlatbuffer + public +#endif + sealed class FlatBufferFormatException : Exception + { + /// + /// Initializes a new instance of the class. + /// + /// A description of what was wrong with the buffer. + public FlatBufferFormatException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// A description of what was wrong with the buffer. + /// The failure that revealed the problem. + public FlatBufferFormatException(string message, Exception innerException) + : base(message, innerException) + { + } + } +} diff --git a/source/CompDataFlatbuffer/Format.cs b/source/CompDataFlatbuffer/Format.cs new file mode 100644 index 00000000..b019590c --- /dev/null +++ b/source/CompDataFlatbuffer/Format.cs @@ -0,0 +1,79 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable enable + +namespace CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer +{ + /// + /// Constants and helpers that describe the lottie_comp.fbs wire format but + /// which are not expressible in the schema itself, and so are not produced + /// by the FlatBuffers compiler. + /// +#if PUBLIC_CompDataFlatbuffer + public +#endif + static class Format + { + /// + /// The version of the schema that this code reads and writes. This is stored in + /// the schema_version field of every buffer. It is incremented for every change + /// to lottie_comp.fbs. Only additive changes are permitted, so a reader can load + /// any buffer whose schema_version is less than or equal to its own. + /// + public const ushort Version = 1; + + /// + /// The 4 character identifier stored at offset 4 of every buffer. This is the + /// file_identifier declared in lottie_comp.fbs. + /// + public const string FileIdentifier = "LCMP"; + + /// + /// The file extension used for serialized compositions. This is the + /// file_extension declared in lottie_comp.fbs. + /// + public const string FileExtension = ".lcomp"; + + /// + /// The value of an index or object reference field that refers to nothing. + /// + public const uint NullIndex = 0xFFFFFFFF; + + /// + /// The number of low bits of an object reference that store the index. The + /// remaining high bits store the , i.e. which + /// of the root table's node vectors the index refers to. + /// + const int ObjectReferenceIndexBits = 28; + + const uint ObjectReferenceIndexMask = (1u << ObjectReferenceIndexBits) - 1; + + /// + /// Combines a category and an index into the single uint used by object + /// reference fields. + /// + /// The vector that indexes. + /// The index of the node within that vector. + /// The packed object reference. + public static uint PackObjectReference(Schema.ObjectCategory category, int index) + => ((uint)category << ObjectReferenceIndexBits) | ((uint)index & ObjectReferenceIndexMask); + + /// + /// Returns the category part of an object reference. + /// + /// A packed object reference. + /// The category of the referenced node. + public static Schema.ObjectCategory UnpackCategory(uint reference) + => (Schema.ObjectCategory)(reference >> ObjectReferenceIndexBits); + + /// + /// Returns the index part of an object reference. + /// + /// A packed object reference. + /// The index of the referenced node within its category's vector. + public static int UnpackIndex(uint reference) + => (int)(reference & ObjectReferenceIndexMask); + } +} diff --git a/source/CompDataFlatbuffer/Generated/lottie_comp_generated.cs b/source/CompDataFlatbuffer/Generated/lottie_comp_generated.cs new file mode 100644 index 00000000..1c33450d --- /dev/null +++ b/source/CompDataFlatbuffer/Generated/lottie_comp_generated.cs @@ -0,0 +1,2051 @@ +// +// automatically generated by the FlatBuffers compiler, do not modify +// + +namespace CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema +{ + +using global::System; +using global::System.Collections.Generic; +using global::Google.FlatBuffers; + +public enum ObjectCategory : byte +{ + Visual = 0, + Shape = 1, + Geometry = 2, + Brush = 3, + Animation = 4, + Easing = 5, + PropertySet = 6, + Surface = 7, + Clip = 8, + Controller = 9, + Shadow = 10, + Effect = 11, + GradientStop = 12, + ViewBox = 13, +}; + +public enum VisualKind : byte +{ + Container = 0, + Sprite = 1, + Shape = 2, + Layer = 3, +}; + +public enum ShapeKind : byte +{ + Container = 0, + Sprite = 1, +}; + +public enum GeometryKind : byte +{ + Path = 0, + Rectangle = 1, + RoundedRectangle = 2, + Ellipse = 3, +}; + +public enum BrushKind : byte +{ + Color = 0, + LinearGradient = 1, + RadialGradient = 2, + Surface = 3, + Mask = 4, + Effect = 5, +}; + +public enum ClipKind : byte +{ + Inset = 0, + Geometric = 1, +}; + +public enum ShadowKind : byte +{ + Drop = 0, +}; + +public enum SurfaceKind : byte +{ + VisualSurface = 0, + LoadedImageFromUri = 1, + LoadedImageFromStream = 2, +}; + +public enum EffectKind : byte +{ + Composite = 0, + GaussianBlur = 1, +}; + +public enum EasingKind : byte +{ + Linear = 0, + CubicBezier = 1, + Step = 2, +}; + +public enum AnimationKind : byte +{ + Scalar = 0, + Vector2 = 1, + Vector3 = 2, + Vector4 = 3, + Color = 4, + Boolean = 5, + Path = 6, + Expression = 7, +}; + +public enum KeyFrameKind : byte +{ + Value = 0, + Expression = 1, +}; + +public enum CanvasGeometryKind : byte +{ + Combination = 0, + Ellipse = 1, + Group = 2, + Path = 3, + RoundedRectangle = 4, + TransformedGeometry = 5, +}; + +public enum PathOp : byte +{ + BeginFigure = 0, + EndFigure = 1, + AddLine = 2, + AddCubicBezier = 3, +}; + +public enum PropertyValueType : byte +{ + None = 0, + Color = 1, + Scalar = 2, + Vector2 = 3, + Vector3 = 4, + Vector4 = 5, +}; + +public struct Vec2 : IFlatbufferObject +{ + private Struct __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public void __init(int _i, ByteBuffer _bb) { __p = new Struct(_i, _bb); } + public Vec2 __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public float X { get { return __p.bb.GetFloat(__p.bb_pos + 0); } } + public float Y { get { return __p.bb.GetFloat(__p.bb_pos + 4); } } + + public static Offset CreateVec2(FlatBufferBuilder builder, float X, float Y) { + builder.Prep(4, 8); + builder.PutFloat(Y); + builder.PutFloat(X); + return new Offset(builder.Offset); + } +} + +public struct Vec3 : IFlatbufferObject +{ + private Struct __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public void __init(int _i, ByteBuffer _bb) { __p = new Struct(_i, _bb); } + public Vec3 __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public float X { get { return __p.bb.GetFloat(__p.bb_pos + 0); } } + public float Y { get { return __p.bb.GetFloat(__p.bb_pos + 4); } } + public float Z { get { return __p.bb.GetFloat(__p.bb_pos + 8); } } + + public static Offset CreateVec3(FlatBufferBuilder builder, float X, float Y, float Z) { + builder.Prep(4, 12); + builder.PutFloat(Z); + builder.PutFloat(Y); + builder.PutFloat(X); + return new Offset(builder.Offset); + } +} + +public struct Vec4 : IFlatbufferObject +{ + private Struct __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public void __init(int _i, ByteBuffer _bb) { __p = new Struct(_i, _bb); } + public Vec4 __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public float X { get { return __p.bb.GetFloat(__p.bb_pos + 0); } } + public float Y { get { return __p.bb.GetFloat(__p.bb_pos + 4); } } + public float Z { get { return __p.bb.GetFloat(__p.bb_pos + 8); } } + public float W { get { return __p.bb.GetFloat(__p.bb_pos + 12); } } + + public static Offset CreateVec4(FlatBufferBuilder builder, float X, float Y, float Z, float W) { + builder.Prep(4, 16); + builder.PutFloat(W); + builder.PutFloat(Z); + builder.PutFloat(Y); + builder.PutFloat(X); + return new Offset(builder.Offset); + } +} + +public struct Mat3x2 : IFlatbufferObject +{ + private Struct __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public void __init(int _i, ByteBuffer _bb) { __p = new Struct(_i, _bb); } + public Mat3x2 __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public float M11 { get { return __p.bb.GetFloat(__p.bb_pos + 0); } } + public float M12 { get { return __p.bb.GetFloat(__p.bb_pos + 4); } } + public float M21 { get { return __p.bb.GetFloat(__p.bb_pos + 8); } } + public float M22 { get { return __p.bb.GetFloat(__p.bb_pos + 12); } } + public float M31 { get { return __p.bb.GetFloat(__p.bb_pos + 16); } } + public float M32 { get { return __p.bb.GetFloat(__p.bb_pos + 20); } } + + public static Offset CreateMat3x2(FlatBufferBuilder builder, float M11, float M12, float M21, float M22, float M31, float M32) { + builder.Prep(4, 24); + builder.PutFloat(M32); + builder.PutFloat(M31); + builder.PutFloat(M22); + builder.PutFloat(M21); + builder.PutFloat(M12); + builder.PutFloat(M11); + return new Offset(builder.Offset); + } +} + +public struct Mat4x4 : IFlatbufferObject +{ + private Struct __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public void __init(int _i, ByteBuffer _bb) { __p = new Struct(_i, _bb); } + public Mat4x4 __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public float M11 { get { return __p.bb.GetFloat(__p.bb_pos + 0); } } + public float M12 { get { return __p.bb.GetFloat(__p.bb_pos + 4); } } + public float M13 { get { return __p.bb.GetFloat(__p.bb_pos + 8); } } + public float M14 { get { return __p.bb.GetFloat(__p.bb_pos + 12); } } + public float M21 { get { return __p.bb.GetFloat(__p.bb_pos + 16); } } + public float M22 { get { return __p.bb.GetFloat(__p.bb_pos + 20); } } + public float M23 { get { return __p.bb.GetFloat(__p.bb_pos + 24); } } + public float M24 { get { return __p.bb.GetFloat(__p.bb_pos + 28); } } + public float M31 { get { return __p.bb.GetFloat(__p.bb_pos + 32); } } + public float M32 { get { return __p.bb.GetFloat(__p.bb_pos + 36); } } + public float M33 { get { return __p.bb.GetFloat(__p.bb_pos + 40); } } + public float M34 { get { return __p.bb.GetFloat(__p.bb_pos + 44); } } + public float M41 { get { return __p.bb.GetFloat(__p.bb_pos + 48); } } + public float M42 { get { return __p.bb.GetFloat(__p.bb_pos + 52); } } + public float M43 { get { return __p.bb.GetFloat(__p.bb_pos + 56); } } + public float M44 { get { return __p.bb.GetFloat(__p.bb_pos + 60); } } + + public static Offset CreateMat4x4(FlatBufferBuilder builder, float M11, float M12, float M13, float M14, float M21, float M22, float M23, float M24, float M31, float M32, float M33, float M34, float M41, float M42, float M43, float M44) { + builder.Prep(4, 64); + builder.PutFloat(M44); + builder.PutFloat(M43); + builder.PutFloat(M42); + builder.PutFloat(M41); + builder.PutFloat(M34); + builder.PutFloat(M33); + builder.PutFloat(M32); + builder.PutFloat(M31); + builder.PutFloat(M24); + builder.PutFloat(M23); + builder.PutFloat(M22); + builder.PutFloat(M21); + builder.PutFloat(M14); + builder.PutFloat(M13); + builder.PutFloat(M12); + builder.PutFloat(M11); + return new Offset(builder.Offset); + } +} + +public struct Color : IFlatbufferObject +{ + private Struct __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public void __init(int _i, ByteBuffer _bb) { __p = new Struct(_i, _bb); } + public Color __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public byte A { get { return __p.bb.Get(__p.bb_pos + 0); } } + public byte R { get { return __p.bb.Get(__p.bb_pos + 1); } } + public byte G { get { return __p.bb.Get(__p.bb_pos + 2); } } + public byte B { get { return __p.bb.Get(__p.bb_pos + 3); } } + + public static Offset CreateColor(FlatBufferBuilder builder, byte A, byte R, byte G, byte B) { + builder.Prep(1, 4); + builder.PutByte(B); + builder.PutByte(G); + builder.PutByte(R); + builder.PutByte(A); + return new Offset(builder.Offset); + } +} + +public struct Animator : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static Animator GetRootAsAnimator(ByteBuffer _bb) { return GetRootAsAnimator(_bb, new Animator()); } + public static Animator GetRootAsAnimator(ByteBuffer _bb, Animator obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public Animator __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public uint Property { get { int o = __p.__offset(4); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)0; } } + public uint Animation { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)0; } } + public uint Controller { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + + public static Offset CreateAnimator(FlatBufferBuilder builder, + uint property = 0, + uint animation = 0, + uint controller = 4294967295) { + builder.StartTable(3); + Animator.AddController(builder, controller); + Animator.AddAnimation(builder, animation); + Animator.AddProperty(builder, property); + return Animator.EndAnimator(builder); + } + + public static void StartAnimator(FlatBufferBuilder builder) { builder.StartTable(3); } + public static void AddProperty(FlatBufferBuilder builder, uint property) { builder.AddUint(0, property, 0); } + public static void AddAnimation(FlatBufferBuilder builder, uint animation) { builder.AddUint(1, animation, 0); } + public static void AddController(FlatBufferBuilder builder, uint controller) { builder.AddUint(2, controller, 4294967295); } + public static Offset EndAnimator(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class AnimatorVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyField(tablePos, 4 /*Property*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 6 /*Animation*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 8 /*Controller*/, 4 /*uint*/, 4, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct CompObj : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static CompObj GetRootAsCompObj(ByteBuffer _bb) { return GetRootAsCompObj(_bb, new CompObj()); } + public static CompObj GetRootAsCompObj(ByteBuffer _bb, CompObj obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public CompObj __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public uint Comment { get { int o = __p.__offset(4); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Animator? Animators(int j) { int o = __p.__offset(6); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Animator?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Animator()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int AnimatorsLength { get { int o = __p.__offset(6); return o != 0 ? __p.__vector_len(o) : 0; } } + public uint Properties { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + + public static Offset CreateCompObj(FlatBufferBuilder builder, + uint comment = 4294967295, + VectorOffset animatorsOffset = default(VectorOffset), + uint properties = 4294967295) { + builder.StartTable(3); + CompObj.AddProperties(builder, properties); + CompObj.AddAnimators(builder, animatorsOffset); + CompObj.AddComment(builder, comment); + return CompObj.EndCompObj(builder); + } + + public static void StartCompObj(FlatBufferBuilder builder) { builder.StartTable(3); } + public static void AddComment(FlatBufferBuilder builder, uint comment) { builder.AddUint(0, comment, 4294967295); } + public static void AddAnimators(FlatBufferBuilder builder, VectorOffset animatorsOffset) { builder.AddOffset(1, animatorsOffset.Value, 0); } + public static VectorOffset CreateAnimatorsVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreateAnimatorsVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateAnimatorsVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateAnimatorsVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartAnimatorsVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddProperties(FlatBufferBuilder builder, uint properties) { builder.AddUint(2, properties, 4294967295); } + public static Offset EndCompObj(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class CompObjVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyField(tablePos, 4 /*Comment*/, 4 /*uint*/, 4, false) + && verifier.VerifyVectorOfTables(tablePos, 6 /*Animators*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.AnimatorVerify.Verify, false) + && verifier.VerifyField(tablePos, 8 /*Properties*/, 4 /*uint*/, 4, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct PropertyValue : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static PropertyValue GetRootAsPropertyValue(ByteBuffer _bb) { return GetRootAsPropertyValue(_bb, new PropertyValue()); } + public static PropertyValue GetRootAsPropertyValue(ByteBuffer _bb, PropertyValue obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public PropertyValue __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public uint Name { get { int o = __p.__offset(4); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)0; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyValueType Type { get { int o = __p.__offset(6); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyValueType)__p.bb.Get(o + __p.bb_pos) : CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyValueType.None; } } + public float Scalar { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec4? Vector { get { int o = __p.__offset(10); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec4?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec4()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color? Color { get { int o = __p.__offset(12); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color()).__assign(o + __p.bb_pos, __p.bb) : null; } } + + public static void StartPropertyValue(FlatBufferBuilder builder) { builder.StartTable(5); } + public static void AddName(FlatBufferBuilder builder, uint name) { builder.AddUint(0, name, 0); } + public static void AddType(FlatBufferBuilder builder, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyValueType type) { builder.AddByte(1, (byte)type, 0); } + public static void AddScalar(FlatBufferBuilder builder, float scalar) { builder.AddFloat(2, scalar, 0.0f); } + public static void AddVector(FlatBufferBuilder builder, Offset vectorOffset) { builder.AddStruct(3, vectorOffset.Value, 0); } + public static void AddColor(FlatBufferBuilder builder, Offset colorOffset) { builder.AddStruct(4, colorOffset.Value, 0); } + public static Offset EndPropertyValue(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class PropertyValueVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyField(tablePos, 4 /*Name*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 6 /*Type*/, 1 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyValueType*/, 1, false) + && verifier.VerifyField(tablePos, 8 /*Scalar*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 10 /*Vector*/, 16 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec4*/, 4, false) + && verifier.VerifyField(tablePos, 12 /*Color*/, 4 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color*/, 1, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct ReferenceParameter : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static ReferenceParameter GetRootAsReferenceParameter(ByteBuffer _bb) { return GetRootAsReferenceParameter(_bb, new ReferenceParameter()); } + public static ReferenceParameter GetRootAsReferenceParameter(ByteBuffer _bb, ReferenceParameter obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public ReferenceParameter __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public uint Name { get { int o = __p.__offset(4); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)0; } } + public uint Target { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)0; } } + + public static Offset CreateReferenceParameter(FlatBufferBuilder builder, + uint name = 0, + uint target = 0) { + builder.StartTable(2); + ReferenceParameter.AddTarget(builder, target); + ReferenceParameter.AddName(builder, name); + return ReferenceParameter.EndReferenceParameter(builder); + } + + public static void StartReferenceParameter(FlatBufferBuilder builder) { builder.StartTable(2); } + public static void AddName(FlatBufferBuilder builder, uint name) { builder.AddUint(0, name, 0); } + public static void AddTarget(FlatBufferBuilder builder, uint target) { builder.AddUint(1, target, 0); } + public static Offset EndReferenceParameter(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class ReferenceParameterVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyField(tablePos, 4 /*Name*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 6 /*Target*/, 4 /*uint*/, 4, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct SourceParameter : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static SourceParameter GetRootAsSourceParameter(ByteBuffer _bb) { return GetRootAsSourceParameter(_bb, new SourceParameter()); } + public static SourceParameter GetRootAsSourceParameter(ByteBuffer _bb, SourceParameter obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public SourceParameter __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public uint Name { get { int o = __p.__offset(4); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)0; } } + public uint Brush { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)0; } } + + public static Offset CreateSourceParameter(FlatBufferBuilder builder, + uint name = 0, + uint brush = 0) { + builder.StartTable(2); + SourceParameter.AddBrush(builder, brush); + SourceParameter.AddName(builder, name); + return SourceParameter.EndSourceParameter(builder); + } + + public static void StartSourceParameter(FlatBufferBuilder builder) { builder.StartTable(2); } + public static void AddName(FlatBufferBuilder builder, uint name) { builder.AddUint(0, name, 0); } + public static void AddBrush(FlatBufferBuilder builder, uint brush) { builder.AddUint(1, brush, 0); } + public static Offset EndSourceParameter(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class SourceParameterVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyField(tablePos, 4 /*Name*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 6 /*Brush*/, 4 /*uint*/, 4, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct KeyFrame : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static KeyFrame GetRootAsKeyFrame(ByteBuffer _bb) { return GetRootAsKeyFrame(_bb, new KeyFrame()); } + public static KeyFrame GetRootAsKeyFrame(ByteBuffer _bb, KeyFrame obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public KeyFrame __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public float Progress { get { int o = __p.__offset(4); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } } + public uint Easing { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.KeyFrameKind Kind { get { int o = __p.__offset(8); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.KeyFrameKind)__p.bb.Get(o + __p.bb_pos) : CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.KeyFrameKind.Value; } } + public uint Expression { get { int o = __p.__offset(10); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public float Scalar { get { int o = __p.__offset(12); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec4? Vector { get { int o = __p.__offset(14); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec4?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec4()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color? Color { get { int o = __p.__offset(16); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public uint Path { get { int o = __p.__offset(18); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + + public static void StartKeyFrame(FlatBufferBuilder builder) { builder.StartTable(8); } + public static void AddProgress(FlatBufferBuilder builder, float progress) { builder.AddFloat(0, progress, 0.0f); } + public static void AddEasing(FlatBufferBuilder builder, uint easing) { builder.AddUint(1, easing, 4294967295); } + public static void AddKind(FlatBufferBuilder builder, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.KeyFrameKind kind) { builder.AddByte(2, (byte)kind, 0); } + public static void AddExpression(FlatBufferBuilder builder, uint expression) { builder.AddUint(3, expression, 4294967295); } + public static void AddScalar(FlatBufferBuilder builder, float scalar) { builder.AddFloat(4, scalar, 0.0f); } + public static void AddVector(FlatBufferBuilder builder, Offset vectorOffset) { builder.AddStruct(5, vectorOffset.Value, 0); } + public static void AddColor(FlatBufferBuilder builder, Offset colorOffset) { builder.AddStruct(6, colorOffset.Value, 0); } + public static void AddPath(FlatBufferBuilder builder, uint path) { builder.AddUint(7, path, 4294967295); } + public static Offset EndKeyFrame(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class KeyFrameVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyField(tablePos, 4 /*Progress*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 6 /*Easing*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 8 /*Kind*/, 1 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.KeyFrameKind*/, 1, false) + && verifier.VerifyField(tablePos, 10 /*Expression*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 12 /*Scalar*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 14 /*Vector*/, 16 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec4*/, 4, false) + && verifier.VerifyField(tablePos, 16 /*Color*/, 4 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color*/, 1, false) + && verifier.VerifyField(tablePos, 18 /*Path*/, 4 /*uint*/, 4, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct Visual : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static Visual GetRootAsVisual(ByteBuffer _bb) { return GetRootAsVisual(_bb, new Visual()); } + public static Visual GetRootAsVisual(ByteBuffer _bb, Visual obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public Visual __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj? Base { get { int o = __p.__offset(4); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.VisualKind Kind { get { int o = __p.__offset(6); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.VisualKind)__p.bb.Get(o + __p.bb_pos) : CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.VisualKind.Container; } } + public byte? BorderMode { get { int o = __p.__offset(8); return o != 0 ? __p.bb.Get(o + __p.bb_pos) : (byte?)null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec3? CenterPoint { get { int o = __p.__offset(10); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec3?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec3()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public uint Clip { get { int o = __p.__offset(12); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public bool? IsVisible { get { int o = __p.__offset(14); return o != 0 ? 0!=__p.bb.Get(o + __p.bb_pos) : (bool?)null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec3? Offset { get { int o = __p.__offset(16); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec3?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec3()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public float? Opacity { get { int o = __p.__offset(18); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float?)null; } } + public float? RotationAngleInDegrees { get { int o = __p.__offset(20); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float?)null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec3? RotationAxis { get { int o = __p.__offset(22); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec3?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec3()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec3? Scale { get { int o = __p.__offset(24); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec3?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec3()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? Size { get { int o = __p.__offset(26); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Mat4x4? TransformMatrix { get { int o = __p.__offset(28); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Mat4x4?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Mat4x4()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public uint Children(int j) { int o = __p.__offset(30); return o != 0 ? __p.bb.GetUint(__p.__vector(o) + j * 4) : (uint)0; } + public int ChildrenLength { get { int o = __p.__offset(30); return o != 0 ? __p.__vector_len(o) : 0; } } +#if ENABLE_SPAN_T + public Span GetChildrenBytes() { return __p.__vector_as_span(30, 4); } +#else + public ArraySegment? GetChildrenBytes() { return __p.__vector_as_arraysegment(30); } +#endif + public uint[] GetChildrenArray() { return __p.__vector_as_array(30); } + public uint Shapes(int j) { int o = __p.__offset(32); return o != 0 ? __p.bb.GetUint(__p.__vector(o) + j * 4) : (uint)0; } + public int ShapesLength { get { int o = __p.__offset(32); return o != 0 ? __p.__vector_len(o) : 0; } } +#if ENABLE_SPAN_T + public Span GetShapesBytes() { return __p.__vector_as_span(32, 4); } +#else + public ArraySegment? GetShapesBytes() { return __p.__vector_as_arraysegment(32); } +#endif + public uint[] GetShapesArray() { return __p.__vector_as_array(32); } + public uint ViewBox { get { int o = __p.__offset(34); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public uint Brush { get { int o = __p.__offset(36); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public uint Shadow { get { int o = __p.__offset(38); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + + public static void StartVisual(FlatBufferBuilder builder) { builder.StartTable(18); } + public static void AddBase(FlatBufferBuilder builder, Offset baseOffset) { builder.AddOffset(0, baseOffset.Value, 0); } + public static void AddKind(FlatBufferBuilder builder, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.VisualKind kind) { builder.AddByte(1, (byte)kind, 0); } + public static void AddBorderMode(FlatBufferBuilder builder, byte? borderMode) { builder.AddByte(2, borderMode); } + public static void AddCenterPoint(FlatBufferBuilder builder, Offset centerPointOffset) { builder.AddStruct(3, centerPointOffset.Value, 0); } + public static void AddClip(FlatBufferBuilder builder, uint clip) { builder.AddUint(4, clip, 4294967295); } + public static void AddIsVisible(FlatBufferBuilder builder, bool? isVisible) { builder.AddBool(5, isVisible); } + public static void AddOffset(FlatBufferBuilder builder, Offset offsetOffset) { builder.AddStruct(6, offsetOffset.Value, 0); } + public static void AddOpacity(FlatBufferBuilder builder, float? opacity) { builder.AddFloat(7, opacity); } + public static void AddRotationAngleInDegrees(FlatBufferBuilder builder, float? rotationAngleInDegrees) { builder.AddFloat(8, rotationAngleInDegrees); } + public static void AddRotationAxis(FlatBufferBuilder builder, Offset rotationAxisOffset) { builder.AddStruct(9, rotationAxisOffset.Value, 0); } + public static void AddScale(FlatBufferBuilder builder, Offset scaleOffset) { builder.AddStruct(10, scaleOffset.Value, 0); } + public static void AddSize(FlatBufferBuilder builder, Offset sizeOffset) { builder.AddStruct(11, sizeOffset.Value, 0); } + public static void AddTransformMatrix(FlatBufferBuilder builder, Offset transformMatrixOffset) { builder.AddStruct(12, transformMatrixOffset.Value, 0); } + public static void AddChildren(FlatBufferBuilder builder, VectorOffset childrenOffset) { builder.AddOffset(13, childrenOffset.Value, 0); } + public static VectorOffset CreateChildrenVector(FlatBufferBuilder builder, uint[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddUint(data[i]); return builder.EndVector(); } + public static VectorOffset CreateChildrenVectorBlock(FlatBufferBuilder builder, uint[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateChildrenVectorBlock(FlatBufferBuilder builder, ArraySegment data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateChildrenVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartChildrenVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddShapes(FlatBufferBuilder builder, VectorOffset shapesOffset) { builder.AddOffset(14, shapesOffset.Value, 0); } + public static VectorOffset CreateShapesVector(FlatBufferBuilder builder, uint[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddUint(data[i]); return builder.EndVector(); } + public static VectorOffset CreateShapesVectorBlock(FlatBufferBuilder builder, uint[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateShapesVectorBlock(FlatBufferBuilder builder, ArraySegment data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateShapesVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartShapesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddViewBox(FlatBufferBuilder builder, uint viewBox) { builder.AddUint(15, viewBox, 4294967295); } + public static void AddBrush(FlatBufferBuilder builder, uint brush) { builder.AddUint(16, brush, 4294967295); } + public static void AddShadow(FlatBufferBuilder builder, uint shadow) { builder.AddUint(17, shadow, 4294967295); } + public static Offset EndVisual(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class VisualVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyTable(tablePos, 4 /*Base*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObjVerify.Verify, false) + && verifier.VerifyField(tablePos, 6 /*Kind*/, 1 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.VisualKind*/, 1, false) + && verifier.VerifyField(tablePos, 8 /*BorderMode*/, 1 /*byte*/, 1, false) + && verifier.VerifyField(tablePos, 10 /*CenterPoint*/, 12 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec3*/, 4, false) + && verifier.VerifyField(tablePos, 12 /*Clip*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 14 /*IsVisible*/, 1 /*bool*/, 1, false) + && verifier.VerifyField(tablePos, 16 /*Offset*/, 12 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec3*/, 4, false) + && verifier.VerifyField(tablePos, 18 /*Opacity*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 20 /*RotationAngleInDegrees*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 22 /*RotationAxis*/, 12 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec3*/, 4, false) + && verifier.VerifyField(tablePos, 24 /*Scale*/, 12 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec3*/, 4, false) + && verifier.VerifyField(tablePos, 26 /*Size*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 28 /*TransformMatrix*/, 64 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Mat4x4*/, 4, false) + && verifier.VerifyVectorOfData(tablePos, 30 /*Children*/, 4 /*uint*/, false) + && verifier.VerifyVectorOfData(tablePos, 32 /*Shapes*/, 4 /*uint*/, false) + && verifier.VerifyField(tablePos, 34 /*ViewBox*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 36 /*Brush*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 38 /*Shadow*/, 4 /*uint*/, 4, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct Shape : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static Shape GetRootAsShape(ByteBuffer _bb) { return GetRootAsShape(_bb, new Shape()); } + public static Shape GetRootAsShape(ByteBuffer _bb, Shape obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public Shape __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj? Base { get { int o = __p.__offset(4); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ShapeKind Kind { get { int o = __p.__offset(6); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ShapeKind)__p.bb.Get(o + __p.bb_pos) : CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ShapeKind.Container; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? CenterPoint { get { int o = __p.__offset(8); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? Offset { get { int o = __p.__offset(10); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public float? RotationAngleInDegrees { get { int o = __p.__offset(12); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float?)null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? Scale { get { int o = __p.__offset(14); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Mat3x2? TransformMatrix { get { int o = __p.__offset(16); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Mat3x2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Mat3x2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public uint Shapes(int j) { int o = __p.__offset(18); return o != 0 ? __p.bb.GetUint(__p.__vector(o) + j * 4) : (uint)0; } + public int ShapesLength { get { int o = __p.__offset(18); return o != 0 ? __p.__vector_len(o) : 0; } } +#if ENABLE_SPAN_T + public Span GetShapesBytes() { return __p.__vector_as_span(18, 4); } +#else + public ArraySegment? GetShapesBytes() { return __p.__vector_as_arraysegment(18); } +#endif + public uint[] GetShapesArray() { return __p.__vector_as_array(18); } + public uint FillBrush { get { int o = __p.__offset(20); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public uint StrokeBrush { get { int o = __p.__offset(22); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public uint Geometry { get { int o = __p.__offset(24); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public bool? IsStrokeNonScaling { get { int o = __p.__offset(26); return o != 0 ? 0!=__p.bb.Get(o + __p.bb_pos) : (bool?)null; } } + public float? StrokeDashOffset { get { int o = __p.__offset(28); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float?)null; } } + public float StrokeDashArray(int j) { int o = __p.__offset(30); return o != 0 ? __p.bb.GetFloat(__p.__vector(o) + j * 4) : (float)0; } + public int StrokeDashArrayLength { get { int o = __p.__offset(30); return o != 0 ? __p.__vector_len(o) : 0; } } +#if ENABLE_SPAN_T + public Span GetStrokeDashArrayBytes() { return __p.__vector_as_span(30, 4); } +#else + public ArraySegment? GetStrokeDashArrayBytes() { return __p.__vector_as_arraysegment(30); } +#endif + public float[] GetStrokeDashArrayArray() { return __p.__vector_as_array(30); } + public byte? StrokeDashCap { get { int o = __p.__offset(32); return o != 0 ? __p.bb.Get(o + __p.bb_pos) : (byte?)null; } } + public byte? StrokeStartCap { get { int o = __p.__offset(34); return o != 0 ? __p.bb.Get(o + __p.bb_pos) : (byte?)null; } } + public byte? StrokeEndCap { get { int o = __p.__offset(36); return o != 0 ? __p.bb.Get(o + __p.bb_pos) : (byte?)null; } } + public byte? StrokeLineJoin { get { int o = __p.__offset(38); return o != 0 ? __p.bb.Get(o + __p.bb_pos) : (byte?)null; } } + public float? StrokeMiterLimit { get { int o = __p.__offset(40); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float?)null; } } + public float? StrokeThickness { get { int o = __p.__offset(42); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float?)null; } } + + public static void StartShape(FlatBufferBuilder builder) { builder.StartTable(20); } + public static void AddBase(FlatBufferBuilder builder, Offset baseOffset) { builder.AddOffset(0, baseOffset.Value, 0); } + public static void AddKind(FlatBufferBuilder builder, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ShapeKind kind) { builder.AddByte(1, (byte)kind, 0); } + public static void AddCenterPoint(FlatBufferBuilder builder, Offset centerPointOffset) { builder.AddStruct(2, centerPointOffset.Value, 0); } + public static void AddOffset(FlatBufferBuilder builder, Offset offsetOffset) { builder.AddStruct(3, offsetOffset.Value, 0); } + public static void AddRotationAngleInDegrees(FlatBufferBuilder builder, float? rotationAngleInDegrees) { builder.AddFloat(4, rotationAngleInDegrees); } + public static void AddScale(FlatBufferBuilder builder, Offset scaleOffset) { builder.AddStruct(5, scaleOffset.Value, 0); } + public static void AddTransformMatrix(FlatBufferBuilder builder, Offset transformMatrixOffset) { builder.AddStruct(6, transformMatrixOffset.Value, 0); } + public static void AddShapes(FlatBufferBuilder builder, VectorOffset shapesOffset) { builder.AddOffset(7, shapesOffset.Value, 0); } + public static VectorOffset CreateShapesVector(FlatBufferBuilder builder, uint[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddUint(data[i]); return builder.EndVector(); } + public static VectorOffset CreateShapesVectorBlock(FlatBufferBuilder builder, uint[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateShapesVectorBlock(FlatBufferBuilder builder, ArraySegment data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateShapesVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartShapesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddFillBrush(FlatBufferBuilder builder, uint fillBrush) { builder.AddUint(8, fillBrush, 4294967295); } + public static void AddStrokeBrush(FlatBufferBuilder builder, uint strokeBrush) { builder.AddUint(9, strokeBrush, 4294967295); } + public static void AddGeometry(FlatBufferBuilder builder, uint geometry) { builder.AddUint(10, geometry, 4294967295); } + public static void AddIsStrokeNonScaling(FlatBufferBuilder builder, bool? isStrokeNonScaling) { builder.AddBool(11, isStrokeNonScaling); } + public static void AddStrokeDashOffset(FlatBufferBuilder builder, float? strokeDashOffset) { builder.AddFloat(12, strokeDashOffset); } + public static void AddStrokeDashArray(FlatBufferBuilder builder, VectorOffset strokeDashArrayOffset) { builder.AddOffset(13, strokeDashArrayOffset.Value, 0); } + public static VectorOffset CreateStrokeDashArrayVector(FlatBufferBuilder builder, float[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddFloat(data[i]); return builder.EndVector(); } + public static VectorOffset CreateStrokeDashArrayVectorBlock(FlatBufferBuilder builder, float[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateStrokeDashArrayVectorBlock(FlatBufferBuilder builder, ArraySegment data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateStrokeDashArrayVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartStrokeDashArrayVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddStrokeDashCap(FlatBufferBuilder builder, byte? strokeDashCap) { builder.AddByte(14, strokeDashCap); } + public static void AddStrokeStartCap(FlatBufferBuilder builder, byte? strokeStartCap) { builder.AddByte(15, strokeStartCap); } + public static void AddStrokeEndCap(FlatBufferBuilder builder, byte? strokeEndCap) { builder.AddByte(16, strokeEndCap); } + public static void AddStrokeLineJoin(FlatBufferBuilder builder, byte? strokeLineJoin) { builder.AddByte(17, strokeLineJoin); } + public static void AddStrokeMiterLimit(FlatBufferBuilder builder, float? strokeMiterLimit) { builder.AddFloat(18, strokeMiterLimit); } + public static void AddStrokeThickness(FlatBufferBuilder builder, float? strokeThickness) { builder.AddFloat(19, strokeThickness); } + public static Offset EndShape(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class ShapeVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyTable(tablePos, 4 /*Base*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObjVerify.Verify, false) + && verifier.VerifyField(tablePos, 6 /*Kind*/, 1 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ShapeKind*/, 1, false) + && verifier.VerifyField(tablePos, 8 /*CenterPoint*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 10 /*Offset*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 12 /*RotationAngleInDegrees*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 14 /*Scale*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 16 /*TransformMatrix*/, 24 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Mat3x2*/, 4, false) + && verifier.VerifyVectorOfData(tablePos, 18 /*Shapes*/, 4 /*uint*/, false) + && verifier.VerifyField(tablePos, 20 /*FillBrush*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 22 /*StrokeBrush*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 24 /*Geometry*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 26 /*IsStrokeNonScaling*/, 1 /*bool*/, 1, false) + && verifier.VerifyField(tablePos, 28 /*StrokeDashOffset*/, 4 /*float*/, 4, false) + && verifier.VerifyVectorOfData(tablePos, 30 /*StrokeDashArray*/, 4 /*float*/, false) + && verifier.VerifyField(tablePos, 32 /*StrokeDashCap*/, 1 /*byte*/, 1, false) + && verifier.VerifyField(tablePos, 34 /*StrokeStartCap*/, 1 /*byte*/, 1, false) + && verifier.VerifyField(tablePos, 36 /*StrokeEndCap*/, 1 /*byte*/, 1, false) + && verifier.VerifyField(tablePos, 38 /*StrokeLineJoin*/, 1 /*byte*/, 1, false) + && verifier.VerifyField(tablePos, 40 /*StrokeMiterLimit*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 42 /*StrokeThickness*/, 4 /*float*/, 4, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct Geometry : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static Geometry GetRootAsGeometry(ByteBuffer _bb) { return GetRootAsGeometry(_bb, new Geometry()); } + public static Geometry GetRootAsGeometry(ByteBuffer _bb, Geometry obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public Geometry __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj? Base { get { int o = __p.__offset(4); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.GeometryKind Kind { get { int o = __p.__offset(6); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.GeometryKind)__p.bb.Get(o + __p.bb_pos) : CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.GeometryKind.Path; } } + public float? TrimStart { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float?)null; } } + public float? TrimEnd { get { int o = __p.__offset(10); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float?)null; } } + public float? TrimOffset { get { int o = __p.__offset(12); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float?)null; } } + public uint Path { get { int o = __p.__offset(14); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? Offset { get { int o = __p.__offset(16); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? Size { get { int o = __p.__offset(18); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? CornerRadius { get { int o = __p.__offset(20); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? Center { get { int o = __p.__offset(22); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? Radius { get { int o = __p.__offset(24); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + + public static void StartGeometry(FlatBufferBuilder builder) { builder.StartTable(11); } + public static void AddBase(FlatBufferBuilder builder, Offset baseOffset) { builder.AddOffset(0, baseOffset.Value, 0); } + public static void AddKind(FlatBufferBuilder builder, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.GeometryKind kind) { builder.AddByte(1, (byte)kind, 0); } + public static void AddTrimStart(FlatBufferBuilder builder, float? trimStart) { builder.AddFloat(2, trimStart); } + public static void AddTrimEnd(FlatBufferBuilder builder, float? trimEnd) { builder.AddFloat(3, trimEnd); } + public static void AddTrimOffset(FlatBufferBuilder builder, float? trimOffset) { builder.AddFloat(4, trimOffset); } + public static void AddPath(FlatBufferBuilder builder, uint path) { builder.AddUint(5, path, 4294967295); } + public static void AddOffset(FlatBufferBuilder builder, Offset offsetOffset) { builder.AddStruct(6, offsetOffset.Value, 0); } + public static void AddSize(FlatBufferBuilder builder, Offset sizeOffset) { builder.AddStruct(7, sizeOffset.Value, 0); } + public static void AddCornerRadius(FlatBufferBuilder builder, Offset cornerRadiusOffset) { builder.AddStruct(8, cornerRadiusOffset.Value, 0); } + public static void AddCenter(FlatBufferBuilder builder, Offset centerOffset) { builder.AddStruct(9, centerOffset.Value, 0); } + public static void AddRadius(FlatBufferBuilder builder, Offset radiusOffset) { builder.AddStruct(10, radiusOffset.Value, 0); } + public static Offset EndGeometry(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class GeometryVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyTable(tablePos, 4 /*Base*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObjVerify.Verify, false) + && verifier.VerifyField(tablePos, 6 /*Kind*/, 1 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.GeometryKind*/, 1, false) + && verifier.VerifyField(tablePos, 8 /*TrimStart*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 10 /*TrimEnd*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 12 /*TrimOffset*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 14 /*Path*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 16 /*Offset*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 18 /*Size*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 20 /*CornerRadius*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 22 /*Center*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 24 /*Radius*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct Brush : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static Brush GetRootAsBrush(ByteBuffer _bb) { return GetRootAsBrush(_bb, new Brush()); } + public static Brush GetRootAsBrush(ByteBuffer _bb, Brush obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public Brush __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj? Base { get { int o = __p.__offset(4); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.BrushKind Kind { get { int o = __p.__offset(6); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.BrushKind)__p.bb.Get(o + __p.bb_pos) : CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.BrushKind.Color; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color? Color { get { int o = __p.__offset(8); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? AnchorPoint { get { int o = __p.__offset(10); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? CenterPoint { get { int o = __p.__offset(12); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public uint ColorStops(int j) { int o = __p.__offset(14); return o != 0 ? __p.bb.GetUint(__p.__vector(o) + j * 4) : (uint)0; } + public int ColorStopsLength { get { int o = __p.__offset(14); return o != 0 ? __p.__vector_len(o) : 0; } } +#if ENABLE_SPAN_T + public Span GetColorStopsBytes() { return __p.__vector_as_span(14, 4); } +#else + public ArraySegment? GetColorStopsBytes() { return __p.__vector_as_arraysegment(14); } +#endif + public uint[] GetColorStopsArray() { return __p.__vector_as_array(14); } + public byte? ExtendMode { get { int o = __p.__offset(16); return o != 0 ? __p.bb.Get(o + __p.bb_pos) : (byte?)null; } } + public byte? InterpolationSpace { get { int o = __p.__offset(18); return o != 0 ? __p.bb.Get(o + __p.bb_pos) : (byte?)null; } } + public byte? MappingMode { get { int o = __p.__offset(20); return o != 0 ? __p.bb.Get(o + __p.bb_pos) : (byte?)null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? Offset { get { int o = __p.__offset(22); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public float? RotationAngleInDegrees { get { int o = __p.__offset(24); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float?)null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? Scale { get { int o = __p.__offset(26); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Mat3x2? TransformMatrix { get { int o = __p.__offset(28); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Mat3x2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Mat3x2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? StartPoint { get { int o = __p.__offset(30); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? EndPoint { get { int o = __p.__offset(32); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? EllipseCenter { get { int o = __p.__offset(34); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? EllipseRadius { get { int o = __p.__offset(36); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? GradientOriginOffset { get { int o = __p.__offset(38); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public uint Surface { get { int o = __p.__offset(40); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public uint Source { get { int o = __p.__offset(42); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public uint Mask { get { int o = __p.__offset(44); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public uint Effect { get { int o = __p.__offset(46); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.SourceParameter? SourceParameters(int j) { int o = __p.__offset(48); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.SourceParameter?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.SourceParameter()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int SourceParametersLength { get { int o = __p.__offset(48); return o != 0 ? __p.__vector_len(o) : 0; } } + + public static void StartBrush(FlatBufferBuilder builder) { builder.StartTable(23); } + public static void AddBase(FlatBufferBuilder builder, Offset baseOffset) { builder.AddOffset(0, baseOffset.Value, 0); } + public static void AddKind(FlatBufferBuilder builder, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.BrushKind kind) { builder.AddByte(1, (byte)kind, 0); } + public static void AddColor(FlatBufferBuilder builder, Offset colorOffset) { builder.AddStruct(2, colorOffset.Value, 0); } + public static void AddAnchorPoint(FlatBufferBuilder builder, Offset anchorPointOffset) { builder.AddStruct(3, anchorPointOffset.Value, 0); } + public static void AddCenterPoint(FlatBufferBuilder builder, Offset centerPointOffset) { builder.AddStruct(4, centerPointOffset.Value, 0); } + public static void AddColorStops(FlatBufferBuilder builder, VectorOffset colorStopsOffset) { builder.AddOffset(5, colorStopsOffset.Value, 0); } + public static VectorOffset CreateColorStopsVector(FlatBufferBuilder builder, uint[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddUint(data[i]); return builder.EndVector(); } + public static VectorOffset CreateColorStopsVectorBlock(FlatBufferBuilder builder, uint[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateColorStopsVectorBlock(FlatBufferBuilder builder, ArraySegment data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateColorStopsVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartColorStopsVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddExtendMode(FlatBufferBuilder builder, byte? extendMode) { builder.AddByte(6, extendMode); } + public static void AddInterpolationSpace(FlatBufferBuilder builder, byte? interpolationSpace) { builder.AddByte(7, interpolationSpace); } + public static void AddMappingMode(FlatBufferBuilder builder, byte? mappingMode) { builder.AddByte(8, mappingMode); } + public static void AddOffset(FlatBufferBuilder builder, Offset offsetOffset) { builder.AddStruct(9, offsetOffset.Value, 0); } + public static void AddRotationAngleInDegrees(FlatBufferBuilder builder, float? rotationAngleInDegrees) { builder.AddFloat(10, rotationAngleInDegrees); } + public static void AddScale(FlatBufferBuilder builder, Offset scaleOffset) { builder.AddStruct(11, scaleOffset.Value, 0); } + public static void AddTransformMatrix(FlatBufferBuilder builder, Offset transformMatrixOffset) { builder.AddStruct(12, transformMatrixOffset.Value, 0); } + public static void AddStartPoint(FlatBufferBuilder builder, Offset startPointOffset) { builder.AddStruct(13, startPointOffset.Value, 0); } + public static void AddEndPoint(FlatBufferBuilder builder, Offset endPointOffset) { builder.AddStruct(14, endPointOffset.Value, 0); } + public static void AddEllipseCenter(FlatBufferBuilder builder, Offset ellipseCenterOffset) { builder.AddStruct(15, ellipseCenterOffset.Value, 0); } + public static void AddEllipseRadius(FlatBufferBuilder builder, Offset ellipseRadiusOffset) { builder.AddStruct(16, ellipseRadiusOffset.Value, 0); } + public static void AddGradientOriginOffset(FlatBufferBuilder builder, Offset gradientOriginOffsetOffset) { builder.AddStruct(17, gradientOriginOffsetOffset.Value, 0); } + public static void AddSurface(FlatBufferBuilder builder, uint surface) { builder.AddUint(18, surface, 4294967295); } + public static void AddSource(FlatBufferBuilder builder, uint source) { builder.AddUint(19, source, 4294967295); } + public static void AddMask(FlatBufferBuilder builder, uint mask) { builder.AddUint(20, mask, 4294967295); } + public static void AddEffect(FlatBufferBuilder builder, uint effect) { builder.AddUint(21, effect, 4294967295); } + public static void AddSourceParameters(FlatBufferBuilder builder, VectorOffset sourceParametersOffset) { builder.AddOffset(22, sourceParametersOffset.Value, 0); } + public static VectorOffset CreateSourceParametersVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreateSourceParametersVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateSourceParametersVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateSourceParametersVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartSourceParametersVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static Offset EndBrush(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class BrushVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyTable(tablePos, 4 /*Base*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObjVerify.Verify, false) + && verifier.VerifyField(tablePos, 6 /*Kind*/, 1 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.BrushKind*/, 1, false) + && verifier.VerifyField(tablePos, 8 /*Color*/, 4 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color*/, 1, false) + && verifier.VerifyField(tablePos, 10 /*AnchorPoint*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 12 /*CenterPoint*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyVectorOfData(tablePos, 14 /*ColorStops*/, 4 /*uint*/, false) + && verifier.VerifyField(tablePos, 16 /*ExtendMode*/, 1 /*byte*/, 1, false) + && verifier.VerifyField(tablePos, 18 /*InterpolationSpace*/, 1 /*byte*/, 1, false) + && verifier.VerifyField(tablePos, 20 /*MappingMode*/, 1 /*byte*/, 1, false) + && verifier.VerifyField(tablePos, 22 /*Offset*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 24 /*RotationAngleInDegrees*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 26 /*Scale*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 28 /*TransformMatrix*/, 24 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Mat3x2*/, 4, false) + && verifier.VerifyField(tablePos, 30 /*StartPoint*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 32 /*EndPoint*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 34 /*EllipseCenter*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 36 /*EllipseRadius*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 38 /*GradientOriginOffset*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 40 /*Surface*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 42 /*Source*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 44 /*Mask*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 46 /*Effect*/, 4 /*uint*/, 4, false) + && verifier.VerifyVectorOfTables(tablePos, 48 /*SourceParameters*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.SourceParameterVerify.Verify, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct GradientStop : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static GradientStop GetRootAsGradientStop(ByteBuffer _bb) { return GetRootAsGradientStop(_bb, new GradientStop()); } + public static GradientStop GetRootAsGradientStop(ByteBuffer _bb, GradientStop obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public GradientStop __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj? Base { get { int o = __p.__offset(4); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color? Color { get { int o = __p.__offset(6); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public float Offset { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } } + + public static void StartGradientStop(FlatBufferBuilder builder) { builder.StartTable(3); } + public static void AddBase(FlatBufferBuilder builder, Offset baseOffset) { builder.AddOffset(0, baseOffset.Value, 0); } + public static void AddColor(FlatBufferBuilder builder, Offset colorOffset) { builder.AddStruct(1, colorOffset.Value, 0); } + public static void AddOffset(FlatBufferBuilder builder, float offset) { builder.AddFloat(2, offset, 0.0f); } + public static Offset EndGradientStop(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class GradientStopVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyTable(tablePos, 4 /*Base*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObjVerify.Verify, false) + && verifier.VerifyField(tablePos, 6 /*Color*/, 4 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color*/, 1, false) + && verifier.VerifyField(tablePos, 8 /*Offset*/, 4 /*float*/, 4, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct ViewBox : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static ViewBox GetRootAsViewBox(ByteBuffer _bb) { return GetRootAsViewBox(_bb, new ViewBox()); } + public static ViewBox GetRootAsViewBox(ByteBuffer _bb, ViewBox obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public ViewBox __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj? Base { get { int o = __p.__offset(4); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? Size { get { int o = __p.__offset(6); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + + public static void StartViewBox(FlatBufferBuilder builder) { builder.StartTable(2); } + public static void AddBase(FlatBufferBuilder builder, Offset baseOffset) { builder.AddOffset(0, baseOffset.Value, 0); } + public static void AddSize(FlatBufferBuilder builder, Offset sizeOffset) { builder.AddStruct(1, sizeOffset.Value, 0); } + public static Offset EndViewBox(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class ViewBoxVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyTable(tablePos, 4 /*Base*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObjVerify.Verify, false) + && verifier.VerifyField(tablePos, 6 /*Size*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct Clip : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static Clip GetRootAsClip(ByteBuffer _bb) { return GetRootAsClip(_bb, new Clip()); } + public static Clip GetRootAsClip(ByteBuffer _bb, Clip obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public Clip __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj? Base { get { int o = __p.__offset(4); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ClipKind Kind { get { int o = __p.__offset(6); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ClipKind)__p.bb.Get(o + __p.bb_pos) : CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ClipKind.Inset; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? CenterPoint { get { int o = __p.__offset(8); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? Scale { get { int o = __p.__offset(10); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public float? LeftInset { get { int o = __p.__offset(12); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float?)null; } } + public float? RightInset { get { int o = __p.__offset(14); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float?)null; } } + public float? TopInset { get { int o = __p.__offset(16); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float?)null; } } + public float? BottomInset { get { int o = __p.__offset(18); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float?)null; } } + public uint Geometry { get { int o = __p.__offset(20); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + + public static void StartClip(FlatBufferBuilder builder) { builder.StartTable(9); } + public static void AddBase(FlatBufferBuilder builder, Offset baseOffset) { builder.AddOffset(0, baseOffset.Value, 0); } + public static void AddKind(FlatBufferBuilder builder, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ClipKind kind) { builder.AddByte(1, (byte)kind, 0); } + public static void AddCenterPoint(FlatBufferBuilder builder, Offset centerPointOffset) { builder.AddStruct(2, centerPointOffset.Value, 0); } + public static void AddScale(FlatBufferBuilder builder, Offset scaleOffset) { builder.AddStruct(3, scaleOffset.Value, 0); } + public static void AddLeftInset(FlatBufferBuilder builder, float? leftInset) { builder.AddFloat(4, leftInset); } + public static void AddRightInset(FlatBufferBuilder builder, float? rightInset) { builder.AddFloat(5, rightInset); } + public static void AddTopInset(FlatBufferBuilder builder, float? topInset) { builder.AddFloat(6, topInset); } + public static void AddBottomInset(FlatBufferBuilder builder, float? bottomInset) { builder.AddFloat(7, bottomInset); } + public static void AddGeometry(FlatBufferBuilder builder, uint geometry) { builder.AddUint(8, geometry, 4294967295); } + public static Offset EndClip(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class ClipVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyTable(tablePos, 4 /*Base*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObjVerify.Verify, false) + && verifier.VerifyField(tablePos, 6 /*Kind*/, 1 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ClipKind*/, 1, false) + && verifier.VerifyField(tablePos, 8 /*CenterPoint*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 10 /*Scale*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 12 /*LeftInset*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 14 /*RightInset*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 16 /*TopInset*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 18 /*BottomInset*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 20 /*Geometry*/, 4 /*uint*/, 4, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct Shadow : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static Shadow GetRootAsShadow(ByteBuffer _bb) { return GetRootAsShadow(_bb, new Shadow()); } + public static Shadow GetRootAsShadow(ByteBuffer _bb, Shadow obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public Shadow __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj? Base { get { int o = __p.__offset(4); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ShadowKind Kind { get { int o = __p.__offset(6); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ShadowKind)__p.bb.Get(o + __p.bb_pos) : CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ShadowKind.Drop; } } + public float? BlurRadius { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float?)null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color? Color { get { int o = __p.__offset(10); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public uint Mask { get { int o = __p.__offset(12); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec3? Offset { get { int o = __p.__offset(14); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec3?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec3()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public float? Opacity { get { int o = __p.__offset(16); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float?)null; } } + public byte? SourcePolicy { get { int o = __p.__offset(18); return o != 0 ? __p.bb.Get(o + __p.bb_pos) : (byte?)null; } } + + public static void StartShadow(FlatBufferBuilder builder) { builder.StartTable(8); } + public static void AddBase(FlatBufferBuilder builder, Offset baseOffset) { builder.AddOffset(0, baseOffset.Value, 0); } + public static void AddKind(FlatBufferBuilder builder, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ShadowKind kind) { builder.AddByte(1, (byte)kind, 0); } + public static void AddBlurRadius(FlatBufferBuilder builder, float? blurRadius) { builder.AddFloat(2, blurRadius); } + public static void AddColor(FlatBufferBuilder builder, Offset colorOffset) { builder.AddStruct(3, colorOffset.Value, 0); } + public static void AddMask(FlatBufferBuilder builder, uint mask) { builder.AddUint(4, mask, 4294967295); } + public static void AddOffset(FlatBufferBuilder builder, Offset offsetOffset) { builder.AddStruct(5, offsetOffset.Value, 0); } + public static void AddOpacity(FlatBufferBuilder builder, float? opacity) { builder.AddFloat(6, opacity); } + public static void AddSourcePolicy(FlatBufferBuilder builder, byte? sourcePolicy) { builder.AddByte(7, sourcePolicy); } + public static Offset EndShadow(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class ShadowVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyTable(tablePos, 4 /*Base*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObjVerify.Verify, false) + && verifier.VerifyField(tablePos, 6 /*Kind*/, 1 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ShadowKind*/, 1, false) + && verifier.VerifyField(tablePos, 8 /*BlurRadius*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 10 /*Color*/, 4 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color*/, 1, false) + && verifier.VerifyField(tablePos, 12 /*Mask*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 14 /*Offset*/, 12 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec3*/, 4, false) + && verifier.VerifyField(tablePos, 16 /*Opacity*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 18 /*SourcePolicy*/, 1 /*byte*/, 1, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct Surface : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static Surface GetRootAsSurface(ByteBuffer _bb) { return GetRootAsSurface(_bb, new Surface()); } + public static Surface GetRootAsSurface(ByteBuffer _bb, Surface obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public Surface __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj? Base { get { int o = __p.__offset(4); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.SurfaceKind Kind { get { int o = __p.__offset(6); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.SurfaceKind)__p.bb.Get(o + __p.bb_pos) : CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.SurfaceKind.VisualSurface; } } + public uint SourceVisual { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? SourceSize { get { int o = __p.__offset(10); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? SourceOffset { get { int o = __p.__offset(12); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public uint Uri { get { int o = __p.__offset(14); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public byte Bytes(int j) { int o = __p.__offset(16); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; } + public int BytesLength { get { int o = __p.__offset(16); return o != 0 ? __p.__vector_len(o) : 0; } } +#if ENABLE_SPAN_T + public Span GetBytesBytes() { return __p.__vector_as_span(16, 1); } +#else + public ArraySegment? GetBytesBytes() { return __p.__vector_as_arraysegment(16); } +#endif + public byte[] GetBytesArray() { return __p.__vector_as_array(16); } + + public static void StartSurface(FlatBufferBuilder builder) { builder.StartTable(7); } + public static void AddBase(FlatBufferBuilder builder, Offset baseOffset) { builder.AddOffset(0, baseOffset.Value, 0); } + public static void AddKind(FlatBufferBuilder builder, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.SurfaceKind kind) { builder.AddByte(1, (byte)kind, 0); } + public static void AddSourceVisual(FlatBufferBuilder builder, uint sourceVisual) { builder.AddUint(2, sourceVisual, 4294967295); } + public static void AddSourceSize(FlatBufferBuilder builder, Offset sourceSizeOffset) { builder.AddStruct(3, sourceSizeOffset.Value, 0); } + public static void AddSourceOffset(FlatBufferBuilder builder, Offset sourceOffsetOffset) { builder.AddStruct(4, sourceOffsetOffset.Value, 0); } + public static void AddUri(FlatBufferBuilder builder, uint uri) { builder.AddUint(5, uri, 4294967295); } + public static void AddBytes(FlatBufferBuilder builder, VectorOffset bytesOffset) { builder.AddOffset(6, bytesOffset.Value, 0); } + public static VectorOffset CreateBytesVector(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddByte(data[i]); return builder.EndVector(); } + public static VectorOffset CreateBytesVectorBlock(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateBytesVectorBlock(FlatBufferBuilder builder, ArraySegment data) { builder.StartVector(1, data.Count, 1); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateBytesVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartBytesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); } + public static Offset EndSurface(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class SurfaceVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyTable(tablePos, 4 /*Base*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObjVerify.Verify, false) + && verifier.VerifyField(tablePos, 6 /*Kind*/, 1 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.SurfaceKind*/, 1, false) + && verifier.VerifyField(tablePos, 8 /*SourceVisual*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 10 /*SourceSize*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 12 /*SourceOffset*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 14 /*Uri*/, 4 /*uint*/, 4, false) + && verifier.VerifyVectorOfData(tablePos, 16 /*Bytes*/, 1 /*byte*/, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct Effect : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static Effect GetRootAsEffect(ByteBuffer _bb) { return GetRootAsEffect(_bb, new Effect()); } + public static Effect GetRootAsEffect(ByteBuffer _bb, Effect obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public Effect __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj? Base { get { int o = __p.__offset(4); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.EffectKind Kind { get { int o = __p.__offset(6); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.EffectKind)__p.bb.Get(o + __p.bb_pos) : CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.EffectKind.Composite; } } + public uint Sources(int j) { int o = __p.__offset(8); return o != 0 ? __p.bb.GetUint(__p.__vector(o) + j * 4) : (uint)0; } + public int SourcesLength { get { int o = __p.__offset(8); return o != 0 ? __p.__vector_len(o) : 0; } } +#if ENABLE_SPAN_T + public Span GetSourcesBytes() { return __p.__vector_as_span(8, 4); } +#else + public ArraySegment? GetSourcesBytes() { return __p.__vector_as_arraysegment(8); } +#endif + public uint[] GetSourcesArray() { return __p.__vector_as_array(8); } + public byte Mode { get { int o = __p.__offset(10); return o != 0 ? __p.bb.Get(o + __p.bb_pos) : (byte)0; } } + public float BlurAmount { get { int o = __p.__offset(12); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } } + + public static Offset CreateEffect(FlatBufferBuilder builder, + Offset @baseOffset = default(Offset), + CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.EffectKind kind = CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.EffectKind.Composite, + VectorOffset sourcesOffset = default(VectorOffset), + byte mode = 0, + float blur_amount = 0.0f) { + builder.StartTable(5); + Effect.AddBlurAmount(builder, blur_amount); + Effect.AddSources(builder, sourcesOffset); + Effect.AddBase(builder, @baseOffset); + Effect.AddMode(builder, mode); + Effect.AddKind(builder, kind); + return Effect.EndEffect(builder); + } + + public static void StartEffect(FlatBufferBuilder builder) { builder.StartTable(5); } + public static void AddBase(FlatBufferBuilder builder, Offset baseOffset) { builder.AddOffset(0, baseOffset.Value, 0); } + public static void AddKind(FlatBufferBuilder builder, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.EffectKind kind) { builder.AddByte(1, (byte)kind, 0); } + public static void AddSources(FlatBufferBuilder builder, VectorOffset sourcesOffset) { builder.AddOffset(2, sourcesOffset.Value, 0); } + public static VectorOffset CreateSourcesVector(FlatBufferBuilder builder, uint[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddUint(data[i]); return builder.EndVector(); } + public static VectorOffset CreateSourcesVectorBlock(FlatBufferBuilder builder, uint[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateSourcesVectorBlock(FlatBufferBuilder builder, ArraySegment data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateSourcesVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartSourcesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddMode(FlatBufferBuilder builder, byte mode) { builder.AddByte(3, mode, 0); } + public static void AddBlurAmount(FlatBufferBuilder builder, float blurAmount) { builder.AddFloat(4, blurAmount, 0.0f); } + public static Offset EndEffect(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class EffectVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyTable(tablePos, 4 /*Base*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObjVerify.Verify, false) + && verifier.VerifyField(tablePos, 6 /*Kind*/, 1 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.EffectKind*/, 1, false) + && verifier.VerifyVectorOfData(tablePos, 8 /*Sources*/, 4 /*uint*/, false) + && verifier.VerifyField(tablePos, 10 /*Mode*/, 1 /*byte*/, 1, false) + && verifier.VerifyField(tablePos, 12 /*BlurAmount*/, 4 /*float*/, 4, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct Easing : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static Easing GetRootAsEasing(ByteBuffer _bb) { return GetRootAsEasing(_bb, new Easing()); } + public static Easing GetRootAsEasing(ByteBuffer _bb, Easing obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public Easing __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj? Base { get { int o = __p.__offset(4); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.EasingKind Kind { get { int o = __p.__offset(6); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.EasingKind)__p.bb.Get(o + __p.bb_pos) : CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.EasingKind.Linear; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? ControlPoint1 { get { int o = __p.__offset(8); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2? ControlPoint2 { get { int o = __p.__offset(10); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public int? StepCount { get { int o = __p.__offset(12); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int?)null; } } + public int? InitialStep { get { int o = __p.__offset(14); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int?)null; } } + public int? FinalStep { get { int o = __p.__offset(16); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int?)null; } } + public bool? IsInitialStepSingleFrame { get { int o = __p.__offset(18); return o != 0 ? 0!=__p.bb.Get(o + __p.bb_pos) : (bool?)null; } } + public bool? IsFinalStepSingleFrame { get { int o = __p.__offset(20); return o != 0 ? 0!=__p.bb.Get(o + __p.bb_pos) : (bool?)null; } } + + public static void StartEasing(FlatBufferBuilder builder) { builder.StartTable(9); } + public static void AddBase(FlatBufferBuilder builder, Offset baseOffset) { builder.AddOffset(0, baseOffset.Value, 0); } + public static void AddKind(FlatBufferBuilder builder, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.EasingKind kind) { builder.AddByte(1, (byte)kind, 0); } + public static void AddControlPoint1(FlatBufferBuilder builder, Offset controlPoint1Offset) { builder.AddStruct(2, controlPoint1Offset.Value, 0); } + public static void AddControlPoint2(FlatBufferBuilder builder, Offset controlPoint2Offset) { builder.AddStruct(3, controlPoint2Offset.Value, 0); } + public static void AddStepCount(FlatBufferBuilder builder, int? stepCount) { builder.AddInt(4, stepCount); } + public static void AddInitialStep(FlatBufferBuilder builder, int? initialStep) { builder.AddInt(5, initialStep); } + public static void AddFinalStep(FlatBufferBuilder builder, int? finalStep) { builder.AddInt(6, finalStep); } + public static void AddIsInitialStepSingleFrame(FlatBufferBuilder builder, bool? isInitialStepSingleFrame) { builder.AddBool(7, isInitialStepSingleFrame); } + public static void AddIsFinalStepSingleFrame(FlatBufferBuilder builder, bool? isFinalStepSingleFrame) { builder.AddBool(8, isFinalStepSingleFrame); } + public static Offset EndEasing(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class EasingVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyTable(tablePos, 4 /*Base*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObjVerify.Verify, false) + && verifier.VerifyField(tablePos, 6 /*Kind*/, 1 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.EasingKind*/, 1, false) + && verifier.VerifyField(tablePos, 8 /*ControlPoint1*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 10 /*ControlPoint2*/, 8 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec2*/, 4, false) + && verifier.VerifyField(tablePos, 12 /*StepCount*/, 4 /*int*/, 4, false) + && verifier.VerifyField(tablePos, 14 /*InitialStep*/, 4 /*int*/, 4, false) + && verifier.VerifyField(tablePos, 16 /*FinalStep*/, 4 /*int*/, 4, false) + && verifier.VerifyField(tablePos, 18 /*IsInitialStepSingleFrame*/, 1 /*bool*/, 1, false) + && verifier.VerifyField(tablePos, 20 /*IsFinalStepSingleFrame*/, 1 /*bool*/, 1, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct Animation : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static Animation GetRootAsAnimation(ByteBuffer _bb) { return GetRootAsAnimation(_bb, new Animation()); } + public static Animation GetRootAsAnimation(ByteBuffer _bb, Animation obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public Animation __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj? Base { get { int o = __p.__offset(4); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.AnimationKind Kind { get { int o = __p.__offset(6); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.AnimationKind)__p.bb.Get(o + __p.bb_pos) : CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.AnimationKind.Scalar; } } + public uint Target { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ReferenceParameter? ReferenceParameters(int j) { int o = __p.__offset(10); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ReferenceParameter?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ReferenceParameter()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int ReferenceParametersLength { get { int o = __p.__offset(10); return o != 0 ? __p.__vector_len(o) : 0; } } + public uint Expression { get { int o = __p.__offset(12); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public long DurationTicks { get { int o = __p.__offset(14); return o != 0 ? __p.bb.GetLong(o + __p.bb_pos) : (long)0; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.KeyFrame? KeyFrames(int j) { int o = __p.__offset(16); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.KeyFrame?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.KeyFrame()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int KeyFramesLength { get { int o = __p.__offset(16); return o != 0 ? __p.__vector_len(o) : 0; } } + public byte? InterpolationColorSpace { get { int o = __p.__offset(18); return o != 0 ? __p.bb.Get(o + __p.bb_pos) : (byte?)null; } } + + public static Offset CreateAnimation(FlatBufferBuilder builder, + Offset @baseOffset = default(Offset), + CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.AnimationKind kind = CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.AnimationKind.Scalar, + uint target = 4294967295, + VectorOffset reference_parametersOffset = default(VectorOffset), + uint expression = 4294967295, + long duration_ticks = 0, + VectorOffset key_framesOffset = default(VectorOffset), + byte? interpolation_color_space = null) { + builder.StartTable(8); + Animation.AddDurationTicks(builder, duration_ticks); + Animation.AddKeyFrames(builder, key_framesOffset); + Animation.AddExpression(builder, expression); + Animation.AddReferenceParameters(builder, reference_parametersOffset); + Animation.AddTarget(builder, target); + Animation.AddBase(builder, @baseOffset); + Animation.AddInterpolationColorSpace(builder, interpolation_color_space); + Animation.AddKind(builder, kind); + return Animation.EndAnimation(builder); + } + + public static void StartAnimation(FlatBufferBuilder builder) { builder.StartTable(8); } + public static void AddBase(FlatBufferBuilder builder, Offset baseOffset) { builder.AddOffset(0, baseOffset.Value, 0); } + public static void AddKind(FlatBufferBuilder builder, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.AnimationKind kind) { builder.AddByte(1, (byte)kind, 0); } + public static void AddTarget(FlatBufferBuilder builder, uint target) { builder.AddUint(2, target, 4294967295); } + public static void AddReferenceParameters(FlatBufferBuilder builder, VectorOffset referenceParametersOffset) { builder.AddOffset(3, referenceParametersOffset.Value, 0); } + public static VectorOffset CreateReferenceParametersVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreateReferenceParametersVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateReferenceParametersVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateReferenceParametersVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartReferenceParametersVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddExpression(FlatBufferBuilder builder, uint expression) { builder.AddUint(4, expression, 4294967295); } + public static void AddDurationTicks(FlatBufferBuilder builder, long durationTicks) { builder.AddLong(5, durationTicks, 0); } + public static void AddKeyFrames(FlatBufferBuilder builder, VectorOffset keyFramesOffset) { builder.AddOffset(6, keyFramesOffset.Value, 0); } + public static VectorOffset CreateKeyFramesVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreateKeyFramesVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateKeyFramesVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateKeyFramesVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartKeyFramesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddInterpolationColorSpace(FlatBufferBuilder builder, byte? interpolationColorSpace) { builder.AddByte(7, interpolationColorSpace); } + public static Offset EndAnimation(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class AnimationVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyTable(tablePos, 4 /*Base*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObjVerify.Verify, false) + && verifier.VerifyField(tablePos, 6 /*Kind*/, 1 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.AnimationKind*/, 1, false) + && verifier.VerifyField(tablePos, 8 /*Target*/, 4 /*uint*/, 4, false) + && verifier.VerifyVectorOfTables(tablePos, 10 /*ReferenceParameters*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ReferenceParameterVerify.Verify, false) + && verifier.VerifyField(tablePos, 12 /*Expression*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 14 /*DurationTicks*/, 8 /*long*/, 8, false) + && verifier.VerifyVectorOfTables(tablePos, 16 /*KeyFrames*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.KeyFrameVerify.Verify, false) + && verifier.VerifyField(tablePos, 18 /*InterpolationColorSpace*/, 1 /*byte*/, 1, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct PropertySet : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static PropertySet GetRootAsPropertySet(ByteBuffer _bb) { return GetRootAsPropertySet(_bb, new PropertySet()); } + public static PropertySet GetRootAsPropertySet(ByteBuffer _bb, PropertySet obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public PropertySet __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj? Base { get { int o = __p.__offset(4); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } + public uint Owner { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyValue? Values(int j) { int o = __p.__offset(8); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyValue?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyValue()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int ValuesLength { get { int o = __p.__offset(8); return o != 0 ? __p.__vector_len(o) : 0; } } + + public static Offset CreatePropertySet(FlatBufferBuilder builder, + Offset @baseOffset = default(Offset), + uint owner = 4294967295, + VectorOffset valuesOffset = default(VectorOffset)) { + builder.StartTable(3); + PropertySet.AddValues(builder, valuesOffset); + PropertySet.AddOwner(builder, owner); + PropertySet.AddBase(builder, @baseOffset); + return PropertySet.EndPropertySet(builder); + } + + public static void StartPropertySet(FlatBufferBuilder builder) { builder.StartTable(3); } + public static void AddBase(FlatBufferBuilder builder, Offset baseOffset) { builder.AddOffset(0, baseOffset.Value, 0); } + public static void AddOwner(FlatBufferBuilder builder, uint owner) { builder.AddUint(1, owner, 4294967295); } + public static void AddValues(FlatBufferBuilder builder, VectorOffset valuesOffset) { builder.AddOffset(2, valuesOffset.Value, 0); } + public static VectorOffset CreateValuesVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreateValuesVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateValuesVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateValuesVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartValuesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static Offset EndPropertySet(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class PropertySetVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyTable(tablePos, 4 /*Base*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObjVerify.Verify, false) + && verifier.VerifyField(tablePos, 6 /*Owner*/, 4 /*uint*/, 4, false) + && verifier.VerifyVectorOfTables(tablePos, 8 /*Values*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyValueVerify.Verify, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct Controller : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static Controller GetRootAsController(ByteBuffer _bb) { return GetRootAsController(_bb, new Controller()); } + public static Controller GetRootAsController(ByteBuffer _bb, Controller obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public Controller __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj? Base { get { int o = __p.__offset(4); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObj()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } + public uint TargetObject { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public uint TargetProperty { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public bool IsPaused { get { int o = __p.__offset(10); return o != 0 ? 0!=__p.bb.Get(o + __p.bb_pos) : (bool)false; } } + public bool IsCustom { get { int o = __p.__offset(12); return o != 0 ? 0!=__p.bb.Get(o + __p.bb_pos) : (bool)false; } } + + public static Offset CreateController(FlatBufferBuilder builder, + Offset @baseOffset = default(Offset), + uint target_object = 4294967295, + uint target_property = 4294967295, + bool is_paused = false, + bool is_custom = false) { + builder.StartTable(5); + Controller.AddTargetProperty(builder, target_property); + Controller.AddTargetObject(builder, target_object); + Controller.AddBase(builder, @baseOffset); + Controller.AddIsCustom(builder, is_custom); + Controller.AddIsPaused(builder, is_paused); + return Controller.EndController(builder); + } + + public static void StartController(FlatBufferBuilder builder) { builder.StartTable(5); } + public static void AddBase(FlatBufferBuilder builder, Offset baseOffset) { builder.AddOffset(0, baseOffset.Value, 0); } + public static void AddTargetObject(FlatBufferBuilder builder, uint targetObject) { builder.AddUint(1, targetObject, 4294967295); } + public static void AddTargetProperty(FlatBufferBuilder builder, uint targetProperty) { builder.AddUint(2, targetProperty, 4294967295); } + public static void AddIsPaused(FlatBufferBuilder builder, bool isPaused) { builder.AddBool(3, isPaused, false); } + public static void AddIsCustom(FlatBufferBuilder builder, bool isCustom) { builder.AddBool(4, isCustom, false); } + public static Offset EndController(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class ControllerVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyTable(tablePos, 4 /*Base*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CompObjVerify.Verify, false) + && verifier.VerifyField(tablePos, 6 /*TargetObject*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 8 /*TargetProperty*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 10 /*IsPaused*/, 1 /*bool*/, 1, false) + && verifier.VerifyField(tablePos, 12 /*IsCustom*/, 1 /*bool*/, 1, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct PropertyBinding : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static PropertyBinding GetRootAsPropertyBinding(ByteBuffer _bb) { return GetRootAsPropertyBinding(_bb, new PropertyBinding()); } + public static PropertyBinding GetRootAsPropertyBinding(ByteBuffer _bb, PropertyBinding obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public PropertyBinding __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public uint Name { get { int o = __p.__offset(4); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)0; } } + public uint DisplayName { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)0; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyValueType ActualType { get { int o = __p.__offset(8); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyValueType)__p.bb.Get(o + __p.bb_pos) : CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyValueType.None; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyValueType ExposedType { get { int o = __p.__offset(10); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyValueType)__p.bb.Get(o + __p.bb_pos) : CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyValueType.None; } } + public float DefaultScalar { get { int o = __p.__offset(12); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec4? DefaultVector { get { int o = __p.__offset(14); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec4?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec4()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color? DefaultColor { get { int o = __p.__offset(16); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color()).__assign(o + __p.bb_pos, __p.bb) : null; } } + + public static void StartPropertyBinding(FlatBufferBuilder builder) { builder.StartTable(7); } + public static void AddName(FlatBufferBuilder builder, uint name) { builder.AddUint(0, name, 0); } + public static void AddDisplayName(FlatBufferBuilder builder, uint displayName) { builder.AddUint(1, displayName, 0); } + public static void AddActualType(FlatBufferBuilder builder, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyValueType actualType) { builder.AddByte(2, (byte)actualType, 0); } + public static void AddExposedType(FlatBufferBuilder builder, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyValueType exposedType) { builder.AddByte(3, (byte)exposedType, 0); } + public static void AddDefaultScalar(FlatBufferBuilder builder, float defaultScalar) { builder.AddFloat(4, defaultScalar, 0.0f); } + public static void AddDefaultVector(FlatBufferBuilder builder, Offset defaultVectorOffset) { builder.AddStruct(5, defaultVectorOffset.Value, 0); } + public static void AddDefaultColor(FlatBufferBuilder builder, Offset defaultColorOffset) { builder.AddStruct(6, defaultColorOffset.Value, 0); } + public static Offset EndPropertyBinding(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class PropertyBindingVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyField(tablePos, 4 /*Name*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 6 /*DisplayName*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 8 /*ActualType*/, 1 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyValueType*/, 1, false) + && verifier.VerifyField(tablePos, 10 /*ExposedType*/, 1 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyValueType*/, 1, false) + && verifier.VerifyField(tablePos, 12 /*DefaultScalar*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 14 /*DefaultVector*/, 16 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Vec4*/, 4, false) + && verifier.VerifyField(tablePos, 16 /*DefaultColor*/, 4 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Color*/, 1, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct Marker : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static Marker GetRootAsMarker(ByteBuffer _bb) { return GetRootAsMarker(_bb, new Marker()); } + public static Marker GetRootAsMarker(ByteBuffer _bb, Marker obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public Marker __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public uint Name { get { int o = __p.__offset(4); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)0; } } + public float Progress { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } } + public float DurationProgress { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } } + + public static Offset CreateMarker(FlatBufferBuilder builder, + uint name = 0, + float progress = 0.0f, + float duration_progress = 0.0f) { + builder.StartTable(3); + Marker.AddDurationProgress(builder, duration_progress); + Marker.AddProgress(builder, progress); + Marker.AddName(builder, name); + return Marker.EndMarker(builder); + } + + public static void StartMarker(FlatBufferBuilder builder) { builder.StartTable(3); } + public static void AddName(FlatBufferBuilder builder, uint name) { builder.AddUint(0, name, 0); } + public static void AddProgress(FlatBufferBuilder builder, float progress) { builder.AddFloat(1, progress, 0.0f); } + public static void AddDurationProgress(FlatBufferBuilder builder, float durationProgress) { builder.AddFloat(2, durationProgress, 0.0f); } + public static Offset EndMarker(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class MarkerVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyField(tablePos, 4 /*Name*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 6 /*Progress*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 8 /*DurationProgress*/, 4 /*float*/, 4, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct Metadata : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static Metadata GetRootAsMetadata(ByteBuffer _bb) { return GetRootAsMetadata(_bb, new Metadata()); } + public static Metadata GetRootAsMetadata(ByteBuffer _bb, Metadata obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public Metadata __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public uint Name { get { int o = __p.__offset(4); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public float Width { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } } + public float Height { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } } + public long DurationTicks { get { int o = __p.__offset(10); return o != 0 ? __p.bb.GetLong(o + __p.bb_pos) : (long)0; } } + public float FramesPerSecond { get { int o = __p.__offset(12); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyBinding? PropertyBindings(int j) { int o = __p.__offset(14); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyBinding?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyBinding()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int PropertyBindingsLength { get { int o = __p.__offset(14); return o != 0 ? __p.__vector_len(o) : 0; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Marker? Markers(int j) { int o = __p.__offset(16); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Marker?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Marker()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int MarkersLength { get { int o = __p.__offset(16); return o != 0 ? __p.__vector_len(o) : 0; } } + public uint ThemingPropertySet { get { int o = __p.__offset(18); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + + public static Offset CreateMetadata(FlatBufferBuilder builder, + uint name = 4294967295, + float width = 0.0f, + float height = 0.0f, + long duration_ticks = 0, + float frames_per_second = 0.0f, + VectorOffset property_bindingsOffset = default(VectorOffset), + VectorOffset markersOffset = default(VectorOffset), + uint theming_property_set = 4294967295) { + builder.StartTable(8); + Metadata.AddDurationTicks(builder, duration_ticks); + Metadata.AddThemingPropertySet(builder, theming_property_set); + Metadata.AddMarkers(builder, markersOffset); + Metadata.AddPropertyBindings(builder, property_bindingsOffset); + Metadata.AddFramesPerSecond(builder, frames_per_second); + Metadata.AddHeight(builder, height); + Metadata.AddWidth(builder, width); + Metadata.AddName(builder, name); + return Metadata.EndMetadata(builder); + } + + public static void StartMetadata(FlatBufferBuilder builder) { builder.StartTable(8); } + public static void AddName(FlatBufferBuilder builder, uint name) { builder.AddUint(0, name, 4294967295); } + public static void AddWidth(FlatBufferBuilder builder, float width) { builder.AddFloat(1, width, 0.0f); } + public static void AddHeight(FlatBufferBuilder builder, float height) { builder.AddFloat(2, height, 0.0f); } + public static void AddDurationTicks(FlatBufferBuilder builder, long durationTicks) { builder.AddLong(3, durationTicks, 0); } + public static void AddFramesPerSecond(FlatBufferBuilder builder, float framesPerSecond) { builder.AddFloat(4, framesPerSecond, 0.0f); } + public static void AddPropertyBindings(FlatBufferBuilder builder, VectorOffset propertyBindingsOffset) { builder.AddOffset(5, propertyBindingsOffset.Value, 0); } + public static VectorOffset CreatePropertyBindingsVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreatePropertyBindingsVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreatePropertyBindingsVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreatePropertyBindingsVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartPropertyBindingsVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddMarkers(FlatBufferBuilder builder, VectorOffset markersOffset) { builder.AddOffset(6, markersOffset.Value, 0); } + public static VectorOffset CreateMarkersVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreateMarkersVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateMarkersVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateMarkersVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartMarkersVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddThemingPropertySet(FlatBufferBuilder builder, uint themingPropertySet) { builder.AddUint(7, themingPropertySet, 4294967295); } + public static Offset EndMetadata(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class MetadataVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyField(tablePos, 4 /*Name*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 6 /*Width*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 8 /*Height*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 10 /*DurationTicks*/, 8 /*long*/, 8, false) + && verifier.VerifyField(tablePos, 12 /*FramesPerSecond*/, 4 /*float*/, 4, false) + && verifier.VerifyVectorOfTables(tablePos, 14 /*PropertyBindings*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertyBindingVerify.Verify, false) + && verifier.VerifyVectorOfTables(tablePos, 16 /*Markers*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.MarkerVerify.Verify, false) + && verifier.VerifyField(tablePos, 18 /*ThemingPropertySet*/, 4 /*uint*/, 4, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct LottieComposition : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static LottieComposition GetRootAsLottieComposition(ByteBuffer _bb) { return GetRootAsLottieComposition(_bb, new LottieComposition()); } + public static LottieComposition GetRootAsLottieComposition(ByteBuffer _bb, LottieComposition obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public static bool LottieCompositionBufferHasIdentifier(ByteBuffer _bb) { return Table.__has_identifier(_bb, "LCMP"); } + public static bool VerifyLottieComposition(ByteBuffer _bb) {Google.FlatBuffers.Verifier verifier = new Google.FlatBuffers.Verifier(_bb); return verifier.VerifyBuffer("LCMP", false, LottieCompositionVerify.Verify); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public LottieComposition __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public ushort SchemaVersion { get { int o = __p.__offset(4); return o != 0 ? __p.bb.GetUshort(o + __p.bb_pos) : (ushort)0; } } + public ushort RequiredUapVersion { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetUshort(o + __p.bb_pos) : (ushort)0; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Metadata? Metadata { get { int o = __p.__offset(8); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Metadata?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Metadata()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } + public uint RootVisual { get { int o = __p.__offset(10); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public string Strings(int j) { int o = __p.__offset(12); return o != 0 ? __p.__string(__p.__vector(o) + j * 4) : null; } + public int StringsLength { get { int o = __p.__offset(12); return o != 0 ? __p.__vector_len(o) : 0; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Visual? Visuals(int j) { int o = __p.__offset(14); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Visual?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Visual()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int VisualsLength { get { int o = __p.__offset(14); return o != 0 ? __p.__vector_len(o) : 0; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Shape? Shapes(int j) { int o = __p.__offset(16); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Shape?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Shape()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int ShapesLength { get { int o = __p.__offset(16); return o != 0 ? __p.__vector_len(o) : 0; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Geometry? Geometries(int j) { int o = __p.__offset(18); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Geometry?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Geometry()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int GeometriesLength { get { int o = __p.__offset(18); return o != 0 ? __p.__vector_len(o) : 0; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CanvasGeometry? CanvasGeometries(int j) { int o = __p.__offset(20); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CanvasGeometry?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CanvasGeometry()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int CanvasGeometriesLength { get { int o = __p.__offset(20); return o != 0 ? __p.__vector_len(o) : 0; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Brush? Brushes(int j) { int o = __p.__offset(22); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Brush?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Brush()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int BrushesLength { get { int o = __p.__offset(22); return o != 0 ? __p.__vector_len(o) : 0; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.GradientStop? GradientStops(int j) { int o = __p.__offset(24); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.GradientStop?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.GradientStop()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int GradientStopsLength { get { int o = __p.__offset(24); return o != 0 ? __p.__vector_len(o) : 0; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ViewBox? ViewBoxes(int j) { int o = __p.__offset(26); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ViewBox?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ViewBox()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int ViewBoxesLength { get { int o = __p.__offset(26); return o != 0 ? __p.__vector_len(o) : 0; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Clip? Clips(int j) { int o = __p.__offset(28); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Clip?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Clip()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int ClipsLength { get { int o = __p.__offset(28); return o != 0 ? __p.__vector_len(o) : 0; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Shadow? Shadows(int j) { int o = __p.__offset(30); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Shadow?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Shadow()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int ShadowsLength { get { int o = __p.__offset(30); return o != 0 ? __p.__vector_len(o) : 0; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Surface? Surfaces(int j) { int o = __p.__offset(32); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Surface?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Surface()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int SurfacesLength { get { int o = __p.__offset(32); return o != 0 ? __p.__vector_len(o) : 0; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Effect? Effects(int j) { int o = __p.__offset(34); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Effect?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Effect()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int EffectsLength { get { int o = __p.__offset(34); return o != 0 ? __p.__vector_len(o) : 0; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Easing? Easings(int j) { int o = __p.__offset(36); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Easing?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Easing()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int EasingsLength { get { int o = __p.__offset(36); return o != 0 ? __p.__vector_len(o) : 0; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Animation? Animations(int j) { int o = __p.__offset(38); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Animation?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Animation()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int AnimationsLength { get { int o = __p.__offset(38); return o != 0 ? __p.__vector_len(o) : 0; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertySet? PropertySets(int j) { int o = __p.__offset(40); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertySet?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertySet()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int PropertySetsLength { get { int o = __p.__offset(40); return o != 0 ? __p.__vector_len(o) : 0; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Controller? Controllers(int j) { int o = __p.__offset(42); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Controller?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Controller()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } + public int ControllersLength { get { int o = __p.__offset(42); return o != 0 ? __p.__vector_len(o) : 0; } } + public uint CustomControllers(int j) { int o = __p.__offset(44); return o != 0 ? __p.bb.GetUint(__p.__vector(o) + j * 4) : (uint)0; } + public int CustomControllersLength { get { int o = __p.__offset(44); return o != 0 ? __p.__vector_len(o) : 0; } } +#if ENABLE_SPAN_T + public Span GetCustomControllersBytes() { return __p.__vector_as_span(44, 4); } +#else + public ArraySegment? GetCustomControllersBytes() { return __p.__vector_as_arraysegment(44); } +#endif + public uint[] GetCustomControllersArray() { return __p.__vector_as_array(44); } + + public static Offset CreateLottieComposition(FlatBufferBuilder builder, + ushort schema_version = 0, + ushort required_uap_version = 0, + Offset metadataOffset = default(Offset), + uint root_visual = 4294967295, + VectorOffset stringsOffset = default(VectorOffset), + VectorOffset visualsOffset = default(VectorOffset), + VectorOffset shapesOffset = default(VectorOffset), + VectorOffset geometriesOffset = default(VectorOffset), + VectorOffset canvas_geometriesOffset = default(VectorOffset), + VectorOffset brushesOffset = default(VectorOffset), + VectorOffset gradient_stopsOffset = default(VectorOffset), + VectorOffset view_boxesOffset = default(VectorOffset), + VectorOffset clipsOffset = default(VectorOffset), + VectorOffset shadowsOffset = default(VectorOffset), + VectorOffset surfacesOffset = default(VectorOffset), + VectorOffset effectsOffset = default(VectorOffset), + VectorOffset easingsOffset = default(VectorOffset), + VectorOffset animationsOffset = default(VectorOffset), + VectorOffset property_setsOffset = default(VectorOffset), + VectorOffset controllersOffset = default(VectorOffset), + VectorOffset custom_controllersOffset = default(VectorOffset)) { + builder.StartTable(21); + LottieComposition.AddCustomControllers(builder, custom_controllersOffset); + LottieComposition.AddControllers(builder, controllersOffset); + LottieComposition.AddPropertySets(builder, property_setsOffset); + LottieComposition.AddAnimations(builder, animationsOffset); + LottieComposition.AddEasings(builder, easingsOffset); + LottieComposition.AddEffects(builder, effectsOffset); + LottieComposition.AddSurfaces(builder, surfacesOffset); + LottieComposition.AddShadows(builder, shadowsOffset); + LottieComposition.AddClips(builder, clipsOffset); + LottieComposition.AddViewBoxes(builder, view_boxesOffset); + LottieComposition.AddGradientStops(builder, gradient_stopsOffset); + LottieComposition.AddBrushes(builder, brushesOffset); + LottieComposition.AddCanvasGeometries(builder, canvas_geometriesOffset); + LottieComposition.AddGeometries(builder, geometriesOffset); + LottieComposition.AddShapes(builder, shapesOffset); + LottieComposition.AddVisuals(builder, visualsOffset); + LottieComposition.AddStrings(builder, stringsOffset); + LottieComposition.AddRootVisual(builder, root_visual); + LottieComposition.AddMetadata(builder, metadataOffset); + LottieComposition.AddRequiredUapVersion(builder, required_uap_version); + LottieComposition.AddSchemaVersion(builder, schema_version); + return LottieComposition.EndLottieComposition(builder); + } + + public static void StartLottieComposition(FlatBufferBuilder builder) { builder.StartTable(21); } + public static void AddSchemaVersion(FlatBufferBuilder builder, ushort schemaVersion) { builder.AddUshort(0, schemaVersion, 0); } + public static void AddRequiredUapVersion(FlatBufferBuilder builder, ushort requiredUapVersion) { builder.AddUshort(1, requiredUapVersion, 0); } + public static void AddMetadata(FlatBufferBuilder builder, Offset metadataOffset) { builder.AddOffset(2, metadataOffset.Value, 0); } + public static void AddRootVisual(FlatBufferBuilder builder, uint rootVisual) { builder.AddUint(3, rootVisual, 4294967295); } + public static void AddStrings(FlatBufferBuilder builder, VectorOffset stringsOffset) { builder.AddOffset(4, stringsOffset.Value, 0); } + public static VectorOffset CreateStringsVector(FlatBufferBuilder builder, StringOffset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreateStringsVectorBlock(FlatBufferBuilder builder, StringOffset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateStringsVectorBlock(FlatBufferBuilder builder, ArraySegment data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateStringsVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartStringsVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddVisuals(FlatBufferBuilder builder, VectorOffset visualsOffset) { builder.AddOffset(5, visualsOffset.Value, 0); } + public static VectorOffset CreateVisualsVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreateVisualsVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateVisualsVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateVisualsVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartVisualsVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddShapes(FlatBufferBuilder builder, VectorOffset shapesOffset) { builder.AddOffset(6, shapesOffset.Value, 0); } + public static VectorOffset CreateShapesVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreateShapesVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateShapesVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateShapesVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartShapesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddGeometries(FlatBufferBuilder builder, VectorOffset geometriesOffset) { builder.AddOffset(7, geometriesOffset.Value, 0); } + public static VectorOffset CreateGeometriesVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreateGeometriesVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateGeometriesVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateGeometriesVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartGeometriesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddCanvasGeometries(FlatBufferBuilder builder, VectorOffset canvasGeometriesOffset) { builder.AddOffset(8, canvasGeometriesOffset.Value, 0); } + public static VectorOffset CreateCanvasGeometriesVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreateCanvasGeometriesVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateCanvasGeometriesVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateCanvasGeometriesVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartCanvasGeometriesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddBrushes(FlatBufferBuilder builder, VectorOffset brushesOffset) { builder.AddOffset(9, brushesOffset.Value, 0); } + public static VectorOffset CreateBrushesVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreateBrushesVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateBrushesVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateBrushesVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartBrushesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddGradientStops(FlatBufferBuilder builder, VectorOffset gradientStopsOffset) { builder.AddOffset(10, gradientStopsOffset.Value, 0); } + public static VectorOffset CreateGradientStopsVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreateGradientStopsVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateGradientStopsVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateGradientStopsVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartGradientStopsVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddViewBoxes(FlatBufferBuilder builder, VectorOffset viewBoxesOffset) { builder.AddOffset(11, viewBoxesOffset.Value, 0); } + public static VectorOffset CreateViewBoxesVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreateViewBoxesVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateViewBoxesVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateViewBoxesVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartViewBoxesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddClips(FlatBufferBuilder builder, VectorOffset clipsOffset) { builder.AddOffset(12, clipsOffset.Value, 0); } + public static VectorOffset CreateClipsVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreateClipsVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateClipsVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateClipsVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartClipsVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddShadows(FlatBufferBuilder builder, VectorOffset shadowsOffset) { builder.AddOffset(13, shadowsOffset.Value, 0); } + public static VectorOffset CreateShadowsVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreateShadowsVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateShadowsVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateShadowsVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartShadowsVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddSurfaces(FlatBufferBuilder builder, VectorOffset surfacesOffset) { builder.AddOffset(14, surfacesOffset.Value, 0); } + public static VectorOffset CreateSurfacesVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreateSurfacesVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateSurfacesVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateSurfacesVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartSurfacesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddEffects(FlatBufferBuilder builder, VectorOffset effectsOffset) { builder.AddOffset(15, effectsOffset.Value, 0); } + public static VectorOffset CreateEffectsVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreateEffectsVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateEffectsVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateEffectsVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartEffectsVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddEasings(FlatBufferBuilder builder, VectorOffset easingsOffset) { builder.AddOffset(16, easingsOffset.Value, 0); } + public static VectorOffset CreateEasingsVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreateEasingsVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateEasingsVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateEasingsVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartEasingsVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddAnimations(FlatBufferBuilder builder, VectorOffset animationsOffset) { builder.AddOffset(17, animationsOffset.Value, 0); } + public static VectorOffset CreateAnimationsVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreateAnimationsVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateAnimationsVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateAnimationsVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartAnimationsVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddPropertySets(FlatBufferBuilder builder, VectorOffset propertySetsOffset) { builder.AddOffset(18, propertySetsOffset.Value, 0); } + public static VectorOffset CreatePropertySetsVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreatePropertySetsVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreatePropertySetsVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreatePropertySetsVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartPropertySetsVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddControllers(FlatBufferBuilder builder, VectorOffset controllersOffset) { builder.AddOffset(19, controllersOffset.Value, 0); } + public static VectorOffset CreateControllersVector(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } + public static VectorOffset CreateControllersVectorBlock(FlatBufferBuilder builder, Offset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateControllersVectorBlock(FlatBufferBuilder builder, ArraySegment> data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateControllersVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add>(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartControllersVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddCustomControllers(FlatBufferBuilder builder, VectorOffset customControllersOffset) { builder.AddOffset(20, customControllersOffset.Value, 0); } + public static VectorOffset CreateCustomControllersVector(FlatBufferBuilder builder, uint[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddUint(data[i]); return builder.EndVector(); } + public static VectorOffset CreateCustomControllersVectorBlock(FlatBufferBuilder builder, uint[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateCustomControllersVectorBlock(FlatBufferBuilder builder, ArraySegment data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateCustomControllersVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartCustomControllersVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static Offset EndLottieComposition(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } + public static void FinishLottieCompositionBuffer(FlatBufferBuilder builder, Offset offset) { builder.Finish(offset.Value, "LCMP"); } + public static void FinishSizePrefixedLottieCompositionBuffer(FlatBufferBuilder builder, Offset offset) { builder.FinishSizePrefixed(offset.Value, "LCMP"); } +} + + +static public class LottieCompositionVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyField(tablePos, 4 /*SchemaVersion*/, 2 /*ushort*/, 2, false) + && verifier.VerifyField(tablePos, 6 /*RequiredUapVersion*/, 2 /*ushort*/, 2, false) + && verifier.VerifyTable(tablePos, 8 /*Metadata*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.MetadataVerify.Verify, false) + && verifier.VerifyField(tablePos, 10 /*RootVisual*/, 4 /*uint*/, 4, false) + && verifier.VerifyVectorOfStrings(tablePos, 12 /*Strings*/, false) + && verifier.VerifyVectorOfTables(tablePos, 14 /*Visuals*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.VisualVerify.Verify, false) + && verifier.VerifyVectorOfTables(tablePos, 16 /*Shapes*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ShapeVerify.Verify, false) + && verifier.VerifyVectorOfTables(tablePos, 18 /*Geometries*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.GeometryVerify.Verify, false) + && verifier.VerifyVectorOfTables(tablePos, 20 /*CanvasGeometries*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CanvasGeometryVerify.Verify, false) + && verifier.VerifyVectorOfTables(tablePos, 22 /*Brushes*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.BrushVerify.Verify, false) + && verifier.VerifyVectorOfTables(tablePos, 24 /*GradientStops*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.GradientStopVerify.Verify, false) + && verifier.VerifyVectorOfTables(tablePos, 26 /*ViewBoxes*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ViewBoxVerify.Verify, false) + && verifier.VerifyVectorOfTables(tablePos, 28 /*Clips*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ClipVerify.Verify, false) + && verifier.VerifyVectorOfTables(tablePos, 30 /*Shadows*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ShadowVerify.Verify, false) + && verifier.VerifyVectorOfTables(tablePos, 32 /*Surfaces*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.SurfaceVerify.Verify, false) + && verifier.VerifyVectorOfTables(tablePos, 34 /*Effects*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.EffectVerify.Verify, false) + && verifier.VerifyVectorOfTables(tablePos, 36 /*Easings*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.EasingVerify.Verify, false) + && verifier.VerifyVectorOfTables(tablePos, 38 /*Animations*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.AnimationVerify.Verify, false) + && verifier.VerifyVectorOfTables(tablePos, 40 /*PropertySets*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.PropertySetVerify.Verify, false) + && verifier.VerifyVectorOfTables(tablePos, 42 /*Controllers*/, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.ControllerVerify.Verify, false) + && verifier.VerifyVectorOfData(tablePos, 44 /*CustomControllers*/, 4 /*uint*/, false) + && verifier.VerifyTableEnd(tablePos); + } +} +public struct CanvasGeometry : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } + public static CanvasGeometry GetRootAsCanvasGeometry(ByteBuffer _bb) { return GetRootAsCanvasGeometry(_bb, new CanvasGeometry()); } + public static CanvasGeometry GetRootAsCanvasGeometry(ByteBuffer _bb, CanvasGeometry obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public CanvasGeometry __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CanvasGeometryKind Kind { get { int o = __p.__offset(4); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CanvasGeometryKind)__p.bb.Get(o + __p.bb_pos) : CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CanvasGeometryKind.Combination; } } + public uint A { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public uint B { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public byte CombineMode { get { int o = __p.__offset(10); return o != 0 ? __p.bb.Get(o + __p.bb_pos) : (byte)0; } } + public CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Mat3x2? Matrix { get { int o = __p.__offset(12); return o != 0 ? (CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Mat3x2?)(new CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Mat3x2()).__assign(o + __p.bb_pos, __p.bb) : null; } } + public uint Source { get { int o = __p.__offset(14); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)4294967295; } } + public uint Geometries(int j) { int o = __p.__offset(16); return o != 0 ? __p.bb.GetUint(__p.__vector(o) + j * 4) : (uint)0; } + public int GeometriesLength { get { int o = __p.__offset(16); return o != 0 ? __p.__vector_len(o) : 0; } } +#if ENABLE_SPAN_T + public Span GetGeometriesBytes() { return __p.__vector_as_span(16, 4); } +#else + public ArraySegment? GetGeometriesBytes() { return __p.__vector_as_arraysegment(16); } +#endif + public uint[] GetGeometriesArray() { return __p.__vector_as_array(16); } + public byte FillRule { get { int o = __p.__offset(18); return o != 0 ? __p.bb.Get(o + __p.bb_pos) : (byte)0; } } + public byte Ops(int j) { int o = __p.__offset(20); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; } + public int OpsLength { get { int o = __p.__offset(20); return o != 0 ? __p.__vector_len(o) : 0; } } +#if ENABLE_SPAN_T + public Span GetOpsBytes() { return __p.__vector_as_span(20, 1); } +#else + public ArraySegment? GetOpsBytes() { return __p.__vector_as_arraysegment(20); } +#endif + public byte[] GetOpsArray() { return __p.__vector_as_array(20); } + public float Operands(int j) { int o = __p.__offset(22); return o != 0 ? __p.bb.GetFloat(__p.__vector(o) + j * 4) : (float)0; } + public int OperandsLength { get { int o = __p.__offset(22); return o != 0 ? __p.__vector_len(o) : 0; } } +#if ENABLE_SPAN_T + public Span GetOperandsBytes() { return __p.__vector_as_span(22, 4); } +#else + public ArraySegment? GetOperandsBytes() { return __p.__vector_as_arraysegment(22); } +#endif + public float[] GetOperandsArray() { return __p.__vector_as_array(22); } + public float X { get { int o = __p.__offset(24); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } } + public float Y { get { int o = __p.__offset(26); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } } + public float W { get { int o = __p.__offset(28); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } } + public float H { get { int o = __p.__offset(30); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } } + public float RadiusX { get { int o = __p.__offset(32); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } } + public float RadiusY { get { int o = __p.__offset(34); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } } + + public static void StartCanvasGeometry(FlatBufferBuilder builder) { builder.StartTable(16); } + public static void AddKind(FlatBufferBuilder builder, CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CanvasGeometryKind kind) { builder.AddByte(0, (byte)kind, 0); } + public static void AddA(FlatBufferBuilder builder, uint a) { builder.AddUint(1, a, 4294967295); } + public static void AddB(FlatBufferBuilder builder, uint b) { builder.AddUint(2, b, 4294967295); } + public static void AddCombineMode(FlatBufferBuilder builder, byte combineMode) { builder.AddByte(3, combineMode, 0); } + public static void AddMatrix(FlatBufferBuilder builder, Offset matrixOffset) { builder.AddStruct(4, matrixOffset.Value, 0); } + public static void AddSource(FlatBufferBuilder builder, uint source) { builder.AddUint(5, source, 4294967295); } + public static void AddGeometries(FlatBufferBuilder builder, VectorOffset geometriesOffset) { builder.AddOffset(6, geometriesOffset.Value, 0); } + public static VectorOffset CreateGeometriesVector(FlatBufferBuilder builder, uint[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddUint(data[i]); return builder.EndVector(); } + public static VectorOffset CreateGeometriesVectorBlock(FlatBufferBuilder builder, uint[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateGeometriesVectorBlock(FlatBufferBuilder builder, ArraySegment data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateGeometriesVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartGeometriesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddFillRule(FlatBufferBuilder builder, byte fillRule) { builder.AddByte(7, fillRule, 0); } + public static void AddOps(FlatBufferBuilder builder, VectorOffset opsOffset) { builder.AddOffset(8, opsOffset.Value, 0); } + public static VectorOffset CreateOpsVector(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddByte(data[i]); return builder.EndVector(); } + public static VectorOffset CreateOpsVectorBlock(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateOpsVectorBlock(FlatBufferBuilder builder, ArraySegment data) { builder.StartVector(1, data.Count, 1); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateOpsVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartOpsVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); } + public static void AddOperands(FlatBufferBuilder builder, VectorOffset operandsOffset) { builder.AddOffset(9, operandsOffset.Value, 0); } + public static VectorOffset CreateOperandsVector(FlatBufferBuilder builder, float[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddFloat(data[i]); return builder.EndVector(); } + public static VectorOffset CreateOperandsVectorBlock(FlatBufferBuilder builder, float[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateOperandsVectorBlock(FlatBufferBuilder builder, ArraySegment data) { builder.StartVector(4, data.Count, 4); builder.Add(data); return builder.EndVector(); } + public static VectorOffset CreateOperandsVectorBlock(FlatBufferBuilder builder, IntPtr dataPtr, int sizeInBytes) { builder.StartVector(1, sizeInBytes, 1); builder.Add(dataPtr, sizeInBytes); return builder.EndVector(); } + public static void StartOperandsVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } + public static void AddX(FlatBufferBuilder builder, float x) { builder.AddFloat(10, x, 0.0f); } + public static void AddY(FlatBufferBuilder builder, float y) { builder.AddFloat(11, y, 0.0f); } + public static void AddW(FlatBufferBuilder builder, float w) { builder.AddFloat(12, w, 0.0f); } + public static void AddH(FlatBufferBuilder builder, float h) { builder.AddFloat(13, h, 0.0f); } + public static void AddRadiusX(FlatBufferBuilder builder, float radiusX) { builder.AddFloat(14, radiusX, 0.0f); } + public static void AddRadiusY(FlatBufferBuilder builder, float radiusY) { builder.AddFloat(15, radiusY, 0.0f); } + public static Offset EndCanvasGeometry(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } +} + + +static public class CanvasGeometryVerify +{ + static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) + { + return verifier.VerifyTableStart(tablePos) + && verifier.VerifyField(tablePos, 4 /*Kind*/, 1 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.CanvasGeometryKind*/, 1, false) + && verifier.VerifyField(tablePos, 6 /*A*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 8 /*B*/, 4 /*uint*/, 4, false) + && verifier.VerifyField(tablePos, 10 /*CombineMode*/, 1 /*byte*/, 1, false) + && verifier.VerifyField(tablePos, 12 /*Matrix*/, 24 /*CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema.Mat3x2*/, 4, false) + && verifier.VerifyField(tablePos, 14 /*Source*/, 4 /*uint*/, 4, false) + && verifier.VerifyVectorOfData(tablePos, 16 /*Geometries*/, 4 /*uint*/, false) + && verifier.VerifyField(tablePos, 18 /*FillRule*/, 1 /*byte*/, 1, false) + && verifier.VerifyVectorOfData(tablePos, 20 /*Ops*/, 1 /*byte*/, false) + && verifier.VerifyVectorOfData(tablePos, 22 /*Operands*/, 4 /*float*/, false) + && verifier.VerifyField(tablePos, 24 /*X*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 26 /*Y*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 28 /*W*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 30 /*H*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 32 /*RadiusX*/, 4 /*float*/, 4, false) + && verifier.VerifyField(tablePos, 34 /*RadiusY*/, 4 /*float*/, 4, false) + && verifier.VerifyTableEnd(tablePos); + } +} + +} diff --git a/source/CompDataFlatbuffer/GraphIndexer.cs b/source/CompDataFlatbuffer/GraphIndexer.cs new file mode 100644 index 00000000..7d5b6bcc --- /dev/null +++ b/source/CompDataFlatbuffer/GraphIndexer.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable enable + +using System; +using System.Collections.Generic; +using CommunityToolkit.WinUI.Lottie.WinCompData; +using CommunityToolkit.WinUI.Lottie.WinCompData.Mgce; +using CommunityToolkit.WinUI.Lottie.WinCompData.Mgcg; +using CommunityToolkit.WinUI.Lottie.WinUIXamlMediaData; + +namespace CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer +{ + /// + /// Walks a WinCompData graph and assigns a dense index to every node, grouped by + /// the that the node is serialized into. + /// + /// + /// + /// Indices are assigned in the order that nodes are first reached by a depth first + /// walk from the root. The walk order is fully determined by the shape of the graph, + /// so serializing the same graph twice produces identical output. + /// + /// + /// Nodes are identified by reference, not by value. This preserves the sharing in + /// the graph: a node that is referenced from several places is stored once and + /// referenced by index, which is what lets the interpreter realize it once. + /// + /// + sealed class GraphIndexer + { + // Nodes are keyed by reference so that distinct but equal objects stay distinct, + // matching the reference-identity caching that Instantiator performs at runtime. + readonly Dictionary _visuals = new Dictionary(ReferenceComparer.Instance); + readonly Dictionary _shapes = new Dictionary(ReferenceComparer.Instance); + readonly Dictionary _geometries = new Dictionary(ReferenceComparer.Instance); + readonly Dictionary _canvasGeometries = new Dictionary(ReferenceComparer.Instance); + readonly Dictionary _brushes = new Dictionary(ReferenceComparer.Instance); + readonly Dictionary _gradientStops = new Dictionary(ReferenceComparer.Instance); + readonly Dictionary _viewBoxes = new Dictionary(ReferenceComparer.Instance); + readonly Dictionary _clips = new Dictionary(ReferenceComparer.Instance); + readonly Dictionary _shadows = new Dictionary(ReferenceComparer.Instance); + readonly Dictionary _surfaces = new Dictionary(ReferenceComparer.Instance); + readonly Dictionary _effects = new Dictionary(ReferenceComparer.Instance); + readonly Dictionary _easings = new Dictionary(ReferenceComparer.Instance); + readonly Dictionary _animations = new Dictionary(ReferenceComparer.Instance); + readonly Dictionary _propertySets = new Dictionary(ReferenceComparer.Instance); + readonly Dictionary _controllers = new Dictionary(ReferenceComparer.Instance); + + readonly Dictionary _strings = new Dictionary(StringComparer.Ordinal); + + // Set once the string table has been written to the buffer. Interning a new + // string after that point would hand out an index that is past the end of the + // serialized table, so it is treated as a programming error rather than being + // allowed to silently corrupt the output. + bool _stringsAreFrozen; + + GraphIndexer() + { + } + + internal List VisualList { get; } = new List(); + + internal List ShapeList { get; } = new List(); + + internal List GeometryList { get; } = new List(); + + internal List CanvasGeometryList { get; } = new List(); + + internal List BrushList { get; } = new List(); + + internal List GradientStopList { get; } = new List(); + + internal List ViewBoxList { get; } = new List(); + + internal List ClipList { get; } = new List(); + + internal List ShadowList { get; } = new List(); + + internal List SurfaceList { get; } = new List(); + + internal List EffectList { get; } = new List(); + + internal List EasingList { get; } = new List(); + + internal List AnimationList { get; } = new List(); + + internal List PropertySetList { get; } = new List(); + + internal List ControllerList { get; } = new List(); + + internal List StringList { get; } = new List(); + + /// + /// Walks the graph rooted at and returns the resulting index. + /// + /// The root visual of the graph. + /// An indexer holding every node reachable from . + internal static GraphIndexer Index(Visual root) + { + var result = new GraphIndexer(); + result.GetVisual(root); + return result; + } + + /// + /// Returns the index of a string, adding it to the string table if necessary. + /// + /// The string, or null. + /// The index of the string, or if null. + internal uint GetString(string? value) + { + if (value is null) + { + return Format.NullIndex; + } + + if (!_strings.TryGetValue(value, out var index)) + { + if (_stringsAreFrozen) + { + throw new InvalidOperationException( + $"The string \"{value}\" was interned after the string table was written."); + } + + index = StringList.Count; + StringList.Add(value); + _strings.Add(value, index); + } + + return (uint)index; + } + + /// + /// Prevents any further strings from being added. Called once the string table has + /// been written, so that a missed interning site fails loudly instead of producing + /// an out of range string index. + /// + internal void FreezeStrings() => _stringsAreFrozen = true; + + internal uint GetVisual(Visual? value) => Index(_visuals, value); + + internal uint GetShape(CompositionShape? value) => Index(_shapes, value); + + internal uint GetGeometry(CompositionGeometry? value) => Index(_geometries, value); + + internal uint GetCanvasGeometry(CanvasGeometry? value) => Index(_canvasGeometries, value); + + internal uint GetBrush(CompositionBrush? value) => Index(_brushes, value); + + internal uint GetGradientStop(CompositionColorGradientStop? value) => Index(_gradientStops, value); + + internal uint GetViewBox(CompositionViewBox? value) => Index(_viewBoxes, value); + + internal uint GetClip(CompositionClip? value) => Index(_clips, value); + + internal uint GetShadow(CompositionShadow? value) => Index(_shadows, value); + + internal uint GetSurface(ICompositionSurface? value) => Index(_surfaces, value); + + internal uint GetEffect(GraphicsEffectBase? value) => Index(_effects, value); + + internal uint GetEasing(CompositionEasingFunction? value) => Index(_easings, value); + + internal uint GetAnimation(CompositionAnimation? value) => Index(_animations, value); + + internal uint GetPropertySet(CompositionPropertySet? value) => Index(_propertySets, value); + + internal uint GetController(AnimationController? value) => Index(_controllers, value); + + /// + /// Returns the index of an already-discovered object as a packed object reference. + /// Used for the fields that can refer to any kind of object, such as the target of + /// an animation reference parameter. + /// + /// The object, or null. + /// The packed object reference, or . + internal uint GetObjectReference(CompositionObject? value) + { + if (value is null) + { + return Format.NullIndex; + } + + var (category, index) = value switch + { + Visual visual => (Schema.ObjectCategory.Visual, GetVisual(visual)), + CompositionShape shape => (Schema.ObjectCategory.Shape, GetShape(shape)), + CompositionGeometry geometry => (Schema.ObjectCategory.Geometry, GetGeometry(geometry)), + CompositionBrush brush => (Schema.ObjectCategory.Brush, GetBrush(brush)), + CompositionAnimation animation => (Schema.ObjectCategory.Animation, GetAnimation(animation)), + CompositionEasingFunction easing => (Schema.ObjectCategory.Easing, GetEasing(easing)), + CompositionPropertySet propertySet => (Schema.ObjectCategory.PropertySet, GetPropertySet(propertySet)), + CompositionVisualSurface surface => (Schema.ObjectCategory.Surface, GetSurface(surface)), + CompositionClip clip => (Schema.ObjectCategory.Clip, GetClip(clip)), + AnimationController controller => (Schema.ObjectCategory.Controller, GetController(controller)), + CompositionShadow shadow => (Schema.ObjectCategory.Shadow, GetShadow(shadow)), + CompositionColorGradientStop stop => (Schema.ObjectCategory.GradientStop, GetGradientStop(stop)), + CompositionViewBox viewBox => (Schema.ObjectCategory.ViewBox, GetViewBox(viewBox)), + _ => throw new InvalidOperationException($"Cannot reference {value.Type}."), + }; + + return Format.PackObjectReference(category, (int)index); + } + + // Returns the plain index of a node, adding it to the graph if it has not been + // seen before. The node is registered before its children are walked so that + // cycles terminate. + uint Index(Dictionary map, T? value) + where T : class + { + if (value is null) + { + return Format.NullIndex; + } + + if (map.TryGetValue(value, out var existing)) + { + return (uint)existing; + } + + var index = map.Count; + map.Add(value, index); + Add(value); + return (uint)index; + } + + // Appends a newly discovered node to its category list and walks its children. + void Add(object value) + { + switch (value) + { + case Visual visual: + VisualList.Add(visual); + WalkVisual(visual); + break; + case CompositionShape shape: + ShapeList.Add(shape); + WalkShape(shape); + break; + case CompositionGeometry geometry: + GeometryList.Add(geometry); + WalkGeometry(geometry); + break; + case CanvasGeometry canvasGeometry: + CanvasGeometryList.Add(canvasGeometry); + WalkCanvasGeometry(canvasGeometry); + break; + case CompositionBrush brush: + BrushList.Add(brush); + WalkBrush(brush); + break; + case CompositionColorGradientStop stop: + GradientStopList.Add(stop); + WalkCompositionObject(stop); + break; + case CompositionViewBox viewBox: + ViewBoxList.Add(viewBox); + WalkCompositionObject(viewBox); + break; + case CompositionClip clip: + ClipList.Add(clip); + WalkClip(clip); + break; + case CompositionShadow shadow: + ShadowList.Add(shadow); + WalkShadow(shadow); + break; + case ICompositionSurface surface: + SurfaceList.Add(surface); + WalkSurface(surface); + break; + case GraphicsEffectBase effect: + EffectList.Add(effect); + break; + case CompositionEasingFunction easing: + EasingList.Add(easing); + WalkCompositionObject(easing); + break; + case CompositionAnimation animation: + AnimationList.Add(animation); + WalkAnimation(animation); + break; + case CompositionPropertySet propertySet: + PropertySetList.Add(propertySet); + WalkPropertySet(propertySet); + break; + case AnimationController controller: + ControllerList.Add(controller); + WalkController(controller); + break; + default: + throw new InvalidOperationException($"Unexpected node {value.GetType().Name}."); + } + } + + // Walks the state that every CompositionObject has: its comment, its animators, + // and its property set. + void WalkCompositionObject(CompositionObject value) + { + GetString(value.Comment); + + foreach (var animator in value.Animators) + { + GetString(animator.AnimatedProperty); + GetAnimation(animator.Animation); + GetController(animator.Controller); + } + + // A property set is only serialized if it carries state. The property set of a + // property set is itself, so recursing into it unconditionally would not + // terminate. + if (value.Type != CompositionObjectType.CompositionPropertySet && HasState(value.Properties)) + { + GetPropertySet(value.Properties); + } + } + + internal static bool HasState(CompositionPropertySet propertySet) + { + if (propertySet.Names.Count > 0) + { + return true; + } + + foreach (var unused in propertySet.Animators) + { + return true; + } + + return propertySet.Comment is not null; + } + + void WalkVisual(Visual value) + { + WalkCompositionObject(value); + GetClip(value.Clip); + + switch (value) + { + case ShapeVisual shapeVisual: + foreach (var shape in shapeVisual.Shapes) + { + GetShape(shape); + } + + GetViewBox(shapeVisual.ViewBox); + break; + case SpriteVisual spriteVisual: + GetBrush(spriteVisual.Brush); + GetShadow(spriteVisual.Shadow); + break; + case LayerVisual layerVisual: + GetShadow(layerVisual.Shadow); + break; + } + + if (value is ContainerVisual container) + { + foreach (var child in container.Children) + { + GetVisual(child); + } + } + } + + void WalkShape(CompositionShape value) + { + WalkCompositionObject(value); + + switch (value) + { + case CompositionContainerShape containerShape: + foreach (var shape in containerShape.Shapes) + { + GetShape(shape); + } + + break; + case CompositionSpriteShape spriteShape: + GetBrush(spriteShape.FillBrush); + GetBrush(spriteShape.StrokeBrush); + GetGeometry(spriteShape.Geometry); + break; + } + } + + void WalkGeometry(CompositionGeometry value) + { + WalkCompositionObject(value); + + if (value is CompositionPathGeometry pathGeometry && pathGeometry.Path is not null) + { + GetCanvasGeometry((CanvasGeometry)pathGeometry.Path.Source); + } + } + + void WalkCanvasGeometry(CanvasGeometry value) + { + switch (value) + { + case CanvasGeometry.Combination combination: + GetCanvasGeometry(combination.A); + GetCanvasGeometry(combination.B); + break; + case CanvasGeometry.Group group: + foreach (var geometry in group.Geometries) + { + GetCanvasGeometry(geometry); + } + + break; + case CanvasGeometry.TransformedGeometry transformed: + GetCanvasGeometry(transformed.SourceGeometry); + break; + } + } + + void WalkBrush(CompositionBrush value) + { + WalkCompositionObject(value); + + switch (value) + { + case CompositionGradientBrush gradientBrush: + foreach (var stop in gradientBrush.ColorStops) + { + GetGradientStop(stop); + } + + break; + case CompositionSurfaceBrush surfaceBrush: + GetSurface(surfaceBrush.Surface); + break; + case CompositionMaskBrush maskBrush: + GetBrush(maskBrush.Source); + GetBrush(maskBrush.Mask); + break; + case CompositionEffectBrush effectBrush: + var effect = effectBrush.GetEffectFactory().Effect; + GetEffect(effect); + foreach (var source in effect.Sources) + { + GetString(source.Name); + GetBrush(effectBrush.GetSourceParameter(source.Name)); + } + + break; + } + } + + void WalkClip(CompositionClip value) + { + WalkCompositionObject(value); + + if (value is CompositionGeometricClip geometricClip) + { + GetGeometry(geometricClip.Geometry); + } + } + + void WalkShadow(CompositionShadow value) + { + WalkCompositionObject(value); + + if (value is DropShadow dropShadow) + { + GetBrush(dropShadow.Mask); + } + } + + void WalkSurface(ICompositionSurface value) + { + switch (value) + { + case CompositionVisualSurface visualSurface: + WalkCompositionObject(visualSurface); + GetVisual(visualSurface.SourceVisual); + break; + case LoadedImageSurfaceFromUri fromUri: + GetString(fromUri.Uri.ToString()); + break; + } + } + + void WalkAnimation(CompositionAnimation value) + { + WalkCompositionObject(value); + GetString(value.Target); + + foreach (var parameter in value.ReferenceParameters) + { + GetString(parameter.Key); + GetObjectReference(parameter.Value); + } + + switch (value) + { + case ExpressionAnimation expressionAnimation: + GetString(expressionAnimation.Expression.ToText()); + break; + case KeyFrameAnimation_ keyFrameAnimation: + foreach (var keyFrame in keyFrameAnimation.KeyFrames) + { + GetEasing(keyFrame.Easing); + + switch (keyFrame) + { + case KeyFrameAnimation_.ExpressionKeyFrame expressionKeyFrame: + GetString(expressionKeyFrame.Expression.ToText()); + break; + case KeyFrameAnimation.ValueKeyFrame pathKeyFrame: + GetCanvasGeometry((CanvasGeometry)pathKeyFrame.Value.Source); + break; + } + } + + break; + } + } + + void WalkPropertySet(CompositionPropertySet value) + { + GetString(value.Comment); + + foreach (var animator in value.Animators) + { + GetString(animator.AnimatedProperty); + GetAnimation(animator.Animation); + GetController(animator.Controller); + } + + foreach (var name in value.Names) + { + GetString(name.Key); + } + + if (value.Owner is not null) + { + GetObjectReference(value.Owner); + } + } + + void WalkController(AnimationController value) + { + WalkCompositionObject(value); + GetString(value.TargetProperty); + + if (value.TargetObject is not null) + { + GetObjectReference(value.TargetObject); + } + } + + sealed class ReferenceComparer : IEqualityComparer + { + internal static readonly ReferenceComparer Instance = new ReferenceComparer(); + + ReferenceComparer() + { + } + + bool IEqualityComparer.Equals(object? x, object? y) => ReferenceEquals(x, y); + + int IEqualityComparer.GetHashCode(object obj) + => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj); + } + } +} diff --git a/source/LottieFlatbuffer/README.md b/source/LottieFlatbuffer/README.md new file mode 100644 index 00000000..5550fdc3 --- /dev/null +++ b/source/LottieFlatbuffer/README.md @@ -0,0 +1,83 @@ +# LottieFlatbuffer + +`lottie_comp.fbs` is the schema for the serialized form of a `WinCompData` graph. + +## What is serialized, and why that + +A Lottie file goes through several stages before anything is drawn: + +``` +Lottie JSON --> LottieData --> WinCompData graph --> composition tree +``` + +The interesting choice is which of those to serialize. The Lottie authoring format +would be the obvious answer, but it is the wrong one: reading it back still requires +the whole translator, which is by far the largest part of Lottie-Windows and the +part that changes most often. The `WinCompData` graph is much closer to what the +composition engine needs, so a reader for it is small, and it is a closed object +model, so a reader for it is *complete* rather than approximate. + +This is the same seam that the code generators use. `Instantiator.cs`, the C#, C++/CX +and C++/WinRT generators, and this format are all consumers of the same graph, which +is why they all produce the same visual tree. + +## Layout + +The graph is a DAG with sharing, so it is stored as a set of parallel node vectors, +one per category, and every reference is a `uint32` index into one of them. +`0xFFFFFFFF` means no node. Sharing therefore costs nothing: two references to the +same node are two copies of the same index. + +Three fields can point at more than one category — a reference parameter's target, a +property set's owner and a controller's target. Those pack the category into the top +four bits, so they are the only places a reader has to decode a category. Everywhere +else the field's type already says which vector to index. + +Strings are interned into a single vector and referenced by index, which is what +makes the format small: the graph is full of repeated property names such as +`Offset`, `Progress` and `TrimEnd`. + +Path geometry is flattened into a `[ubyte]` of opcodes and a `[float]` of operands +rather than a table per command, because a path can have thousands of commands and a +FlatBuffers table has a fixed overhead that would dominate. + +Serialization is deterministic: the same graph always produces the same bytes, so +output can be diffed and cached. + +## Versioning + +The rules are at the top of `lottie_comp.fbs`. In short: fields may only be added, +never removed or reordered, and `SCHEMA_VERSION` is bumped when they are. A reader +refuses a buffer whose version is higher than the one it was built for, because such +a buffer may carry meaning in fields the reader does not look at. + +## Regenerating + +`flatc` output for both C# and C++ is checked in, so contributors do not need `flatc` +installed. After changing the schema: + +```powershell +.\build\RegenerateFlatbuffers.ps1 +``` + +The script restores vcpkg dependencies, then uses the restored host +`tools\flatbuffers\flatc.exe` to generate both bindings. It uses `VCPKG_ROOT` +when set and otherwise bootstraps the repo-local `.vcpkg` checkout. Override +`VcpkgRoot`, `InstalledDir`, or `HostTriplet` for a different installation. +Updating the FlatBuffers dependency requires updating the manifest and +the `Google.FlatBuffers` NuGet references, then regenerating the bindings. + +## Consumers + +| | | +| --- | --- | +| `source/CompDataFlatbuffer/CompositionSerializer.cs` | Writes a graph | +| `source/CompDataFlatbuffer/CompositionDeserializer.cs` | Reads one back, in C# | +| `source/LottieRuntime` | Reads one back using statically compiled WinUI 2 or WinUI 3 C++/WinRT source | +| `LottieGen -Language flatbuffer` | Produces a `.lcomp` file | +| `tests/CompDataFlatbuffer.Tests` | Asserts a graph survives the round trip unchanged | + +When the requested UAP range needs different translated graphs, LottieGen writes +one `.lcomp` file per range. The file names contain the supported range, such as +`.uap12-plus.lcomp` or `.uap7-11.lcomp`; the consumer selects the appropriate +variant before calling the native reader. diff --git a/source/LottieFlatbuffer/lottie_comp.fbs b/source/LottieFlatbuffer/lottie_comp.fbs new file mode 100644 index 00000000..1aa8d4dc --- /dev/null +++ b/source/LottieFlatbuffer/lottie_comp.fbs @@ -0,0 +1,529 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// +// Serialized form of a translated Lottie animation (a WinCompData object graph). +// +// Design notes +// ------------ +// * The graph is stored as a set of flat node vectors - one per node category - +// and all references between nodes are indices into those vectors rather than +// FlatBuffers offsets. This lets an interpreter keep a single realization cache +// per category that is indexed identically to the serialized data, so +// reference-identity caching is an array lookup rather than a hash lookup. +// * Each category is a single table with a "kind" discriminator rather than a +// union of per-kind tables. This keeps the interpreter to one switch per +// category and lets the shared property-application code be written once. +// * Absent fields mean "property was never set", exactly matching the nullable +// properties of the WinCompData object model. +// +// Versioning rules +// ---------------- +// Changes MUST be additive: new fields are appended to the end of a table, and +// new enum values are appended to the end of an enum. SCHEMA_VERSION is bumped +// for every additive change; readers reject buffers whose schema_version is +// greater than the version they were built against. + +namespace CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Schema; + +// --------------------------------------------------------------------------- +// Value types. +// --------------------------------------------------------------------------- + +struct Vec2 { x: float; y: float; } +struct Vec3 { x: float; y: float; z: float; } +struct Vec4 { x: float; y: float; z: float; w: float; } +struct Mat3x2 { m11: float; m12: float; m21: float; m22: float; m31: float; m32: float; } +struct Mat4x4 { + m11: float; m12: float; m13: float; m14: float; + m21: float; m22: float; m23: float; m24: float; + m31: float; m32: float; m33: float; m34: float; + m41: float; m42: float; m43: float; m44: float; +} +struct Color { a: ubyte; r: ubyte; g: ubyte; b: ubyte; } + +// --------------------------------------------------------------------------- +// Enums. Values match the corresponding WinCompData enums. +// --------------------------------------------------------------------------- + +// Identifies the node vector that an object reference points into. +// An object reference is packed into a uint as (category << 28) | index. +// The value 0xFFFFFFFF means "no reference". +enum ObjectCategory : ubyte { + Visual = 0, + Shape = 1, + Geometry = 2, + Brush = 3, + Animation = 4, + Easing = 5, + PropertySet = 6, + Surface = 7, + Clip = 8, + Controller = 9, + Shadow = 10, + Effect = 11, + GradientStop = 12, + ViewBox = 13, +} + +enum VisualKind : ubyte { Container = 0, Sprite = 1, Shape = 2, Layer = 3 } +enum ShapeKind : ubyte { Container = 0, Sprite = 1 } +enum GeometryKind : ubyte { Path = 0, Rectangle = 1, RoundedRectangle = 2, Ellipse = 3 } +enum BrushKind : ubyte { Color = 0, LinearGradient = 1, RadialGradient = 2, Surface = 3, Mask = 4, Effect = 5 } +enum ClipKind : ubyte { Inset = 0, Geometric = 1 } +enum ShadowKind : ubyte { Drop = 0 } +enum SurfaceKind : ubyte { VisualSurface = 0, LoadedImageFromUri = 1, LoadedImageFromStream = 2 } +enum EffectKind : ubyte { Composite = 0, GaussianBlur = 1 } +enum EasingKind : ubyte { Linear = 0, CubicBezier = 1, Step = 2 } + +enum AnimationKind : ubyte { + Scalar = 0, + Vector2 = 1, + Vector3 = 2, + Vector4 = 3, + Color = 4, + Boolean = 5, + Path = 6, + Expression = 7, +} + +enum KeyFrameKind : ubyte { Value = 0, Expression = 1 } + +enum CanvasGeometryKind : ubyte { + Combination = 0, + Ellipse = 1, + Group = 2, + Path = 3, + RoundedRectangle = 4, + TransformedGeometry = 5, +} + +// Opcodes of the flattened CanvasPathBuilder command stream. Each opcode +// consumes a fixed number of floats from the operand vector. +enum PathOp : ubyte { + BeginFigure = 0, // 2 operands: x, y + EndFigure = 1, // 1 operand: CanvasFigureLoop as a float + AddLine = 2, // 2 operands: x, y + AddCubicBezier = 3, // 6 operands: cp1.x, cp1.y, cp2.x, cp2.y, end.x, end.y +} + +// Mirrors WinCompData.MetaData.PropertySetValueType. +enum PropertyValueType : ubyte { + None = 0, + Color = 1, + Scalar = 2, + Vector2 = 3, + Vector3 = 4, + Vector4 = 5, +} + +// --------------------------------------------------------------------------- +// Shared structures. +// --------------------------------------------------------------------------- + +// An animation bound to a property of an object. +table Animator { + property: uint; // string index of the animated property name + animation: uint; // index into LottieComposition.animations + controller: uint = 0xFFFFFFFF; // index into LottieComposition.controllers +} + +// State common to every CompositionObject. Omitted when empty. +table CompObj { + comment: uint = 0xFFFFFFFF; // string index + animators: [Animator]; + + // The CompositionPropertySet of the object, if it has any values or + // animations. Index into LottieComposition.property_sets. + properties: uint = 0xFFFFFFFF; +} + +// A named value in a CompositionPropertySet. +table PropertyValue { + name: uint; // string index + type: PropertyValueType; + scalar: float; + vector: Vec4; + color: Color; +} + +// A named reference parameter of a CompositionAnimation. +table ReferenceParameter { + name: uint; // string index + target: uint; // packed object reference +} + +// A named source of a CompositionEffectBrush. +table SourceParameter { + name: uint; // string index + brush: uint; // index into LottieComposition.brushes +} + +table KeyFrame { + progress: float; + easing: uint = 0xFFFFFFFF; // index into LottieComposition.easings + kind: KeyFrameKind; + expression: uint = 0xFFFFFFFF; // string index, for expression key frames + scalar: float; // Scalar and Boolean values + vector: Vec4; // Vector2, Vector3 and Vector4 values + color: Color; + path: uint = 0xFFFFFFFF; // index into LottieComposition.canvas_geometries +} + +// --------------------------------------------------------------------------- +// Node tables. +// --------------------------------------------------------------------------- + +table Visual { + base: CompObj; + kind: VisualKind; + + // Visual. + border_mode: ubyte = null; + center_point: Vec3; + clip: uint = 0xFFFFFFFF; + is_visible: bool = null; + offset: Vec3; + opacity: float = null; + rotation_angle_in_degrees: float = null; + rotation_axis: Vec3; + scale: Vec3; + size: Vec2; + transform_matrix: Mat4x4; + + // ContainerVisual and LayerVisual. + children: [uint]; + + // ShapeVisual. + shapes: [uint]; + view_box: uint = 0xFFFFFFFF; + + // SpriteVisual. + brush: uint = 0xFFFFFFFF; + + // SpriteVisual and LayerVisual. + shadow: uint = 0xFFFFFFFF; +} + +table Shape { + base: CompObj; + kind: ShapeKind; + + // CompositionShape. + center_point: Vec2; + offset: Vec2; + rotation_angle_in_degrees: float = null; + scale: Vec2; + transform_matrix: Mat3x2; + + // CompositionContainerShape. + shapes: [uint]; + + // CompositionSpriteShape. + fill_brush: uint = 0xFFFFFFFF; + stroke_brush: uint = 0xFFFFFFFF; + geometry: uint = 0xFFFFFFFF; + is_stroke_non_scaling: bool = null; + stroke_dash_offset: float = null; + stroke_dash_array: [float]; + stroke_dash_cap: ubyte = null; + stroke_start_cap: ubyte = null; + stroke_end_cap: ubyte = null; + stroke_line_join: ubyte = null; + stroke_miter_limit: float = null; + stroke_thickness: float = null; +} + +table Geometry { + base: CompObj; + kind: GeometryKind; + + // CompositionGeometry. + trim_start: float = null; + trim_end: float = null; + trim_offset: float = null; + + // CompositionPathGeometry. + path: uint = 0xFFFFFFFF; // index into canvas_geometries + + // CompositionRectangleGeometry and CompositionRoundedRectangleGeometry. + offset: Vec2; + size: Vec2; + + // CompositionRoundedRectangleGeometry. + corner_radius: Vec2; + + // CompositionEllipseGeometry. + center: Vec2; + radius: Vec2; +} + +table Brush { + base: CompObj; + kind: BrushKind; + + // CompositionColorBrush. + color: Color; + + // CompositionGradientBrush. + anchor_point: Vec2; + center_point: Vec2; + color_stops: [uint]; + extend_mode: ubyte = null; + interpolation_space: ubyte = null; + mapping_mode: ubyte = null; + offset: Vec2; + rotation_angle_in_degrees: float = null; + scale: Vec2; + transform_matrix: Mat3x2; + + // CompositionLinearGradientBrush. + start_point: Vec2; + end_point: Vec2; + + // CompositionRadialGradientBrush. + ellipse_center: Vec2; + ellipse_radius: Vec2; + gradient_origin_offset: Vec2; + + // CompositionSurfaceBrush. + surface: uint = 0xFFFFFFFF; + + // CompositionMaskBrush. + source: uint = 0xFFFFFFFF; + mask: uint = 0xFFFFFFFF; + + // CompositionEffectBrush. + effect: uint = 0xFFFFFFFF; + source_parameters: [SourceParameter]; +} + +table GradientStop { + base: CompObj; + color: Color; + offset: float; +} + +table ViewBox { + base: CompObj; + size: Vec2; +} + +table Clip { + base: CompObj; + kind: ClipKind; + + // CompositionClip. + center_point: Vec2; + scale: Vec2; + + // InsetClip. + left_inset: float = null; + right_inset: float = null; + top_inset: float = null; + bottom_inset: float = null; + + // CompositionGeometricClip. + geometry: uint = 0xFFFFFFFF; +} + +table Shadow { + base: CompObj; + kind: ShadowKind; + + // DropShadow. + blur_radius: float = null; + color: Color; + mask: uint = 0xFFFFFFFF; + offset: Vec3; + opacity: float = null; + source_policy: ubyte = null; +} + +table Surface { + base: CompObj; + kind: SurfaceKind; + + // CompositionVisualSurface. + source_visual: uint = 0xFFFFFFFF; + source_size: Vec2; + source_offset: Vec2; + + // LoadedImageSurfaceFromUri. + uri: uint = 0xFFFFFFFF; // string index + + // LoadedImageSurfaceFromStream. + bytes: [ubyte]; +} + +table Effect { + base: CompObj; + kind: EffectKind; + + // Names (string indices) of the CompositionEffectSourceParameters. + sources: [uint]; + + // CompositeEffect. + mode: ubyte; // CanvasComposite + + // GaussianBlurEffect. + blur_amount: float; +} + +table Easing { + base: CompObj; + kind: EasingKind; + + // CubicBezierEasingFunction. + control_point_1: Vec2; + control_point_2: Vec2; + + // StepEasingFunction. + step_count: int = null; + initial_step: int = null; + final_step: int = null; + is_initial_step_single_frame: bool = null; + is_final_step_single_frame: bool = null; +} + +table Animation { + base: CompObj; + kind: AnimationKind; + target: uint = 0xFFFFFFFF; // string index + reference_parameters: [ReferenceParameter]; + + // ExpressionAnimation. + expression: uint = 0xFFFFFFFF; // string index + + // KeyFrameAnimation. + duration_ticks: long; + key_frames: [KeyFrame]; + + // ColorKeyFrameAnimation. + interpolation_color_space: ubyte = null; +} + +table PropertySet { + base: CompObj; + + // The object that owns this property set, or 0xFFFFFFFF if the property set + // is standalone (created by Compositor.CreatePropertySet). + owner: uint = 0xFFFFFFFF; // packed object reference + values: [PropertyValue]; +} + +table Controller { + base: CompObj; + + // The object and property that this controller controls. Absent for a + // custom controller. + target_object: uint = 0xFFFFFFFF; // packed object reference + target_property: uint = 0xFFFFFFFF; // string index + is_paused: bool; + is_custom: bool; +} + +// --------------------------------------------------------------------------- +// Metadata. +// --------------------------------------------------------------------------- + +table PropertyBinding { + name: uint; // string index of the binding name + display_name: uint; // string index + actual_type: PropertyValueType; + exposed_type: PropertyValueType; + default_scalar: float; + default_vector: Vec4; + default_color: Color; +} + +table Marker { + name: uint; // string index + progress: float; // start of the marker, 0..1 + duration_progress: float; // duration of the marker, 0..1 +} + +table Metadata { + name: uint = 0xFFFFFFFF; // string index of the composition name + width: float; + height: float; + duration_ticks: long; + frames_per_second: float; + property_bindings: [PropertyBinding]; + markers: [Marker]; + + // The property set that holds the theming properties, or 0xFFFFFFFF. + theming_property_set: uint = 0xFFFFFFFF; // index into property_sets +} + +// --------------------------------------------------------------------------- +// Root. +// --------------------------------------------------------------------------- + +table LottieComposition { + schema_version: ushort; + required_uap_version: ushort; + metadata: Metadata; + + // Index into visuals of the root of the tree. + root_visual: uint = 0xFFFFFFFF; + + strings: [string]; + visuals: [Visual]; + shapes: [Shape]; + geometries: [Geometry]; + canvas_geometries: [CanvasGeometry]; + brushes: [Brush]; + gradient_stops: [GradientStop]; + view_boxes: [ViewBox]; + clips: [Clip]; + shadows: [Shadow]; + surfaces: [Surface]; + effects: [Effect]; + easings: [Easing]; + animations: [Animation]; + property_sets: [PropertySet]; + controllers: [Controller]; + + // Indices into controllers of the custom animation controllers, in the order + // that a host should expose them. + custom_controllers: [uint]; +} + +table CanvasGeometry { + kind: CanvasGeometryKind; + + // Combination. + a: uint = 0xFFFFFFFF; + b: uint = 0xFFFFFFFF; + combine_mode: ubyte; + + // Combination and TransformedGeometry. + matrix: Mat3x2; + + // TransformedGeometry. + source: uint = 0xFFFFFFFF; + + // Group. + geometries: [uint]; + + // Group and Path. + fill_rule: ubyte; // CanvasFilledRegionDetermination + + // Path. + ops: [ubyte]; + operands: [float]; + + // Ellipse (x, y, radius_x, radius_y) and + // RoundedRectangle (x, y, w, h, radius_x, radius_y). + x: float; + y: float; + w: float; + h: float; + radius_x: float; + radius_y: float; +} + +root_type LottieComposition; +file_identifier "LCMP"; +file_extension "lcomp"; diff --git a/source/LottieGen/CommandLineOptions.cs b/source/LottieGen/CommandLineOptions.cs index 125efc44..755438fa 100644 --- a/source/LottieGen/CommandLineOptions.cs +++ b/source/LottieGen/CommandLineOptions.cs @@ -214,6 +214,7 @@ internal static CommandLineOptions ParseCommandLine(string[] args) .AddKeyword(Language.Cx) .AddKeyword(Language.Cppwinrt) .AddKeyword(Language.Cppwinrt, "winrtcpp") + .AddKeyword(Language.Flatbuffer) .AddKeyword(Language.LottieYaml) .AddKeyword(Language.WinCompDgml, "dgml") .AddKeyword(Language.Stats); diff --git a/source/LottieGen/Glob.cs b/source/LottieGen/Glob.cs index 162e1180..e28a958c 100644 --- a/source/LottieGen/Glob.cs +++ b/source/LottieGen/Glob.cs @@ -161,20 +161,22 @@ static Regex WildcardToRegex(string wildcard) if (string.IsNullOrEmpty(directoryPath)) { - directoryPath = @".\"; + directoryPath = $".{Path.DirectorySeparatorChar}"; } - if (directoryPath.EndsWith(":")) + if (directoryPath.Length == 2 && directoryPath[1] == ':' && char.IsLetter(directoryPath[0])) { // The directory path is just a drive letter with no directory. // Ensure it is treated as the current directory on the drive. - directoryPath += @".\"; + // A name that merely ends in ':' is not a drive letter, and on a + // platform where that is a legal directory name it must be left alone. + directoryPath += $".{Path.DirectorySeparatorChar}"; } - // Ensure that we always have a trailing backslash. Callers expect this. - if (!directoryPath.EndsWith(@"\")) + // Ensure that we always have a trailing directory separator. Callers expect this. + if (!directoryPath.EndsWith(Path.DirectorySeparatorChar.ToString())) { - directoryPath += @"\"; + directoryPath += Path.DirectorySeparatorChar; } return (Path.GetFullPath(directoryPath), pattern); diff --git a/source/LottieGen/Language.cs b/source/LottieGen/Language.cs index 3cca53c3..4cad27ac 100644 --- a/source/LottieGen/Language.cs +++ b/source/LottieGen/Language.cs @@ -15,6 +15,7 @@ enum Language CSharp, Cx, Cppwinrt, + Flatbuffer, LottieYaml, WinCompDgml, Stats, diff --git a/source/LottieGen/LottieJsonFileProcessor.cs b/source/LottieGen/LottieJsonFileProcessor.cs index 3d6db369..d21b5726 100644 --- a/source/LottieGen/LottieJsonFileProcessor.cs +++ b/source/LottieGen/LottieJsonFileProcessor.cs @@ -8,6 +8,7 @@ using System.IO; using System.Linq; using System.Text; +using CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer; using CommunityToolkit.WinUI.Lottie.LottieData; using CommunityToolkit.WinUI.Lottie.LottieData.Optimization; using CommunityToolkit.WinUI.Lottie.LottieData.Serialization; @@ -201,6 +202,11 @@ bool TryGenerateCode(LottieComposition lottieComposition) _profiler.OnCodeGenFinished(); break; + case Language.Flatbuffer: + codeGenSucceeded &= TryGenerateFlatbuffer(lottieComposition, $"{outputFileBase}.lcomp"); + _profiler.OnSerializationFinished(); + break; + case Language.LottieYaml: codeGenSucceeded &= TryGenerateLottieYaml(lottieComposition, $"{outputFileBase}-Lottie.yaml"); _profiler.OnSerializationFinished(); @@ -425,6 +431,75 @@ bool TryGenerateLottieYaml(LottieComposition lottieComposition, string outputFil return result; } + bool TryGenerateFlatbuffer(LottieComposition lottieComposition, string outputFilePath) + { + if (!TryEnsureTranslated(lottieComposition)) + { + return false; + } + + var result = true; + var maximumUapVersion = _options.TargetUapVersion ?? uint.MaxValue; + + for (var i = 0; i < _translationResults.Count; i++) + { + var translationResult = _translationResults[i]; + var sourceMetadata = new SourceMetadata(translationResult.SourceMetadata); + var minimumUapVersion = translationResult.MinimumRequiredUapVersion; + var maximumVariantUapVersion = i == 0 + ? maximumUapVersion + : _translationResults[i - 1].MinimumRequiredUapVersion - 1; + var variantPath = _translationResults.Count == 1 + ? outputFilePath + : GetFlatbufferVariantPath( + outputFilePath, + minimumUapVersion, + maximumVariantUapVersion); + + if (!TryWriteBinaryFile( + variantPath, + CompositionSerializer.Serialize( + translationResult.RootVisual!, + checked((ushort)minimumUapVersion), + sourceMetadata.LottieMetadata, + sourceMetadata.PropertyBindings, + (float)lottieComposition.Width, + (float)lottieComposition.Height))) + { + result = false; + continue; + } + + using (_reporter.InfoStream.Lock()) + { + _reporter.WriteInfo( + $"Flatbuffer data for class {_className}, UAP versions " + + (maximumVariantUapVersion == uint.MaxValue + ? $"{minimumUapVersion} and later" + : $"{minimumUapVersion} through {maximumVariantUapVersion}") + + ", written to:"); + _reporter.WriteInfo(InfoType.FilePath, $" {variantPath}"); + } + } + + return result; + } + + static string GetFlatbufferVariantPath( + string outputFilePath, + uint minimumUapVersion, + uint maximumUapVersion) + { + var directory = System.IO.Path.GetDirectoryName(outputFilePath); + var fileName = System.IO.Path.GetFileNameWithoutExtension(outputFilePath); + var extension = System.IO.Path.GetExtension(outputFilePath); + var range = maximumUapVersion == uint.MaxValue + ? $"uap{minimumUapVersion}-plus" + : $"uap{minimumUapVersion}-{maximumUapVersion}"; + + return System.IO.Path.Combine(directory ?? string.Empty, $"{fileName}.{range}{extension}"); + } + bool TryGenerateWincompDgml( LottieComposition lottieComposition, string outputFilePath) @@ -617,6 +692,25 @@ bool TryWriteTextFile(string filePath, Action writer) } } + bool TryWriteBinaryFile(string filePath, byte[] contents) + { + try + { + File.WriteAllBytes(filePath, contents); + return true; + } + catch (Exception e) + { + using (_reporter.ErrorStream.Lock()) + { + _reporter.WriteError($"Failed to write to {filePath}"); + _reporter.WriteError(e.Message); + } + + return false; + } + } + bool TryWriteTextFile(string filePath, string contents) { try @@ -804,7 +898,15 @@ bool TryEnsureTranslated(LottieComposition lottieComposition) var translationResult = LottieToMultiVersionWinCompTranslator.TryTranslateLottieComposition( lottieComposition: lottieComposition, configuration: configuration, - minimumUapVersion: _options.WinUIVersion.Major >= 3 ? uint.MaxValue : _minimumUapVersion); + minimumUapVersion: + _options.WinUIVersion.Major < 3 || + !_options.Languages.Any( + language => + language == Language.CSharp || + language == Language.Cx || + language == Language.Cppwinrt) + ? _minimumUapVersion + : uint.MaxValue); _translationResults = translationResult.TranslationResults; _translationIssues = translationResult.Issues; diff --git a/source/LottieGenExe/Main.cs b/source/LottieGenExe/Main.cs index 4fe843e2..7b2cfe5e 100644 --- a/source/LottieGenExe/Main.cs +++ b/source/LottieGenExe/Main.cs @@ -75,10 +75,18 @@ RunResult Run() _reporter.ErrorStream.WriteLine(_options.ErrorDescription); return RunResult.InvalidUsage; } - else if (_options.WinUIVersion.Major >= 3 && (_options.MinimumUapVersion.HasValue || _options.TargetUapVersion.HasValue)) + else if ( + _options.WinUIVersion.Major >= 3 && + _options.Languages.Any( + language => + language == Language.CSharp || + language == Language.Cx || + language == Language.Cppwinrt) && + (_options.MinimumUapVersion.HasValue || _options.TargetUapVersion.HasValue)) { - // WinUI3 does not permit setting a minimum or target version because WinUI3 implies - // the latest version only. + // WinUI3 source code implies the latest version only. FlatBuffer output is + // projection-neutral, so it can still request a UAP range for consumers + // that select the matching data variant. _reporter.WriteError($"WinUI versions of 3 and above cannot be used with {nameof(_options.MinimumUapVersion)} or {nameof(_options.TargetUapVersion)}."); return RunResult.InvalidUsage; } diff --git a/source/LottieGenExe/Usage.cs b/source/LottieGenExe/Usage.cs index 5d267b10..0cbf7543 100644 --- a/source/LottieGenExe/Usage.cs +++ b/source/LottieGenExe/Usage.cs @@ -24,7 +24,7 @@ internal static string Text OVERVIEW: Generates source code from Lottie files for playing in the AnimatedVisualPlayer. LOTTIEFILE is a Lottie .json file or .lottie file. LOTTIEFILE may contain wildcards. - LANG is one of cs, cppcx, cppwinrt, lottieyaml, dgml, or stats. + LANG is one of cs, cppcx, cppwinrt, flatbuffer, lottieyaml, dgml, or stats. -Language LANG may be specified multiple times. [Other options] diff --git a/source/LottieRuntime/Generated/lottie_comp_generated.h b/source/LottieRuntime/Generated/lottie_comp_generated.h new file mode 100644 index 00000000..b2eba1b4 --- /dev/null +++ b/source/LottieRuntime/Generated/lottie_comp_generated.h @@ -0,0 +1,4301 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_LOTTIECOMP_COMMUNITYTOOLKIT_WINUI_LOTTIE_COMPDATAFLATBUFFER_SCHEMA_H_ +#define FLATBUFFERS_GENERATED_LOTTIECOMP_COMMUNITYTOOLKIT_WINUI_LOTTIE_COMPDATAFLATBUFFER_SCHEMA_H_ + +#include "flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 25 && + FLATBUFFERS_VERSION_MINOR == 2 && + FLATBUFFERS_VERSION_REVISION == 10, + "Non-compatible flatbuffers version included"); + +namespace CommunityToolkit { +namespace WinUI { +namespace Lottie { +namespace CompDataFlatbuffer { +namespace Schema { + +struct Vec2; + +struct Vec3; + +struct Vec4; + +struct Mat3x2; + +struct Mat4x4; + +struct Color; + +struct Animator; +struct AnimatorBuilder; + +struct CompObj; +struct CompObjBuilder; + +struct PropertyValue; +struct PropertyValueBuilder; + +struct ReferenceParameter; +struct ReferenceParameterBuilder; + +struct SourceParameter; +struct SourceParameterBuilder; + +struct KeyFrame; +struct KeyFrameBuilder; + +struct Visual; +struct VisualBuilder; + +struct Shape; +struct ShapeBuilder; + +struct Geometry; +struct GeometryBuilder; + +struct Brush; +struct BrushBuilder; + +struct GradientStop; +struct GradientStopBuilder; + +struct ViewBox; +struct ViewBoxBuilder; + +struct Clip; +struct ClipBuilder; + +struct Shadow; +struct ShadowBuilder; + +struct Surface; +struct SurfaceBuilder; + +struct Effect; +struct EffectBuilder; + +struct Easing; +struct EasingBuilder; + +struct Animation; +struct AnimationBuilder; + +struct PropertySet; +struct PropertySetBuilder; + +struct Controller; +struct ControllerBuilder; + +struct PropertyBinding; +struct PropertyBindingBuilder; + +struct Marker; +struct MarkerBuilder; + +struct Metadata; +struct MetadataBuilder; + +struct LottieComposition; +struct LottieCompositionBuilder; + +struct CanvasGeometry; +struct CanvasGeometryBuilder; + +enum class ObjectCategory : uint8_t { + Visual = 0, + Shape = 1, + Geometry = 2, + Brush = 3, + Animation = 4, + Easing = 5, + PropertySet = 6, + Surface = 7, + Clip = 8, + Controller = 9, + Shadow = 10, + Effect = 11, + GradientStop = 12, + ViewBox = 13, + MIN = Visual, + MAX = ViewBox +}; + +inline const ObjectCategory (&EnumValuesObjectCategory())[14] { + static const ObjectCategory values[] = { + ObjectCategory::Visual, + ObjectCategory::Shape, + ObjectCategory::Geometry, + ObjectCategory::Brush, + ObjectCategory::Animation, + ObjectCategory::Easing, + ObjectCategory::PropertySet, + ObjectCategory::Surface, + ObjectCategory::Clip, + ObjectCategory::Controller, + ObjectCategory::Shadow, + ObjectCategory::Effect, + ObjectCategory::GradientStop, + ObjectCategory::ViewBox + }; + return values; +} + +inline const char * const *EnumNamesObjectCategory() { + static const char * const names[15] = { + "Visual", + "Shape", + "Geometry", + "Brush", + "Animation", + "Easing", + "PropertySet", + "Surface", + "Clip", + "Controller", + "Shadow", + "Effect", + "GradientStop", + "ViewBox", + nullptr + }; + return names; +} + +inline const char *EnumNameObjectCategory(ObjectCategory e) { + if (::flatbuffers::IsOutRange(e, ObjectCategory::Visual, ObjectCategory::ViewBox)) return ""; + const size_t index = static_cast(e); + return EnumNamesObjectCategory()[index]; +} + +enum class VisualKind : uint8_t { + Container = 0, + Sprite = 1, + Shape = 2, + Layer = 3, + MIN = Container, + MAX = Layer +}; + +inline const VisualKind (&EnumValuesVisualKind())[4] { + static const VisualKind values[] = { + VisualKind::Container, + VisualKind::Sprite, + VisualKind::Shape, + VisualKind::Layer + }; + return values; +} + +inline const char * const *EnumNamesVisualKind() { + static const char * const names[5] = { + "Container", + "Sprite", + "Shape", + "Layer", + nullptr + }; + return names; +} + +inline const char *EnumNameVisualKind(VisualKind e) { + if (::flatbuffers::IsOutRange(e, VisualKind::Container, VisualKind::Layer)) return ""; + const size_t index = static_cast(e); + return EnumNamesVisualKind()[index]; +} + +enum class ShapeKind : uint8_t { + Container = 0, + Sprite = 1, + MIN = Container, + MAX = Sprite +}; + +inline const ShapeKind (&EnumValuesShapeKind())[2] { + static const ShapeKind values[] = { + ShapeKind::Container, + ShapeKind::Sprite + }; + return values; +} + +inline const char * const *EnumNamesShapeKind() { + static const char * const names[3] = { + "Container", + "Sprite", + nullptr + }; + return names; +} + +inline const char *EnumNameShapeKind(ShapeKind e) { + if (::flatbuffers::IsOutRange(e, ShapeKind::Container, ShapeKind::Sprite)) return ""; + const size_t index = static_cast(e); + return EnumNamesShapeKind()[index]; +} + +enum class GeometryKind : uint8_t { + Path = 0, + Rectangle = 1, + RoundedRectangle = 2, + Ellipse = 3, + MIN = Path, + MAX = Ellipse +}; + +inline const GeometryKind (&EnumValuesGeometryKind())[4] { + static const GeometryKind values[] = { + GeometryKind::Path, + GeometryKind::Rectangle, + GeometryKind::RoundedRectangle, + GeometryKind::Ellipse + }; + return values; +} + +inline const char * const *EnumNamesGeometryKind() { + static const char * const names[5] = { + "Path", + "Rectangle", + "RoundedRectangle", + "Ellipse", + nullptr + }; + return names; +} + +inline const char *EnumNameGeometryKind(GeometryKind e) { + if (::flatbuffers::IsOutRange(e, GeometryKind::Path, GeometryKind::Ellipse)) return ""; + const size_t index = static_cast(e); + return EnumNamesGeometryKind()[index]; +} + +enum class BrushKind : uint8_t { + Color = 0, + LinearGradient = 1, + RadialGradient = 2, + Surface = 3, + Mask = 4, + Effect = 5, + MIN = Color, + MAX = Effect +}; + +inline const BrushKind (&EnumValuesBrushKind())[6] { + static const BrushKind values[] = { + BrushKind::Color, + BrushKind::LinearGradient, + BrushKind::RadialGradient, + BrushKind::Surface, + BrushKind::Mask, + BrushKind::Effect + }; + return values; +} + +inline const char * const *EnumNamesBrushKind() { + static const char * const names[7] = { + "Color", + "LinearGradient", + "RadialGradient", + "Surface", + "Mask", + "Effect", + nullptr + }; + return names; +} + +inline const char *EnumNameBrushKind(BrushKind e) { + if (::flatbuffers::IsOutRange(e, BrushKind::Color, BrushKind::Effect)) return ""; + const size_t index = static_cast(e); + return EnumNamesBrushKind()[index]; +} + +enum class ClipKind : uint8_t { + Inset = 0, + Geometric = 1, + MIN = Inset, + MAX = Geometric +}; + +inline const ClipKind (&EnumValuesClipKind())[2] { + static const ClipKind values[] = { + ClipKind::Inset, + ClipKind::Geometric + }; + return values; +} + +inline const char * const *EnumNamesClipKind() { + static const char * const names[3] = { + "Inset", + "Geometric", + nullptr + }; + return names; +} + +inline const char *EnumNameClipKind(ClipKind e) { + if (::flatbuffers::IsOutRange(e, ClipKind::Inset, ClipKind::Geometric)) return ""; + const size_t index = static_cast(e); + return EnumNamesClipKind()[index]; +} + +enum class ShadowKind : uint8_t { + Drop = 0, + MIN = Drop, + MAX = Drop +}; + +inline const ShadowKind (&EnumValuesShadowKind())[1] { + static const ShadowKind values[] = { + ShadowKind::Drop + }; + return values; +} + +inline const char * const *EnumNamesShadowKind() { + static const char * const names[2] = { + "Drop", + nullptr + }; + return names; +} + +inline const char *EnumNameShadowKind(ShadowKind e) { + if (::flatbuffers::IsOutRange(e, ShadowKind::Drop, ShadowKind::Drop)) return ""; + const size_t index = static_cast(e); + return EnumNamesShadowKind()[index]; +} + +enum class SurfaceKind : uint8_t { + VisualSurface = 0, + LoadedImageFromUri = 1, + LoadedImageFromStream = 2, + MIN = VisualSurface, + MAX = LoadedImageFromStream +}; + +inline const SurfaceKind (&EnumValuesSurfaceKind())[3] { + static const SurfaceKind values[] = { + SurfaceKind::VisualSurface, + SurfaceKind::LoadedImageFromUri, + SurfaceKind::LoadedImageFromStream + }; + return values; +} + +inline const char * const *EnumNamesSurfaceKind() { + static const char * const names[4] = { + "VisualSurface", + "LoadedImageFromUri", + "LoadedImageFromStream", + nullptr + }; + return names; +} + +inline const char *EnumNameSurfaceKind(SurfaceKind e) { + if (::flatbuffers::IsOutRange(e, SurfaceKind::VisualSurface, SurfaceKind::LoadedImageFromStream)) return ""; + const size_t index = static_cast(e); + return EnumNamesSurfaceKind()[index]; +} + +enum class EffectKind : uint8_t { + Composite = 0, + GaussianBlur = 1, + MIN = Composite, + MAX = GaussianBlur +}; + +inline const EffectKind (&EnumValuesEffectKind())[2] { + static const EffectKind values[] = { + EffectKind::Composite, + EffectKind::GaussianBlur + }; + return values; +} + +inline const char * const *EnumNamesEffectKind() { + static const char * const names[3] = { + "Composite", + "GaussianBlur", + nullptr + }; + return names; +} + +inline const char *EnumNameEffectKind(EffectKind e) { + if (::flatbuffers::IsOutRange(e, EffectKind::Composite, EffectKind::GaussianBlur)) return ""; + const size_t index = static_cast(e); + return EnumNamesEffectKind()[index]; +} + +enum class EasingKind : uint8_t { + Linear = 0, + CubicBezier = 1, + Step = 2, + MIN = Linear, + MAX = Step +}; + +inline const EasingKind (&EnumValuesEasingKind())[3] { + static const EasingKind values[] = { + EasingKind::Linear, + EasingKind::CubicBezier, + EasingKind::Step + }; + return values; +} + +inline const char * const *EnumNamesEasingKind() { + static const char * const names[4] = { + "Linear", + "CubicBezier", + "Step", + nullptr + }; + return names; +} + +inline const char *EnumNameEasingKind(EasingKind e) { + if (::flatbuffers::IsOutRange(e, EasingKind::Linear, EasingKind::Step)) return ""; + const size_t index = static_cast(e); + return EnumNamesEasingKind()[index]; +} + +enum class AnimationKind : uint8_t { + Scalar = 0, + Vector2 = 1, + Vector3 = 2, + Vector4 = 3, + Color = 4, + Boolean = 5, + Path = 6, + Expression = 7, + MIN = Scalar, + MAX = Expression +}; + +inline const AnimationKind (&EnumValuesAnimationKind())[8] { + static const AnimationKind values[] = { + AnimationKind::Scalar, + AnimationKind::Vector2, + AnimationKind::Vector3, + AnimationKind::Vector4, + AnimationKind::Color, + AnimationKind::Boolean, + AnimationKind::Path, + AnimationKind::Expression + }; + return values; +} + +inline const char * const *EnumNamesAnimationKind() { + static const char * const names[9] = { + "Scalar", + "Vector2", + "Vector3", + "Vector4", + "Color", + "Boolean", + "Path", + "Expression", + nullptr + }; + return names; +} + +inline const char *EnumNameAnimationKind(AnimationKind e) { + if (::flatbuffers::IsOutRange(e, AnimationKind::Scalar, AnimationKind::Expression)) return ""; + const size_t index = static_cast(e); + return EnumNamesAnimationKind()[index]; +} + +enum class KeyFrameKind : uint8_t { + Value = 0, + Expression = 1, + MIN = Value, + MAX = Expression +}; + +inline const KeyFrameKind (&EnumValuesKeyFrameKind())[2] { + static const KeyFrameKind values[] = { + KeyFrameKind::Value, + KeyFrameKind::Expression + }; + return values; +} + +inline const char * const *EnumNamesKeyFrameKind() { + static const char * const names[3] = { + "Value", + "Expression", + nullptr + }; + return names; +} + +inline const char *EnumNameKeyFrameKind(KeyFrameKind e) { + if (::flatbuffers::IsOutRange(e, KeyFrameKind::Value, KeyFrameKind::Expression)) return ""; + const size_t index = static_cast(e); + return EnumNamesKeyFrameKind()[index]; +} + +enum class CanvasGeometryKind : uint8_t { + Combination = 0, + Ellipse = 1, + Group = 2, + Path = 3, + RoundedRectangle = 4, + TransformedGeometry = 5, + MIN = Combination, + MAX = TransformedGeometry +}; + +inline const CanvasGeometryKind (&EnumValuesCanvasGeometryKind())[6] { + static const CanvasGeometryKind values[] = { + CanvasGeometryKind::Combination, + CanvasGeometryKind::Ellipse, + CanvasGeometryKind::Group, + CanvasGeometryKind::Path, + CanvasGeometryKind::RoundedRectangle, + CanvasGeometryKind::TransformedGeometry + }; + return values; +} + +inline const char * const *EnumNamesCanvasGeometryKind() { + static const char * const names[7] = { + "Combination", + "Ellipse", + "Group", + "Path", + "RoundedRectangle", + "TransformedGeometry", + nullptr + }; + return names; +} + +inline const char *EnumNameCanvasGeometryKind(CanvasGeometryKind e) { + if (::flatbuffers::IsOutRange(e, CanvasGeometryKind::Combination, CanvasGeometryKind::TransformedGeometry)) return ""; + const size_t index = static_cast(e); + return EnumNamesCanvasGeometryKind()[index]; +} + +enum class PathOp : uint8_t { + BeginFigure = 0, + EndFigure = 1, + AddLine = 2, + AddCubicBezier = 3, + MIN = BeginFigure, + MAX = AddCubicBezier +}; + +inline const PathOp (&EnumValuesPathOp())[4] { + static const PathOp values[] = { + PathOp::BeginFigure, + PathOp::EndFigure, + PathOp::AddLine, + PathOp::AddCubicBezier + }; + return values; +} + +inline const char * const *EnumNamesPathOp() { + static const char * const names[5] = { + "BeginFigure", + "EndFigure", + "AddLine", + "AddCubicBezier", + nullptr + }; + return names; +} + +inline const char *EnumNamePathOp(PathOp e) { + if (::flatbuffers::IsOutRange(e, PathOp::BeginFigure, PathOp::AddCubicBezier)) return ""; + const size_t index = static_cast(e); + return EnumNamesPathOp()[index]; +} + +enum class PropertyValueType : uint8_t { + None = 0, + Color = 1, + Scalar = 2, + Vector2 = 3, + Vector3 = 4, + Vector4 = 5, + MIN = None, + MAX = Vector4 +}; + +inline const PropertyValueType (&EnumValuesPropertyValueType())[6] { + static const PropertyValueType values[] = { + PropertyValueType::None, + PropertyValueType::Color, + PropertyValueType::Scalar, + PropertyValueType::Vector2, + PropertyValueType::Vector3, + PropertyValueType::Vector4 + }; + return values; +} + +inline const char * const *EnumNamesPropertyValueType() { + static const char * const names[7] = { + "None", + "Color", + "Scalar", + "Vector2", + "Vector3", + "Vector4", + nullptr + }; + return names; +} + +inline const char *EnumNamePropertyValueType(PropertyValueType e) { + if (::flatbuffers::IsOutRange(e, PropertyValueType::None, PropertyValueType::Vector4)) return ""; + const size_t index = static_cast(e); + return EnumNamesPropertyValueType()[index]; +} + +FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vec2 FLATBUFFERS_FINAL_CLASS { + private: + float x_; + float y_; + + public: + Vec2() + : x_(0), + y_(0) { + } + Vec2(float _x, float _y) + : x_(::flatbuffers::EndianScalar(_x)), + y_(::flatbuffers::EndianScalar(_y)) { + } + float x() const { + return ::flatbuffers::EndianScalar(x_); + } + float y() const { + return ::flatbuffers::EndianScalar(y_); + } +}; +FLATBUFFERS_STRUCT_END(Vec2, 8); + +FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS { + private: + float x_; + float y_; + float z_; + + public: + Vec3() + : x_(0), + y_(0), + z_(0) { + } + Vec3(float _x, float _y, float _z) + : x_(::flatbuffers::EndianScalar(_x)), + y_(::flatbuffers::EndianScalar(_y)), + z_(::flatbuffers::EndianScalar(_z)) { + } + float x() const { + return ::flatbuffers::EndianScalar(x_); + } + float y() const { + return ::flatbuffers::EndianScalar(y_); + } + float z() const { + return ::flatbuffers::EndianScalar(z_); + } +}; +FLATBUFFERS_STRUCT_END(Vec3, 12); + +FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vec4 FLATBUFFERS_FINAL_CLASS { + private: + float x_; + float y_; + float z_; + float w_; + + public: + Vec4() + : x_(0), + y_(0), + z_(0), + w_(0) { + } + Vec4(float _x, float _y, float _z, float _w) + : x_(::flatbuffers::EndianScalar(_x)), + y_(::flatbuffers::EndianScalar(_y)), + z_(::flatbuffers::EndianScalar(_z)), + w_(::flatbuffers::EndianScalar(_w)) { + } + float x() const { + return ::flatbuffers::EndianScalar(x_); + } + float y() const { + return ::flatbuffers::EndianScalar(y_); + } + float z() const { + return ::flatbuffers::EndianScalar(z_); + } + float w() const { + return ::flatbuffers::EndianScalar(w_); + } +}; +FLATBUFFERS_STRUCT_END(Vec4, 16); + +FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Mat3x2 FLATBUFFERS_FINAL_CLASS { + private: + float m11_; + float m12_; + float m21_; + float m22_; + float m31_; + float m32_; + + public: + Mat3x2() + : m11_(0), + m12_(0), + m21_(0), + m22_(0), + m31_(0), + m32_(0) { + } + Mat3x2(float _m11, float _m12, float _m21, float _m22, float _m31, float _m32) + : m11_(::flatbuffers::EndianScalar(_m11)), + m12_(::flatbuffers::EndianScalar(_m12)), + m21_(::flatbuffers::EndianScalar(_m21)), + m22_(::flatbuffers::EndianScalar(_m22)), + m31_(::flatbuffers::EndianScalar(_m31)), + m32_(::flatbuffers::EndianScalar(_m32)) { + } + float m11() const { + return ::flatbuffers::EndianScalar(m11_); + } + float m12() const { + return ::flatbuffers::EndianScalar(m12_); + } + float m21() const { + return ::flatbuffers::EndianScalar(m21_); + } + float m22() const { + return ::flatbuffers::EndianScalar(m22_); + } + float m31() const { + return ::flatbuffers::EndianScalar(m31_); + } + float m32() const { + return ::flatbuffers::EndianScalar(m32_); + } +}; +FLATBUFFERS_STRUCT_END(Mat3x2, 24); + +FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Mat4x4 FLATBUFFERS_FINAL_CLASS { + private: + float m11_; + float m12_; + float m13_; + float m14_; + float m21_; + float m22_; + float m23_; + float m24_; + float m31_; + float m32_; + float m33_; + float m34_; + float m41_; + float m42_; + float m43_; + float m44_; + + public: + Mat4x4() + : m11_(0), + m12_(0), + m13_(0), + m14_(0), + m21_(0), + m22_(0), + m23_(0), + m24_(0), + m31_(0), + m32_(0), + m33_(0), + m34_(0), + m41_(0), + m42_(0), + m43_(0), + m44_(0) { + } + Mat4x4(float _m11, float _m12, float _m13, float _m14, float _m21, float _m22, float _m23, float _m24, float _m31, float _m32, float _m33, float _m34, float _m41, float _m42, float _m43, float _m44) + : m11_(::flatbuffers::EndianScalar(_m11)), + m12_(::flatbuffers::EndianScalar(_m12)), + m13_(::flatbuffers::EndianScalar(_m13)), + m14_(::flatbuffers::EndianScalar(_m14)), + m21_(::flatbuffers::EndianScalar(_m21)), + m22_(::flatbuffers::EndianScalar(_m22)), + m23_(::flatbuffers::EndianScalar(_m23)), + m24_(::flatbuffers::EndianScalar(_m24)), + m31_(::flatbuffers::EndianScalar(_m31)), + m32_(::flatbuffers::EndianScalar(_m32)), + m33_(::flatbuffers::EndianScalar(_m33)), + m34_(::flatbuffers::EndianScalar(_m34)), + m41_(::flatbuffers::EndianScalar(_m41)), + m42_(::flatbuffers::EndianScalar(_m42)), + m43_(::flatbuffers::EndianScalar(_m43)), + m44_(::flatbuffers::EndianScalar(_m44)) { + } + float m11() const { + return ::flatbuffers::EndianScalar(m11_); + } + float m12() const { + return ::flatbuffers::EndianScalar(m12_); + } + float m13() const { + return ::flatbuffers::EndianScalar(m13_); + } + float m14() const { + return ::flatbuffers::EndianScalar(m14_); + } + float m21() const { + return ::flatbuffers::EndianScalar(m21_); + } + float m22() const { + return ::flatbuffers::EndianScalar(m22_); + } + float m23() const { + return ::flatbuffers::EndianScalar(m23_); + } + float m24() const { + return ::flatbuffers::EndianScalar(m24_); + } + float m31() const { + return ::flatbuffers::EndianScalar(m31_); + } + float m32() const { + return ::flatbuffers::EndianScalar(m32_); + } + float m33() const { + return ::flatbuffers::EndianScalar(m33_); + } + float m34() const { + return ::flatbuffers::EndianScalar(m34_); + } + float m41() const { + return ::flatbuffers::EndianScalar(m41_); + } + float m42() const { + return ::flatbuffers::EndianScalar(m42_); + } + float m43() const { + return ::flatbuffers::EndianScalar(m43_); + } + float m44() const { + return ::flatbuffers::EndianScalar(m44_); + } +}; +FLATBUFFERS_STRUCT_END(Mat4x4, 64); + +FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(1) Color FLATBUFFERS_FINAL_CLASS { + private: + uint8_t a_; + uint8_t r_; + uint8_t g_; + uint8_t b_; + + public: + Color() + : a_(0), + r_(0), + g_(0), + b_(0) { + } + Color(uint8_t _a, uint8_t _r, uint8_t _g, uint8_t _b) + : a_(::flatbuffers::EndianScalar(_a)), + r_(::flatbuffers::EndianScalar(_r)), + g_(::flatbuffers::EndianScalar(_g)), + b_(::flatbuffers::EndianScalar(_b)) { + } + uint8_t a() const { + return ::flatbuffers::EndianScalar(a_); + } + uint8_t r() const { + return ::flatbuffers::EndianScalar(r_); + } + uint8_t g() const { + return ::flatbuffers::EndianScalar(g_); + } + uint8_t b() const { + return ::flatbuffers::EndianScalar(b_); + } +}; +FLATBUFFERS_STRUCT_END(Color, 4); + +struct Animator FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef AnimatorBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_PROPERTY = 4, + VT_ANIMATION = 6, + VT_CONTROLLER = 8 + }; + uint32_t property() const { + return GetField(VT_PROPERTY, 0); + } + uint32_t animation() const { + return GetField(VT_ANIMATION, 0); + } + uint32_t controller() const { + return GetField(VT_CONTROLLER, 4294967295); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_PROPERTY, 4) && + VerifyField(verifier, VT_ANIMATION, 4) && + VerifyField(verifier, VT_CONTROLLER, 4) && + verifier.EndTable(); + } +}; + +struct AnimatorBuilder { + typedef Animator Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_property(uint32_t property) { + fbb_.AddElement(Animator::VT_PROPERTY, property, 0); + } + void add_animation(uint32_t animation) { + fbb_.AddElement(Animator::VT_ANIMATION, animation, 0); + } + void add_controller(uint32_t controller) { + fbb_.AddElement(Animator::VT_CONTROLLER, controller, 4294967295); + } + explicit AnimatorBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateAnimator( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint32_t property = 0, + uint32_t animation = 0, + uint32_t controller = 4294967295) { + AnimatorBuilder builder_(_fbb); + builder_.add_controller(controller); + builder_.add_animation(animation); + builder_.add_property(property); + return builder_.Finish(); +} + +struct CompObj FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef CompObjBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_COMMENT = 4, + VT_ANIMATORS = 6, + VT_PROPERTIES = 8 + }; + uint32_t comment() const { + return GetField(VT_COMMENT, 4294967295); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *animators() const { + return GetPointer> *>(VT_ANIMATORS); + } + uint32_t properties() const { + return GetField(VT_PROPERTIES, 4294967295); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_COMMENT, 4) && + VerifyOffset(verifier, VT_ANIMATORS) && + verifier.VerifyVector(animators()) && + verifier.VerifyVectorOfTables(animators()) && + VerifyField(verifier, VT_PROPERTIES, 4) && + verifier.EndTable(); + } +}; + +struct CompObjBuilder { + typedef CompObj Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_comment(uint32_t comment) { + fbb_.AddElement(CompObj::VT_COMMENT, comment, 4294967295); + } + void add_animators(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> animators) { + fbb_.AddOffset(CompObj::VT_ANIMATORS, animators); + } + void add_properties(uint32_t properties) { + fbb_.AddElement(CompObj::VT_PROPERTIES, properties, 4294967295); + } + explicit CompObjBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateCompObj( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint32_t comment = 4294967295, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> animators = 0, + uint32_t properties = 4294967295) { + CompObjBuilder builder_(_fbb); + builder_.add_properties(properties); + builder_.add_animators(animators); + builder_.add_comment(comment); + return builder_.Finish(); +} + +inline ::flatbuffers::Offset CreateCompObjDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint32_t comment = 4294967295, + const std::vector<::flatbuffers::Offset> *animators = nullptr, + uint32_t properties = 4294967295) { + auto animators__ = animators ? _fbb.CreateVector<::flatbuffers::Offset>(*animators) : 0; + return CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CreateCompObj( + _fbb, + comment, + animators__, + properties); +} + +struct PropertyValue FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef PropertyValueBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_TYPE = 6, + VT_SCALAR = 8, + VT_VECTOR = 10, + VT_COLOR = 12 + }; + uint32_t name() const { + return GetField(VT_NAME, 0); + } + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::PropertyValueType type() const { + return static_cast(GetField(VT_TYPE, 0)); + } + float scalar() const { + return GetField(VT_SCALAR, 0.0f); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec4 *vector() const { + return GetStruct(VT_VECTOR); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Color *color() const { + return GetStruct(VT_COLOR); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_NAME, 4) && + VerifyField(verifier, VT_TYPE, 1) && + VerifyField(verifier, VT_SCALAR, 4) && + VerifyField(verifier, VT_VECTOR, 4) && + VerifyField(verifier, VT_COLOR, 1) && + verifier.EndTable(); + } +}; + +struct PropertyValueBuilder { + typedef PropertyValue Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_name(uint32_t name) { + fbb_.AddElement(PropertyValue::VT_NAME, name, 0); + } + void add_type(CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::PropertyValueType type) { + fbb_.AddElement(PropertyValue::VT_TYPE, static_cast(type), 0); + } + void add_scalar(float scalar) { + fbb_.AddElement(PropertyValue::VT_SCALAR, scalar, 0.0f); + } + void add_vector(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec4 *vector) { + fbb_.AddStruct(PropertyValue::VT_VECTOR, vector); + } + void add_color(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Color *color) { + fbb_.AddStruct(PropertyValue::VT_COLOR, color); + } + explicit PropertyValueBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreatePropertyValue( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint32_t name = 0, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::PropertyValueType type = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::PropertyValueType::None, + float scalar = 0.0f, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec4 *vector = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Color *color = nullptr) { + PropertyValueBuilder builder_(_fbb); + builder_.add_color(color); + builder_.add_vector(vector); + builder_.add_scalar(scalar); + builder_.add_name(name); + builder_.add_type(type); + return builder_.Finish(); +} + +struct ReferenceParameter FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef ReferenceParameterBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_TARGET = 6 + }; + uint32_t name() const { + return GetField(VT_NAME, 0); + } + uint32_t target() const { + return GetField(VT_TARGET, 0); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_NAME, 4) && + VerifyField(verifier, VT_TARGET, 4) && + verifier.EndTable(); + } +}; + +struct ReferenceParameterBuilder { + typedef ReferenceParameter Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_name(uint32_t name) { + fbb_.AddElement(ReferenceParameter::VT_NAME, name, 0); + } + void add_target(uint32_t target) { + fbb_.AddElement(ReferenceParameter::VT_TARGET, target, 0); + } + explicit ReferenceParameterBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateReferenceParameter( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint32_t name = 0, + uint32_t target = 0) { + ReferenceParameterBuilder builder_(_fbb); + builder_.add_target(target); + builder_.add_name(name); + return builder_.Finish(); +} + +struct SourceParameter FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef SourceParameterBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_BRUSH = 6 + }; + uint32_t name() const { + return GetField(VT_NAME, 0); + } + uint32_t brush() const { + return GetField(VT_BRUSH, 0); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_NAME, 4) && + VerifyField(verifier, VT_BRUSH, 4) && + verifier.EndTable(); + } +}; + +struct SourceParameterBuilder { + typedef SourceParameter Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_name(uint32_t name) { + fbb_.AddElement(SourceParameter::VT_NAME, name, 0); + } + void add_brush(uint32_t brush) { + fbb_.AddElement(SourceParameter::VT_BRUSH, brush, 0); + } + explicit SourceParameterBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateSourceParameter( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint32_t name = 0, + uint32_t brush = 0) { + SourceParameterBuilder builder_(_fbb); + builder_.add_brush(brush); + builder_.add_name(name); + return builder_.Finish(); +} + +struct KeyFrame FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef KeyFrameBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_PROGRESS = 4, + VT_EASING = 6, + VT_KIND = 8, + VT_EXPRESSION = 10, + VT_SCALAR = 12, + VT_VECTOR = 14, + VT_COLOR = 16, + VT_PATH = 18 + }; + float progress() const { + return GetField(VT_PROGRESS, 0.0f); + } + uint32_t easing() const { + return GetField(VT_EASING, 4294967295); + } + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::KeyFrameKind kind() const { + return static_cast(GetField(VT_KIND, 0)); + } + uint32_t expression() const { + return GetField(VT_EXPRESSION, 4294967295); + } + float scalar() const { + return GetField(VT_SCALAR, 0.0f); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec4 *vector() const { + return GetStruct(VT_VECTOR); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Color *color() const { + return GetStruct(VT_COLOR); + } + uint32_t path() const { + return GetField(VT_PATH, 4294967295); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_PROGRESS, 4) && + VerifyField(verifier, VT_EASING, 4) && + VerifyField(verifier, VT_KIND, 1) && + VerifyField(verifier, VT_EXPRESSION, 4) && + VerifyField(verifier, VT_SCALAR, 4) && + VerifyField(verifier, VT_VECTOR, 4) && + VerifyField(verifier, VT_COLOR, 1) && + VerifyField(verifier, VT_PATH, 4) && + verifier.EndTable(); + } +}; + +struct KeyFrameBuilder { + typedef KeyFrame Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_progress(float progress) { + fbb_.AddElement(KeyFrame::VT_PROGRESS, progress, 0.0f); + } + void add_easing(uint32_t easing) { + fbb_.AddElement(KeyFrame::VT_EASING, easing, 4294967295); + } + void add_kind(CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::KeyFrameKind kind) { + fbb_.AddElement(KeyFrame::VT_KIND, static_cast(kind), 0); + } + void add_expression(uint32_t expression) { + fbb_.AddElement(KeyFrame::VT_EXPRESSION, expression, 4294967295); + } + void add_scalar(float scalar) { + fbb_.AddElement(KeyFrame::VT_SCALAR, scalar, 0.0f); + } + void add_vector(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec4 *vector) { + fbb_.AddStruct(KeyFrame::VT_VECTOR, vector); + } + void add_color(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Color *color) { + fbb_.AddStruct(KeyFrame::VT_COLOR, color); + } + void add_path(uint32_t path) { + fbb_.AddElement(KeyFrame::VT_PATH, path, 4294967295); + } + explicit KeyFrameBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateKeyFrame( + ::flatbuffers::FlatBufferBuilder &_fbb, + float progress = 0.0f, + uint32_t easing = 4294967295, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::KeyFrameKind kind = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::KeyFrameKind::Value, + uint32_t expression = 4294967295, + float scalar = 0.0f, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec4 *vector = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Color *color = nullptr, + uint32_t path = 4294967295) { + KeyFrameBuilder builder_(_fbb); + builder_.add_path(path); + builder_.add_color(color); + builder_.add_vector(vector); + builder_.add_scalar(scalar); + builder_.add_expression(expression); + builder_.add_easing(easing); + builder_.add_progress(progress); + builder_.add_kind(kind); + return builder_.Finish(); +} + +struct Visual FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef VisualBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BASE = 4, + VT_KIND = 6, + VT_BORDER_MODE = 8, + VT_CENTER_POINT = 10, + VT_CLIP = 12, + VT_IS_VISIBLE = 14, + VT_OFFSET = 16, + VT_OPACITY = 18, + VT_ROTATION_ANGLE_IN_DEGREES = 20, + VT_ROTATION_AXIS = 22, + VT_SCALE = 24, + VT_SIZE = 26, + VT_TRANSFORM_MATRIX = 28, + VT_CHILDREN = 30, + VT_SHAPES = 32, + VT_VIEW_BOX = 34, + VT_BRUSH = 36, + VT_SHADOW = 38 + }; + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CompObj *base() const { + return GetPointer(VT_BASE); + } + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::VisualKind kind() const { + return static_cast(GetField(VT_KIND, 0)); + } + ::flatbuffers::Optional border_mode() const { + return GetOptional(VT_BORDER_MODE); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec3 *center_point() const { + return GetStruct(VT_CENTER_POINT); + } + uint32_t clip() const { + return GetField(VT_CLIP, 4294967295); + } + ::flatbuffers::Optional is_visible() const { + return GetOptional(VT_IS_VISIBLE); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec3 *offset() const { + return GetStruct(VT_OFFSET); + } + ::flatbuffers::Optional opacity() const { + return GetOptional(VT_OPACITY); + } + ::flatbuffers::Optional rotation_angle_in_degrees() const { + return GetOptional(VT_ROTATION_ANGLE_IN_DEGREES); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec3 *rotation_axis() const { + return GetStruct(VT_ROTATION_AXIS); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec3 *scale() const { + return GetStruct(VT_SCALE); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *size() const { + return GetStruct(VT_SIZE); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Mat4x4 *transform_matrix() const { + return GetStruct(VT_TRANSFORM_MATRIX); + } + const ::flatbuffers::Vector *children() const { + return GetPointer *>(VT_CHILDREN); + } + const ::flatbuffers::Vector *shapes() const { + return GetPointer *>(VT_SHAPES); + } + uint32_t view_box() const { + return GetField(VT_VIEW_BOX, 4294967295); + } + uint32_t brush() const { + return GetField(VT_BRUSH, 4294967295); + } + uint32_t shadow() const { + return GetField(VT_SHADOW, 4294967295); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_BASE) && + verifier.VerifyTable(base()) && + VerifyField(verifier, VT_KIND, 1) && + VerifyField(verifier, VT_BORDER_MODE, 1) && + VerifyField(verifier, VT_CENTER_POINT, 4) && + VerifyField(verifier, VT_CLIP, 4) && + VerifyField(verifier, VT_IS_VISIBLE, 1) && + VerifyField(verifier, VT_OFFSET, 4) && + VerifyField(verifier, VT_OPACITY, 4) && + VerifyField(verifier, VT_ROTATION_ANGLE_IN_DEGREES, 4) && + VerifyField(verifier, VT_ROTATION_AXIS, 4) && + VerifyField(verifier, VT_SCALE, 4) && + VerifyField(verifier, VT_SIZE, 4) && + VerifyField(verifier, VT_TRANSFORM_MATRIX, 4) && + VerifyOffset(verifier, VT_CHILDREN) && + verifier.VerifyVector(children()) && + VerifyOffset(verifier, VT_SHAPES) && + verifier.VerifyVector(shapes()) && + VerifyField(verifier, VT_VIEW_BOX, 4) && + VerifyField(verifier, VT_BRUSH, 4) && + VerifyField(verifier, VT_SHADOW, 4) && + verifier.EndTable(); + } +}; + +struct VisualBuilder { + typedef Visual Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_base(::flatbuffers::Offset base) { + fbb_.AddOffset(Visual::VT_BASE, base); + } + void add_kind(CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::VisualKind kind) { + fbb_.AddElement(Visual::VT_KIND, static_cast(kind), 0); + } + void add_border_mode(uint8_t border_mode) { + fbb_.AddElement(Visual::VT_BORDER_MODE, border_mode); + } + void add_center_point(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec3 *center_point) { + fbb_.AddStruct(Visual::VT_CENTER_POINT, center_point); + } + void add_clip(uint32_t clip) { + fbb_.AddElement(Visual::VT_CLIP, clip, 4294967295); + } + void add_is_visible(bool is_visible) { + fbb_.AddElement(Visual::VT_IS_VISIBLE, static_cast(is_visible)); + } + void add_offset(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec3 *offset) { + fbb_.AddStruct(Visual::VT_OFFSET, offset); + } + void add_opacity(float opacity) { + fbb_.AddElement(Visual::VT_OPACITY, opacity); + } + void add_rotation_angle_in_degrees(float rotation_angle_in_degrees) { + fbb_.AddElement(Visual::VT_ROTATION_ANGLE_IN_DEGREES, rotation_angle_in_degrees); + } + void add_rotation_axis(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec3 *rotation_axis) { + fbb_.AddStruct(Visual::VT_ROTATION_AXIS, rotation_axis); + } + void add_scale(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec3 *scale) { + fbb_.AddStruct(Visual::VT_SCALE, scale); + } + void add_size(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *size) { + fbb_.AddStruct(Visual::VT_SIZE, size); + } + void add_transform_matrix(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Mat4x4 *transform_matrix) { + fbb_.AddStruct(Visual::VT_TRANSFORM_MATRIX, transform_matrix); + } + void add_children(::flatbuffers::Offset<::flatbuffers::Vector> children) { + fbb_.AddOffset(Visual::VT_CHILDREN, children); + } + void add_shapes(::flatbuffers::Offset<::flatbuffers::Vector> shapes) { + fbb_.AddOffset(Visual::VT_SHAPES, shapes); + } + void add_view_box(uint32_t view_box) { + fbb_.AddElement(Visual::VT_VIEW_BOX, view_box, 4294967295); + } + void add_brush(uint32_t brush) { + fbb_.AddElement(Visual::VT_BRUSH, brush, 4294967295); + } + void add_shadow(uint32_t shadow) { + fbb_.AddElement(Visual::VT_SHADOW, shadow, 4294967295); + } + explicit VisualBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateVisual( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset base = 0, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::VisualKind kind = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::VisualKind::Container, + ::flatbuffers::Optional border_mode = ::flatbuffers::nullopt, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec3 *center_point = nullptr, + uint32_t clip = 4294967295, + ::flatbuffers::Optional is_visible = ::flatbuffers::nullopt, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec3 *offset = nullptr, + ::flatbuffers::Optional opacity = ::flatbuffers::nullopt, + ::flatbuffers::Optional rotation_angle_in_degrees = ::flatbuffers::nullopt, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec3 *rotation_axis = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec3 *scale = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *size = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Mat4x4 *transform_matrix = nullptr, + ::flatbuffers::Offset<::flatbuffers::Vector> children = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> shapes = 0, + uint32_t view_box = 4294967295, + uint32_t brush = 4294967295, + uint32_t shadow = 4294967295) { + VisualBuilder builder_(_fbb); + builder_.add_shadow(shadow); + builder_.add_brush(brush); + builder_.add_view_box(view_box); + builder_.add_shapes(shapes); + builder_.add_children(children); + builder_.add_transform_matrix(transform_matrix); + builder_.add_size(size); + builder_.add_scale(scale); + builder_.add_rotation_axis(rotation_axis); + if(rotation_angle_in_degrees) { builder_.add_rotation_angle_in_degrees(*rotation_angle_in_degrees); } + if(opacity) { builder_.add_opacity(*opacity); } + builder_.add_offset(offset); + builder_.add_clip(clip); + builder_.add_center_point(center_point); + builder_.add_base(base); + if(is_visible) { builder_.add_is_visible(*is_visible); } + if(border_mode) { builder_.add_border_mode(*border_mode); } + builder_.add_kind(kind); + return builder_.Finish(); +} + +inline ::flatbuffers::Offset CreateVisualDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset base = 0, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::VisualKind kind = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::VisualKind::Container, + ::flatbuffers::Optional border_mode = ::flatbuffers::nullopt, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec3 *center_point = nullptr, + uint32_t clip = 4294967295, + ::flatbuffers::Optional is_visible = ::flatbuffers::nullopt, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec3 *offset = nullptr, + ::flatbuffers::Optional opacity = ::flatbuffers::nullopt, + ::flatbuffers::Optional rotation_angle_in_degrees = ::flatbuffers::nullopt, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec3 *rotation_axis = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec3 *scale = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *size = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Mat4x4 *transform_matrix = nullptr, + const std::vector *children = nullptr, + const std::vector *shapes = nullptr, + uint32_t view_box = 4294967295, + uint32_t brush = 4294967295, + uint32_t shadow = 4294967295) { + auto children__ = children ? _fbb.CreateVector(*children) : 0; + auto shapes__ = shapes ? _fbb.CreateVector(*shapes) : 0; + return CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CreateVisual( + _fbb, + base, + kind, + border_mode, + center_point, + clip, + is_visible, + offset, + opacity, + rotation_angle_in_degrees, + rotation_axis, + scale, + size, + transform_matrix, + children__, + shapes__, + view_box, + brush, + shadow); +} + +struct Shape FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef ShapeBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BASE = 4, + VT_KIND = 6, + VT_CENTER_POINT = 8, + VT_OFFSET = 10, + VT_ROTATION_ANGLE_IN_DEGREES = 12, + VT_SCALE = 14, + VT_TRANSFORM_MATRIX = 16, + VT_SHAPES = 18, + VT_FILL_BRUSH = 20, + VT_STROKE_BRUSH = 22, + VT_GEOMETRY = 24, + VT_IS_STROKE_NON_SCALING = 26, + VT_STROKE_DASH_OFFSET = 28, + VT_STROKE_DASH_ARRAY = 30, + VT_STROKE_DASH_CAP = 32, + VT_STROKE_START_CAP = 34, + VT_STROKE_END_CAP = 36, + VT_STROKE_LINE_JOIN = 38, + VT_STROKE_MITER_LIMIT = 40, + VT_STROKE_THICKNESS = 42 + }; + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CompObj *base() const { + return GetPointer(VT_BASE); + } + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::ShapeKind kind() const { + return static_cast(GetField(VT_KIND, 0)); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *center_point() const { + return GetStruct(VT_CENTER_POINT); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *offset() const { + return GetStruct(VT_OFFSET); + } + ::flatbuffers::Optional rotation_angle_in_degrees() const { + return GetOptional(VT_ROTATION_ANGLE_IN_DEGREES); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *scale() const { + return GetStruct(VT_SCALE); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Mat3x2 *transform_matrix() const { + return GetStruct(VT_TRANSFORM_MATRIX); + } + const ::flatbuffers::Vector *shapes() const { + return GetPointer *>(VT_SHAPES); + } + uint32_t fill_brush() const { + return GetField(VT_FILL_BRUSH, 4294967295); + } + uint32_t stroke_brush() const { + return GetField(VT_STROKE_BRUSH, 4294967295); + } + uint32_t geometry() const { + return GetField(VT_GEOMETRY, 4294967295); + } + ::flatbuffers::Optional is_stroke_non_scaling() const { + return GetOptional(VT_IS_STROKE_NON_SCALING); + } + ::flatbuffers::Optional stroke_dash_offset() const { + return GetOptional(VT_STROKE_DASH_OFFSET); + } + const ::flatbuffers::Vector *stroke_dash_array() const { + return GetPointer *>(VT_STROKE_DASH_ARRAY); + } + ::flatbuffers::Optional stroke_dash_cap() const { + return GetOptional(VT_STROKE_DASH_CAP); + } + ::flatbuffers::Optional stroke_start_cap() const { + return GetOptional(VT_STROKE_START_CAP); + } + ::flatbuffers::Optional stroke_end_cap() const { + return GetOptional(VT_STROKE_END_CAP); + } + ::flatbuffers::Optional stroke_line_join() const { + return GetOptional(VT_STROKE_LINE_JOIN); + } + ::flatbuffers::Optional stroke_miter_limit() const { + return GetOptional(VT_STROKE_MITER_LIMIT); + } + ::flatbuffers::Optional stroke_thickness() const { + return GetOptional(VT_STROKE_THICKNESS); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_BASE) && + verifier.VerifyTable(base()) && + VerifyField(verifier, VT_KIND, 1) && + VerifyField(verifier, VT_CENTER_POINT, 4) && + VerifyField(verifier, VT_OFFSET, 4) && + VerifyField(verifier, VT_ROTATION_ANGLE_IN_DEGREES, 4) && + VerifyField(verifier, VT_SCALE, 4) && + VerifyField(verifier, VT_TRANSFORM_MATRIX, 4) && + VerifyOffset(verifier, VT_SHAPES) && + verifier.VerifyVector(shapes()) && + VerifyField(verifier, VT_FILL_BRUSH, 4) && + VerifyField(verifier, VT_STROKE_BRUSH, 4) && + VerifyField(verifier, VT_GEOMETRY, 4) && + VerifyField(verifier, VT_IS_STROKE_NON_SCALING, 1) && + VerifyField(verifier, VT_STROKE_DASH_OFFSET, 4) && + VerifyOffset(verifier, VT_STROKE_DASH_ARRAY) && + verifier.VerifyVector(stroke_dash_array()) && + VerifyField(verifier, VT_STROKE_DASH_CAP, 1) && + VerifyField(verifier, VT_STROKE_START_CAP, 1) && + VerifyField(verifier, VT_STROKE_END_CAP, 1) && + VerifyField(verifier, VT_STROKE_LINE_JOIN, 1) && + VerifyField(verifier, VT_STROKE_MITER_LIMIT, 4) && + VerifyField(verifier, VT_STROKE_THICKNESS, 4) && + verifier.EndTable(); + } +}; + +struct ShapeBuilder { + typedef Shape Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_base(::flatbuffers::Offset base) { + fbb_.AddOffset(Shape::VT_BASE, base); + } + void add_kind(CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::ShapeKind kind) { + fbb_.AddElement(Shape::VT_KIND, static_cast(kind), 0); + } + void add_center_point(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *center_point) { + fbb_.AddStruct(Shape::VT_CENTER_POINT, center_point); + } + void add_offset(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *offset) { + fbb_.AddStruct(Shape::VT_OFFSET, offset); + } + void add_rotation_angle_in_degrees(float rotation_angle_in_degrees) { + fbb_.AddElement(Shape::VT_ROTATION_ANGLE_IN_DEGREES, rotation_angle_in_degrees); + } + void add_scale(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *scale) { + fbb_.AddStruct(Shape::VT_SCALE, scale); + } + void add_transform_matrix(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Mat3x2 *transform_matrix) { + fbb_.AddStruct(Shape::VT_TRANSFORM_MATRIX, transform_matrix); + } + void add_shapes(::flatbuffers::Offset<::flatbuffers::Vector> shapes) { + fbb_.AddOffset(Shape::VT_SHAPES, shapes); + } + void add_fill_brush(uint32_t fill_brush) { + fbb_.AddElement(Shape::VT_FILL_BRUSH, fill_brush, 4294967295); + } + void add_stroke_brush(uint32_t stroke_brush) { + fbb_.AddElement(Shape::VT_STROKE_BRUSH, stroke_brush, 4294967295); + } + void add_geometry(uint32_t geometry) { + fbb_.AddElement(Shape::VT_GEOMETRY, geometry, 4294967295); + } + void add_is_stroke_non_scaling(bool is_stroke_non_scaling) { + fbb_.AddElement(Shape::VT_IS_STROKE_NON_SCALING, static_cast(is_stroke_non_scaling)); + } + void add_stroke_dash_offset(float stroke_dash_offset) { + fbb_.AddElement(Shape::VT_STROKE_DASH_OFFSET, stroke_dash_offset); + } + void add_stroke_dash_array(::flatbuffers::Offset<::flatbuffers::Vector> stroke_dash_array) { + fbb_.AddOffset(Shape::VT_STROKE_DASH_ARRAY, stroke_dash_array); + } + void add_stroke_dash_cap(uint8_t stroke_dash_cap) { + fbb_.AddElement(Shape::VT_STROKE_DASH_CAP, stroke_dash_cap); + } + void add_stroke_start_cap(uint8_t stroke_start_cap) { + fbb_.AddElement(Shape::VT_STROKE_START_CAP, stroke_start_cap); + } + void add_stroke_end_cap(uint8_t stroke_end_cap) { + fbb_.AddElement(Shape::VT_STROKE_END_CAP, stroke_end_cap); + } + void add_stroke_line_join(uint8_t stroke_line_join) { + fbb_.AddElement(Shape::VT_STROKE_LINE_JOIN, stroke_line_join); + } + void add_stroke_miter_limit(float stroke_miter_limit) { + fbb_.AddElement(Shape::VT_STROKE_MITER_LIMIT, stroke_miter_limit); + } + void add_stroke_thickness(float stroke_thickness) { + fbb_.AddElement(Shape::VT_STROKE_THICKNESS, stroke_thickness); + } + explicit ShapeBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateShape( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset base = 0, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::ShapeKind kind = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::ShapeKind::Container, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *center_point = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *offset = nullptr, + ::flatbuffers::Optional rotation_angle_in_degrees = ::flatbuffers::nullopt, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *scale = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Mat3x2 *transform_matrix = nullptr, + ::flatbuffers::Offset<::flatbuffers::Vector> shapes = 0, + uint32_t fill_brush = 4294967295, + uint32_t stroke_brush = 4294967295, + uint32_t geometry = 4294967295, + ::flatbuffers::Optional is_stroke_non_scaling = ::flatbuffers::nullopt, + ::flatbuffers::Optional stroke_dash_offset = ::flatbuffers::nullopt, + ::flatbuffers::Offset<::flatbuffers::Vector> stroke_dash_array = 0, + ::flatbuffers::Optional stroke_dash_cap = ::flatbuffers::nullopt, + ::flatbuffers::Optional stroke_start_cap = ::flatbuffers::nullopt, + ::flatbuffers::Optional stroke_end_cap = ::flatbuffers::nullopt, + ::flatbuffers::Optional stroke_line_join = ::flatbuffers::nullopt, + ::flatbuffers::Optional stroke_miter_limit = ::flatbuffers::nullopt, + ::flatbuffers::Optional stroke_thickness = ::flatbuffers::nullopt) { + ShapeBuilder builder_(_fbb); + if(stroke_thickness) { builder_.add_stroke_thickness(*stroke_thickness); } + if(stroke_miter_limit) { builder_.add_stroke_miter_limit(*stroke_miter_limit); } + builder_.add_stroke_dash_array(stroke_dash_array); + if(stroke_dash_offset) { builder_.add_stroke_dash_offset(*stroke_dash_offset); } + builder_.add_geometry(geometry); + builder_.add_stroke_brush(stroke_brush); + builder_.add_fill_brush(fill_brush); + builder_.add_shapes(shapes); + builder_.add_transform_matrix(transform_matrix); + builder_.add_scale(scale); + if(rotation_angle_in_degrees) { builder_.add_rotation_angle_in_degrees(*rotation_angle_in_degrees); } + builder_.add_offset(offset); + builder_.add_center_point(center_point); + builder_.add_base(base); + if(stroke_line_join) { builder_.add_stroke_line_join(*stroke_line_join); } + if(stroke_end_cap) { builder_.add_stroke_end_cap(*stroke_end_cap); } + if(stroke_start_cap) { builder_.add_stroke_start_cap(*stroke_start_cap); } + if(stroke_dash_cap) { builder_.add_stroke_dash_cap(*stroke_dash_cap); } + if(is_stroke_non_scaling) { builder_.add_is_stroke_non_scaling(*is_stroke_non_scaling); } + builder_.add_kind(kind); + return builder_.Finish(); +} + +inline ::flatbuffers::Offset CreateShapeDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset base = 0, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::ShapeKind kind = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::ShapeKind::Container, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *center_point = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *offset = nullptr, + ::flatbuffers::Optional rotation_angle_in_degrees = ::flatbuffers::nullopt, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *scale = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Mat3x2 *transform_matrix = nullptr, + const std::vector *shapes = nullptr, + uint32_t fill_brush = 4294967295, + uint32_t stroke_brush = 4294967295, + uint32_t geometry = 4294967295, + ::flatbuffers::Optional is_stroke_non_scaling = ::flatbuffers::nullopt, + ::flatbuffers::Optional stroke_dash_offset = ::flatbuffers::nullopt, + const std::vector *stroke_dash_array = nullptr, + ::flatbuffers::Optional stroke_dash_cap = ::flatbuffers::nullopt, + ::flatbuffers::Optional stroke_start_cap = ::flatbuffers::nullopt, + ::flatbuffers::Optional stroke_end_cap = ::flatbuffers::nullopt, + ::flatbuffers::Optional stroke_line_join = ::flatbuffers::nullopt, + ::flatbuffers::Optional stroke_miter_limit = ::flatbuffers::nullopt, + ::flatbuffers::Optional stroke_thickness = ::flatbuffers::nullopt) { + auto shapes__ = shapes ? _fbb.CreateVector(*shapes) : 0; + auto stroke_dash_array__ = stroke_dash_array ? _fbb.CreateVector(*stroke_dash_array) : 0; + return CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CreateShape( + _fbb, + base, + kind, + center_point, + offset, + rotation_angle_in_degrees, + scale, + transform_matrix, + shapes__, + fill_brush, + stroke_brush, + geometry, + is_stroke_non_scaling, + stroke_dash_offset, + stroke_dash_array__, + stroke_dash_cap, + stroke_start_cap, + stroke_end_cap, + stroke_line_join, + stroke_miter_limit, + stroke_thickness); +} + +struct Geometry FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef GeometryBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BASE = 4, + VT_KIND = 6, + VT_TRIM_START = 8, + VT_TRIM_END = 10, + VT_TRIM_OFFSET = 12, + VT_PATH = 14, + VT_OFFSET = 16, + VT_SIZE = 18, + VT_CORNER_RADIUS = 20, + VT_CENTER = 22, + VT_RADIUS = 24 + }; + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CompObj *base() const { + return GetPointer(VT_BASE); + } + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::GeometryKind kind() const { + return static_cast(GetField(VT_KIND, 0)); + } + ::flatbuffers::Optional trim_start() const { + return GetOptional(VT_TRIM_START); + } + ::flatbuffers::Optional trim_end() const { + return GetOptional(VT_TRIM_END); + } + ::flatbuffers::Optional trim_offset() const { + return GetOptional(VT_TRIM_OFFSET); + } + uint32_t path() const { + return GetField(VT_PATH, 4294967295); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *offset() const { + return GetStruct(VT_OFFSET); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *size() const { + return GetStruct(VT_SIZE); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *corner_radius() const { + return GetStruct(VT_CORNER_RADIUS); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *center() const { + return GetStruct(VT_CENTER); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *radius() const { + return GetStruct(VT_RADIUS); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_BASE) && + verifier.VerifyTable(base()) && + VerifyField(verifier, VT_KIND, 1) && + VerifyField(verifier, VT_TRIM_START, 4) && + VerifyField(verifier, VT_TRIM_END, 4) && + VerifyField(verifier, VT_TRIM_OFFSET, 4) && + VerifyField(verifier, VT_PATH, 4) && + VerifyField(verifier, VT_OFFSET, 4) && + VerifyField(verifier, VT_SIZE, 4) && + VerifyField(verifier, VT_CORNER_RADIUS, 4) && + VerifyField(verifier, VT_CENTER, 4) && + VerifyField(verifier, VT_RADIUS, 4) && + verifier.EndTable(); + } +}; + +struct GeometryBuilder { + typedef Geometry Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_base(::flatbuffers::Offset base) { + fbb_.AddOffset(Geometry::VT_BASE, base); + } + void add_kind(CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::GeometryKind kind) { + fbb_.AddElement(Geometry::VT_KIND, static_cast(kind), 0); + } + void add_trim_start(float trim_start) { + fbb_.AddElement(Geometry::VT_TRIM_START, trim_start); + } + void add_trim_end(float trim_end) { + fbb_.AddElement(Geometry::VT_TRIM_END, trim_end); + } + void add_trim_offset(float trim_offset) { + fbb_.AddElement(Geometry::VT_TRIM_OFFSET, trim_offset); + } + void add_path(uint32_t path) { + fbb_.AddElement(Geometry::VT_PATH, path, 4294967295); + } + void add_offset(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *offset) { + fbb_.AddStruct(Geometry::VT_OFFSET, offset); + } + void add_size(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *size) { + fbb_.AddStruct(Geometry::VT_SIZE, size); + } + void add_corner_radius(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *corner_radius) { + fbb_.AddStruct(Geometry::VT_CORNER_RADIUS, corner_radius); + } + void add_center(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *center) { + fbb_.AddStruct(Geometry::VT_CENTER, center); + } + void add_radius(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *radius) { + fbb_.AddStruct(Geometry::VT_RADIUS, radius); + } + explicit GeometryBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateGeometry( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset base = 0, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::GeometryKind kind = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::GeometryKind::Path, + ::flatbuffers::Optional trim_start = ::flatbuffers::nullopt, + ::flatbuffers::Optional trim_end = ::flatbuffers::nullopt, + ::flatbuffers::Optional trim_offset = ::flatbuffers::nullopt, + uint32_t path = 4294967295, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *offset = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *size = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *corner_radius = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *center = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *radius = nullptr) { + GeometryBuilder builder_(_fbb); + builder_.add_radius(radius); + builder_.add_center(center); + builder_.add_corner_radius(corner_radius); + builder_.add_size(size); + builder_.add_offset(offset); + builder_.add_path(path); + if(trim_offset) { builder_.add_trim_offset(*trim_offset); } + if(trim_end) { builder_.add_trim_end(*trim_end); } + if(trim_start) { builder_.add_trim_start(*trim_start); } + builder_.add_base(base); + builder_.add_kind(kind); + return builder_.Finish(); +} + +struct Brush FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef BrushBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BASE = 4, + VT_KIND = 6, + VT_COLOR = 8, + VT_ANCHOR_POINT = 10, + VT_CENTER_POINT = 12, + VT_COLOR_STOPS = 14, + VT_EXTEND_MODE = 16, + VT_INTERPOLATION_SPACE = 18, + VT_MAPPING_MODE = 20, + VT_OFFSET = 22, + VT_ROTATION_ANGLE_IN_DEGREES = 24, + VT_SCALE = 26, + VT_TRANSFORM_MATRIX = 28, + VT_START_POINT = 30, + VT_END_POINT = 32, + VT_ELLIPSE_CENTER = 34, + VT_ELLIPSE_RADIUS = 36, + VT_GRADIENT_ORIGIN_OFFSET = 38, + VT_SURFACE = 40, + VT_SOURCE = 42, + VT_MASK = 44, + VT_EFFECT = 46, + VT_SOURCE_PARAMETERS = 48 + }; + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CompObj *base() const { + return GetPointer(VT_BASE); + } + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::BrushKind kind() const { + return static_cast(GetField(VT_KIND, 0)); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Color *color() const { + return GetStruct(VT_COLOR); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *anchor_point() const { + return GetStruct(VT_ANCHOR_POINT); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *center_point() const { + return GetStruct(VT_CENTER_POINT); + } + const ::flatbuffers::Vector *color_stops() const { + return GetPointer *>(VT_COLOR_STOPS); + } + ::flatbuffers::Optional extend_mode() const { + return GetOptional(VT_EXTEND_MODE); + } + ::flatbuffers::Optional interpolation_space() const { + return GetOptional(VT_INTERPOLATION_SPACE); + } + ::flatbuffers::Optional mapping_mode() const { + return GetOptional(VT_MAPPING_MODE); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *offset() const { + return GetStruct(VT_OFFSET); + } + ::flatbuffers::Optional rotation_angle_in_degrees() const { + return GetOptional(VT_ROTATION_ANGLE_IN_DEGREES); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *scale() const { + return GetStruct(VT_SCALE); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Mat3x2 *transform_matrix() const { + return GetStruct(VT_TRANSFORM_MATRIX); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *start_point() const { + return GetStruct(VT_START_POINT); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *end_point() const { + return GetStruct(VT_END_POINT); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *ellipse_center() const { + return GetStruct(VT_ELLIPSE_CENTER); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *ellipse_radius() const { + return GetStruct(VT_ELLIPSE_RADIUS); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *gradient_origin_offset() const { + return GetStruct(VT_GRADIENT_ORIGIN_OFFSET); + } + uint32_t surface() const { + return GetField(VT_SURFACE, 4294967295); + } + uint32_t source() const { + return GetField(VT_SOURCE, 4294967295); + } + uint32_t mask() const { + return GetField(VT_MASK, 4294967295); + } + uint32_t effect() const { + return GetField(VT_EFFECT, 4294967295); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *source_parameters() const { + return GetPointer> *>(VT_SOURCE_PARAMETERS); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_BASE) && + verifier.VerifyTable(base()) && + VerifyField(verifier, VT_KIND, 1) && + VerifyField(verifier, VT_COLOR, 1) && + VerifyField(verifier, VT_ANCHOR_POINT, 4) && + VerifyField(verifier, VT_CENTER_POINT, 4) && + VerifyOffset(verifier, VT_COLOR_STOPS) && + verifier.VerifyVector(color_stops()) && + VerifyField(verifier, VT_EXTEND_MODE, 1) && + VerifyField(verifier, VT_INTERPOLATION_SPACE, 1) && + VerifyField(verifier, VT_MAPPING_MODE, 1) && + VerifyField(verifier, VT_OFFSET, 4) && + VerifyField(verifier, VT_ROTATION_ANGLE_IN_DEGREES, 4) && + VerifyField(verifier, VT_SCALE, 4) && + VerifyField(verifier, VT_TRANSFORM_MATRIX, 4) && + VerifyField(verifier, VT_START_POINT, 4) && + VerifyField(verifier, VT_END_POINT, 4) && + VerifyField(verifier, VT_ELLIPSE_CENTER, 4) && + VerifyField(verifier, VT_ELLIPSE_RADIUS, 4) && + VerifyField(verifier, VT_GRADIENT_ORIGIN_OFFSET, 4) && + VerifyField(verifier, VT_SURFACE, 4) && + VerifyField(verifier, VT_SOURCE, 4) && + VerifyField(verifier, VT_MASK, 4) && + VerifyField(verifier, VT_EFFECT, 4) && + VerifyOffset(verifier, VT_SOURCE_PARAMETERS) && + verifier.VerifyVector(source_parameters()) && + verifier.VerifyVectorOfTables(source_parameters()) && + verifier.EndTable(); + } +}; + +struct BrushBuilder { + typedef Brush Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_base(::flatbuffers::Offset base) { + fbb_.AddOffset(Brush::VT_BASE, base); + } + void add_kind(CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::BrushKind kind) { + fbb_.AddElement(Brush::VT_KIND, static_cast(kind), 0); + } + void add_color(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Color *color) { + fbb_.AddStruct(Brush::VT_COLOR, color); + } + void add_anchor_point(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *anchor_point) { + fbb_.AddStruct(Brush::VT_ANCHOR_POINT, anchor_point); + } + void add_center_point(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *center_point) { + fbb_.AddStruct(Brush::VT_CENTER_POINT, center_point); + } + void add_color_stops(::flatbuffers::Offset<::flatbuffers::Vector> color_stops) { + fbb_.AddOffset(Brush::VT_COLOR_STOPS, color_stops); + } + void add_extend_mode(uint8_t extend_mode) { + fbb_.AddElement(Brush::VT_EXTEND_MODE, extend_mode); + } + void add_interpolation_space(uint8_t interpolation_space) { + fbb_.AddElement(Brush::VT_INTERPOLATION_SPACE, interpolation_space); + } + void add_mapping_mode(uint8_t mapping_mode) { + fbb_.AddElement(Brush::VT_MAPPING_MODE, mapping_mode); + } + void add_offset(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *offset) { + fbb_.AddStruct(Brush::VT_OFFSET, offset); + } + void add_rotation_angle_in_degrees(float rotation_angle_in_degrees) { + fbb_.AddElement(Brush::VT_ROTATION_ANGLE_IN_DEGREES, rotation_angle_in_degrees); + } + void add_scale(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *scale) { + fbb_.AddStruct(Brush::VT_SCALE, scale); + } + void add_transform_matrix(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Mat3x2 *transform_matrix) { + fbb_.AddStruct(Brush::VT_TRANSFORM_MATRIX, transform_matrix); + } + void add_start_point(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *start_point) { + fbb_.AddStruct(Brush::VT_START_POINT, start_point); + } + void add_end_point(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *end_point) { + fbb_.AddStruct(Brush::VT_END_POINT, end_point); + } + void add_ellipse_center(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *ellipse_center) { + fbb_.AddStruct(Brush::VT_ELLIPSE_CENTER, ellipse_center); + } + void add_ellipse_radius(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *ellipse_radius) { + fbb_.AddStruct(Brush::VT_ELLIPSE_RADIUS, ellipse_radius); + } + void add_gradient_origin_offset(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *gradient_origin_offset) { + fbb_.AddStruct(Brush::VT_GRADIENT_ORIGIN_OFFSET, gradient_origin_offset); + } + void add_surface(uint32_t surface) { + fbb_.AddElement(Brush::VT_SURFACE, surface, 4294967295); + } + void add_source(uint32_t source) { + fbb_.AddElement(Brush::VT_SOURCE, source, 4294967295); + } + void add_mask(uint32_t mask) { + fbb_.AddElement(Brush::VT_MASK, mask, 4294967295); + } + void add_effect(uint32_t effect) { + fbb_.AddElement(Brush::VT_EFFECT, effect, 4294967295); + } + void add_source_parameters(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> source_parameters) { + fbb_.AddOffset(Brush::VT_SOURCE_PARAMETERS, source_parameters); + } + explicit BrushBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateBrush( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset base = 0, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::BrushKind kind = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::BrushKind::Color, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Color *color = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *anchor_point = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *center_point = nullptr, + ::flatbuffers::Offset<::flatbuffers::Vector> color_stops = 0, + ::flatbuffers::Optional extend_mode = ::flatbuffers::nullopt, + ::flatbuffers::Optional interpolation_space = ::flatbuffers::nullopt, + ::flatbuffers::Optional mapping_mode = ::flatbuffers::nullopt, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *offset = nullptr, + ::flatbuffers::Optional rotation_angle_in_degrees = ::flatbuffers::nullopt, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *scale = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Mat3x2 *transform_matrix = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *start_point = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *end_point = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *ellipse_center = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *ellipse_radius = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *gradient_origin_offset = nullptr, + uint32_t surface = 4294967295, + uint32_t source = 4294967295, + uint32_t mask = 4294967295, + uint32_t effect = 4294967295, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> source_parameters = 0) { + BrushBuilder builder_(_fbb); + builder_.add_source_parameters(source_parameters); + builder_.add_effect(effect); + builder_.add_mask(mask); + builder_.add_source(source); + builder_.add_surface(surface); + builder_.add_gradient_origin_offset(gradient_origin_offset); + builder_.add_ellipse_radius(ellipse_radius); + builder_.add_ellipse_center(ellipse_center); + builder_.add_end_point(end_point); + builder_.add_start_point(start_point); + builder_.add_transform_matrix(transform_matrix); + builder_.add_scale(scale); + if(rotation_angle_in_degrees) { builder_.add_rotation_angle_in_degrees(*rotation_angle_in_degrees); } + builder_.add_offset(offset); + builder_.add_color_stops(color_stops); + builder_.add_center_point(center_point); + builder_.add_anchor_point(anchor_point); + builder_.add_color(color); + builder_.add_base(base); + if(mapping_mode) { builder_.add_mapping_mode(*mapping_mode); } + if(interpolation_space) { builder_.add_interpolation_space(*interpolation_space); } + if(extend_mode) { builder_.add_extend_mode(*extend_mode); } + builder_.add_kind(kind); + return builder_.Finish(); +} + +inline ::flatbuffers::Offset CreateBrushDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset base = 0, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::BrushKind kind = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::BrushKind::Color, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Color *color = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *anchor_point = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *center_point = nullptr, + const std::vector *color_stops = nullptr, + ::flatbuffers::Optional extend_mode = ::flatbuffers::nullopt, + ::flatbuffers::Optional interpolation_space = ::flatbuffers::nullopt, + ::flatbuffers::Optional mapping_mode = ::flatbuffers::nullopt, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *offset = nullptr, + ::flatbuffers::Optional rotation_angle_in_degrees = ::flatbuffers::nullopt, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *scale = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Mat3x2 *transform_matrix = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *start_point = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *end_point = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *ellipse_center = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *ellipse_radius = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *gradient_origin_offset = nullptr, + uint32_t surface = 4294967295, + uint32_t source = 4294967295, + uint32_t mask = 4294967295, + uint32_t effect = 4294967295, + const std::vector<::flatbuffers::Offset> *source_parameters = nullptr) { + auto color_stops__ = color_stops ? _fbb.CreateVector(*color_stops) : 0; + auto source_parameters__ = source_parameters ? _fbb.CreateVector<::flatbuffers::Offset>(*source_parameters) : 0; + return CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CreateBrush( + _fbb, + base, + kind, + color, + anchor_point, + center_point, + color_stops__, + extend_mode, + interpolation_space, + mapping_mode, + offset, + rotation_angle_in_degrees, + scale, + transform_matrix, + start_point, + end_point, + ellipse_center, + ellipse_radius, + gradient_origin_offset, + surface, + source, + mask, + effect, + source_parameters__); +} + +struct GradientStop FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef GradientStopBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BASE = 4, + VT_COLOR = 6, + VT_OFFSET = 8 + }; + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CompObj *base() const { + return GetPointer(VT_BASE); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Color *color() const { + return GetStruct(VT_COLOR); + } + float offset() const { + return GetField(VT_OFFSET, 0.0f); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_BASE) && + verifier.VerifyTable(base()) && + VerifyField(verifier, VT_COLOR, 1) && + VerifyField(verifier, VT_OFFSET, 4) && + verifier.EndTable(); + } +}; + +struct GradientStopBuilder { + typedef GradientStop Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_base(::flatbuffers::Offset base) { + fbb_.AddOffset(GradientStop::VT_BASE, base); + } + void add_color(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Color *color) { + fbb_.AddStruct(GradientStop::VT_COLOR, color); + } + void add_offset(float offset) { + fbb_.AddElement(GradientStop::VT_OFFSET, offset, 0.0f); + } + explicit GradientStopBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateGradientStop( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset base = 0, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Color *color = nullptr, + float offset = 0.0f) { + GradientStopBuilder builder_(_fbb); + builder_.add_offset(offset); + builder_.add_color(color); + builder_.add_base(base); + return builder_.Finish(); +} + +struct ViewBox FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef ViewBoxBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BASE = 4, + VT_SIZE = 6 + }; + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CompObj *base() const { + return GetPointer(VT_BASE); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *size() const { + return GetStruct(VT_SIZE); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_BASE) && + verifier.VerifyTable(base()) && + VerifyField(verifier, VT_SIZE, 4) && + verifier.EndTable(); + } +}; + +struct ViewBoxBuilder { + typedef ViewBox Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_base(::flatbuffers::Offset base) { + fbb_.AddOffset(ViewBox::VT_BASE, base); + } + void add_size(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *size) { + fbb_.AddStruct(ViewBox::VT_SIZE, size); + } + explicit ViewBoxBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateViewBox( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset base = 0, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *size = nullptr) { + ViewBoxBuilder builder_(_fbb); + builder_.add_size(size); + builder_.add_base(base); + return builder_.Finish(); +} + +struct Clip FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef ClipBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BASE = 4, + VT_KIND = 6, + VT_CENTER_POINT = 8, + VT_SCALE = 10, + VT_LEFT_INSET = 12, + VT_RIGHT_INSET = 14, + VT_TOP_INSET = 16, + VT_BOTTOM_INSET = 18, + VT_GEOMETRY = 20 + }; + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CompObj *base() const { + return GetPointer(VT_BASE); + } + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::ClipKind kind() const { + return static_cast(GetField(VT_KIND, 0)); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *center_point() const { + return GetStruct(VT_CENTER_POINT); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *scale() const { + return GetStruct(VT_SCALE); + } + ::flatbuffers::Optional left_inset() const { + return GetOptional(VT_LEFT_INSET); + } + ::flatbuffers::Optional right_inset() const { + return GetOptional(VT_RIGHT_INSET); + } + ::flatbuffers::Optional top_inset() const { + return GetOptional(VT_TOP_INSET); + } + ::flatbuffers::Optional bottom_inset() const { + return GetOptional(VT_BOTTOM_INSET); + } + uint32_t geometry() const { + return GetField(VT_GEOMETRY, 4294967295); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_BASE) && + verifier.VerifyTable(base()) && + VerifyField(verifier, VT_KIND, 1) && + VerifyField(verifier, VT_CENTER_POINT, 4) && + VerifyField(verifier, VT_SCALE, 4) && + VerifyField(verifier, VT_LEFT_INSET, 4) && + VerifyField(verifier, VT_RIGHT_INSET, 4) && + VerifyField(verifier, VT_TOP_INSET, 4) && + VerifyField(verifier, VT_BOTTOM_INSET, 4) && + VerifyField(verifier, VT_GEOMETRY, 4) && + verifier.EndTable(); + } +}; + +struct ClipBuilder { + typedef Clip Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_base(::flatbuffers::Offset base) { + fbb_.AddOffset(Clip::VT_BASE, base); + } + void add_kind(CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::ClipKind kind) { + fbb_.AddElement(Clip::VT_KIND, static_cast(kind), 0); + } + void add_center_point(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *center_point) { + fbb_.AddStruct(Clip::VT_CENTER_POINT, center_point); + } + void add_scale(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *scale) { + fbb_.AddStruct(Clip::VT_SCALE, scale); + } + void add_left_inset(float left_inset) { + fbb_.AddElement(Clip::VT_LEFT_INSET, left_inset); + } + void add_right_inset(float right_inset) { + fbb_.AddElement(Clip::VT_RIGHT_INSET, right_inset); + } + void add_top_inset(float top_inset) { + fbb_.AddElement(Clip::VT_TOP_INSET, top_inset); + } + void add_bottom_inset(float bottom_inset) { + fbb_.AddElement(Clip::VT_BOTTOM_INSET, bottom_inset); + } + void add_geometry(uint32_t geometry) { + fbb_.AddElement(Clip::VT_GEOMETRY, geometry, 4294967295); + } + explicit ClipBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateClip( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset base = 0, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::ClipKind kind = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::ClipKind::Inset, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *center_point = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *scale = nullptr, + ::flatbuffers::Optional left_inset = ::flatbuffers::nullopt, + ::flatbuffers::Optional right_inset = ::flatbuffers::nullopt, + ::flatbuffers::Optional top_inset = ::flatbuffers::nullopt, + ::flatbuffers::Optional bottom_inset = ::flatbuffers::nullopt, + uint32_t geometry = 4294967295) { + ClipBuilder builder_(_fbb); + builder_.add_geometry(geometry); + if(bottom_inset) { builder_.add_bottom_inset(*bottom_inset); } + if(top_inset) { builder_.add_top_inset(*top_inset); } + if(right_inset) { builder_.add_right_inset(*right_inset); } + if(left_inset) { builder_.add_left_inset(*left_inset); } + builder_.add_scale(scale); + builder_.add_center_point(center_point); + builder_.add_base(base); + builder_.add_kind(kind); + return builder_.Finish(); +} + +struct Shadow FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef ShadowBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BASE = 4, + VT_KIND = 6, + VT_BLUR_RADIUS = 8, + VT_COLOR = 10, + VT_MASK = 12, + VT_OFFSET = 14, + VT_OPACITY = 16, + VT_SOURCE_POLICY = 18 + }; + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CompObj *base() const { + return GetPointer(VT_BASE); + } + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::ShadowKind kind() const { + return static_cast(GetField(VT_KIND, 0)); + } + ::flatbuffers::Optional blur_radius() const { + return GetOptional(VT_BLUR_RADIUS); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Color *color() const { + return GetStruct(VT_COLOR); + } + uint32_t mask() const { + return GetField(VT_MASK, 4294967295); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec3 *offset() const { + return GetStruct(VT_OFFSET); + } + ::flatbuffers::Optional opacity() const { + return GetOptional(VT_OPACITY); + } + ::flatbuffers::Optional source_policy() const { + return GetOptional(VT_SOURCE_POLICY); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_BASE) && + verifier.VerifyTable(base()) && + VerifyField(verifier, VT_KIND, 1) && + VerifyField(verifier, VT_BLUR_RADIUS, 4) && + VerifyField(verifier, VT_COLOR, 1) && + VerifyField(verifier, VT_MASK, 4) && + VerifyField(verifier, VT_OFFSET, 4) && + VerifyField(verifier, VT_OPACITY, 4) && + VerifyField(verifier, VT_SOURCE_POLICY, 1) && + verifier.EndTable(); + } +}; + +struct ShadowBuilder { + typedef Shadow Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_base(::flatbuffers::Offset base) { + fbb_.AddOffset(Shadow::VT_BASE, base); + } + void add_kind(CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::ShadowKind kind) { + fbb_.AddElement(Shadow::VT_KIND, static_cast(kind), 0); + } + void add_blur_radius(float blur_radius) { + fbb_.AddElement(Shadow::VT_BLUR_RADIUS, blur_radius); + } + void add_color(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Color *color) { + fbb_.AddStruct(Shadow::VT_COLOR, color); + } + void add_mask(uint32_t mask) { + fbb_.AddElement(Shadow::VT_MASK, mask, 4294967295); + } + void add_offset(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec3 *offset) { + fbb_.AddStruct(Shadow::VT_OFFSET, offset); + } + void add_opacity(float opacity) { + fbb_.AddElement(Shadow::VT_OPACITY, opacity); + } + void add_source_policy(uint8_t source_policy) { + fbb_.AddElement(Shadow::VT_SOURCE_POLICY, source_policy); + } + explicit ShadowBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateShadow( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset base = 0, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::ShadowKind kind = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::ShadowKind::Drop, + ::flatbuffers::Optional blur_radius = ::flatbuffers::nullopt, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Color *color = nullptr, + uint32_t mask = 4294967295, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec3 *offset = nullptr, + ::flatbuffers::Optional opacity = ::flatbuffers::nullopt, + ::flatbuffers::Optional source_policy = ::flatbuffers::nullopt) { + ShadowBuilder builder_(_fbb); + if(opacity) { builder_.add_opacity(*opacity); } + builder_.add_offset(offset); + builder_.add_mask(mask); + builder_.add_color(color); + if(blur_radius) { builder_.add_blur_radius(*blur_radius); } + builder_.add_base(base); + if(source_policy) { builder_.add_source_policy(*source_policy); } + builder_.add_kind(kind); + return builder_.Finish(); +} + +struct Surface FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef SurfaceBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BASE = 4, + VT_KIND = 6, + VT_SOURCE_VISUAL = 8, + VT_SOURCE_SIZE = 10, + VT_SOURCE_OFFSET = 12, + VT_URI = 14, + VT_BYTES = 16 + }; + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CompObj *base() const { + return GetPointer(VT_BASE); + } + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::SurfaceKind kind() const { + return static_cast(GetField(VT_KIND, 0)); + } + uint32_t source_visual() const { + return GetField(VT_SOURCE_VISUAL, 4294967295); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *source_size() const { + return GetStruct(VT_SOURCE_SIZE); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *source_offset() const { + return GetStruct(VT_SOURCE_OFFSET); + } + uint32_t uri() const { + return GetField(VT_URI, 4294967295); + } + const ::flatbuffers::Vector *bytes() const { + return GetPointer *>(VT_BYTES); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_BASE) && + verifier.VerifyTable(base()) && + VerifyField(verifier, VT_KIND, 1) && + VerifyField(verifier, VT_SOURCE_VISUAL, 4) && + VerifyField(verifier, VT_SOURCE_SIZE, 4) && + VerifyField(verifier, VT_SOURCE_OFFSET, 4) && + VerifyField(verifier, VT_URI, 4) && + VerifyOffset(verifier, VT_BYTES) && + verifier.VerifyVector(bytes()) && + verifier.EndTable(); + } +}; + +struct SurfaceBuilder { + typedef Surface Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_base(::flatbuffers::Offset base) { + fbb_.AddOffset(Surface::VT_BASE, base); + } + void add_kind(CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::SurfaceKind kind) { + fbb_.AddElement(Surface::VT_KIND, static_cast(kind), 0); + } + void add_source_visual(uint32_t source_visual) { + fbb_.AddElement(Surface::VT_SOURCE_VISUAL, source_visual, 4294967295); + } + void add_source_size(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *source_size) { + fbb_.AddStruct(Surface::VT_SOURCE_SIZE, source_size); + } + void add_source_offset(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *source_offset) { + fbb_.AddStruct(Surface::VT_SOURCE_OFFSET, source_offset); + } + void add_uri(uint32_t uri) { + fbb_.AddElement(Surface::VT_URI, uri, 4294967295); + } + void add_bytes(::flatbuffers::Offset<::flatbuffers::Vector> bytes) { + fbb_.AddOffset(Surface::VT_BYTES, bytes); + } + explicit SurfaceBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateSurface( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset base = 0, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::SurfaceKind kind = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::SurfaceKind::VisualSurface, + uint32_t source_visual = 4294967295, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *source_size = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *source_offset = nullptr, + uint32_t uri = 4294967295, + ::flatbuffers::Offset<::flatbuffers::Vector> bytes = 0) { + SurfaceBuilder builder_(_fbb); + builder_.add_bytes(bytes); + builder_.add_uri(uri); + builder_.add_source_offset(source_offset); + builder_.add_source_size(source_size); + builder_.add_source_visual(source_visual); + builder_.add_base(base); + builder_.add_kind(kind); + return builder_.Finish(); +} + +inline ::flatbuffers::Offset CreateSurfaceDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset base = 0, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::SurfaceKind kind = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::SurfaceKind::VisualSurface, + uint32_t source_visual = 4294967295, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *source_size = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *source_offset = nullptr, + uint32_t uri = 4294967295, + const std::vector *bytes = nullptr) { + auto bytes__ = bytes ? _fbb.CreateVector(*bytes) : 0; + return CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CreateSurface( + _fbb, + base, + kind, + source_visual, + source_size, + source_offset, + uri, + bytes__); +} + +struct Effect FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef EffectBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BASE = 4, + VT_KIND = 6, + VT_SOURCES = 8, + VT_MODE = 10, + VT_BLUR_AMOUNT = 12 + }; + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CompObj *base() const { + return GetPointer(VT_BASE); + } + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::EffectKind kind() const { + return static_cast(GetField(VT_KIND, 0)); + } + const ::flatbuffers::Vector *sources() const { + return GetPointer *>(VT_SOURCES); + } + uint8_t mode() const { + return GetField(VT_MODE, 0); + } + float blur_amount() const { + return GetField(VT_BLUR_AMOUNT, 0.0f); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_BASE) && + verifier.VerifyTable(base()) && + VerifyField(verifier, VT_KIND, 1) && + VerifyOffset(verifier, VT_SOURCES) && + verifier.VerifyVector(sources()) && + VerifyField(verifier, VT_MODE, 1) && + VerifyField(verifier, VT_BLUR_AMOUNT, 4) && + verifier.EndTable(); + } +}; + +struct EffectBuilder { + typedef Effect Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_base(::flatbuffers::Offset base) { + fbb_.AddOffset(Effect::VT_BASE, base); + } + void add_kind(CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::EffectKind kind) { + fbb_.AddElement(Effect::VT_KIND, static_cast(kind), 0); + } + void add_sources(::flatbuffers::Offset<::flatbuffers::Vector> sources) { + fbb_.AddOffset(Effect::VT_SOURCES, sources); + } + void add_mode(uint8_t mode) { + fbb_.AddElement(Effect::VT_MODE, mode, 0); + } + void add_blur_amount(float blur_amount) { + fbb_.AddElement(Effect::VT_BLUR_AMOUNT, blur_amount, 0.0f); + } + explicit EffectBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateEffect( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset base = 0, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::EffectKind kind = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::EffectKind::Composite, + ::flatbuffers::Offset<::flatbuffers::Vector> sources = 0, + uint8_t mode = 0, + float blur_amount = 0.0f) { + EffectBuilder builder_(_fbb); + builder_.add_blur_amount(blur_amount); + builder_.add_sources(sources); + builder_.add_base(base); + builder_.add_mode(mode); + builder_.add_kind(kind); + return builder_.Finish(); +} + +inline ::flatbuffers::Offset CreateEffectDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset base = 0, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::EffectKind kind = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::EffectKind::Composite, + const std::vector *sources = nullptr, + uint8_t mode = 0, + float blur_amount = 0.0f) { + auto sources__ = sources ? _fbb.CreateVector(*sources) : 0; + return CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CreateEffect( + _fbb, + base, + kind, + sources__, + mode, + blur_amount); +} + +struct Easing FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef EasingBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BASE = 4, + VT_KIND = 6, + VT_CONTROL_POINT_1 = 8, + VT_CONTROL_POINT_2 = 10, + VT_STEP_COUNT = 12, + VT_INITIAL_STEP = 14, + VT_FINAL_STEP = 16, + VT_IS_INITIAL_STEP_SINGLE_FRAME = 18, + VT_IS_FINAL_STEP_SINGLE_FRAME = 20 + }; + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CompObj *base() const { + return GetPointer(VT_BASE); + } + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::EasingKind kind() const { + return static_cast(GetField(VT_KIND, 0)); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *control_point_1() const { + return GetStruct(VT_CONTROL_POINT_1); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *control_point_2() const { + return GetStruct(VT_CONTROL_POINT_2); + } + ::flatbuffers::Optional step_count() const { + return GetOptional(VT_STEP_COUNT); + } + ::flatbuffers::Optional initial_step() const { + return GetOptional(VT_INITIAL_STEP); + } + ::flatbuffers::Optional final_step() const { + return GetOptional(VT_FINAL_STEP); + } + ::flatbuffers::Optional is_initial_step_single_frame() const { + return GetOptional(VT_IS_INITIAL_STEP_SINGLE_FRAME); + } + ::flatbuffers::Optional is_final_step_single_frame() const { + return GetOptional(VT_IS_FINAL_STEP_SINGLE_FRAME); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_BASE) && + verifier.VerifyTable(base()) && + VerifyField(verifier, VT_KIND, 1) && + VerifyField(verifier, VT_CONTROL_POINT_1, 4) && + VerifyField(verifier, VT_CONTROL_POINT_2, 4) && + VerifyField(verifier, VT_STEP_COUNT, 4) && + VerifyField(verifier, VT_INITIAL_STEP, 4) && + VerifyField(verifier, VT_FINAL_STEP, 4) && + VerifyField(verifier, VT_IS_INITIAL_STEP_SINGLE_FRAME, 1) && + VerifyField(verifier, VT_IS_FINAL_STEP_SINGLE_FRAME, 1) && + verifier.EndTable(); + } +}; + +struct EasingBuilder { + typedef Easing Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_base(::flatbuffers::Offset base) { + fbb_.AddOffset(Easing::VT_BASE, base); + } + void add_kind(CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::EasingKind kind) { + fbb_.AddElement(Easing::VT_KIND, static_cast(kind), 0); + } + void add_control_point_1(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *control_point_1) { + fbb_.AddStruct(Easing::VT_CONTROL_POINT_1, control_point_1); + } + void add_control_point_2(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *control_point_2) { + fbb_.AddStruct(Easing::VT_CONTROL_POINT_2, control_point_2); + } + void add_step_count(int32_t step_count) { + fbb_.AddElement(Easing::VT_STEP_COUNT, step_count); + } + void add_initial_step(int32_t initial_step) { + fbb_.AddElement(Easing::VT_INITIAL_STEP, initial_step); + } + void add_final_step(int32_t final_step) { + fbb_.AddElement(Easing::VT_FINAL_STEP, final_step); + } + void add_is_initial_step_single_frame(bool is_initial_step_single_frame) { + fbb_.AddElement(Easing::VT_IS_INITIAL_STEP_SINGLE_FRAME, static_cast(is_initial_step_single_frame)); + } + void add_is_final_step_single_frame(bool is_final_step_single_frame) { + fbb_.AddElement(Easing::VT_IS_FINAL_STEP_SINGLE_FRAME, static_cast(is_final_step_single_frame)); + } + explicit EasingBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateEasing( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset base = 0, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::EasingKind kind = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::EasingKind::Linear, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *control_point_1 = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec2 *control_point_2 = nullptr, + ::flatbuffers::Optional step_count = ::flatbuffers::nullopt, + ::flatbuffers::Optional initial_step = ::flatbuffers::nullopt, + ::flatbuffers::Optional final_step = ::flatbuffers::nullopt, + ::flatbuffers::Optional is_initial_step_single_frame = ::flatbuffers::nullopt, + ::flatbuffers::Optional is_final_step_single_frame = ::flatbuffers::nullopt) { + EasingBuilder builder_(_fbb); + if(final_step) { builder_.add_final_step(*final_step); } + if(initial_step) { builder_.add_initial_step(*initial_step); } + if(step_count) { builder_.add_step_count(*step_count); } + builder_.add_control_point_2(control_point_2); + builder_.add_control_point_1(control_point_1); + builder_.add_base(base); + if(is_final_step_single_frame) { builder_.add_is_final_step_single_frame(*is_final_step_single_frame); } + if(is_initial_step_single_frame) { builder_.add_is_initial_step_single_frame(*is_initial_step_single_frame); } + builder_.add_kind(kind); + return builder_.Finish(); +} + +struct Animation FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef AnimationBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BASE = 4, + VT_KIND = 6, + VT_TARGET = 8, + VT_REFERENCE_PARAMETERS = 10, + VT_EXPRESSION = 12, + VT_DURATION_TICKS = 14, + VT_KEY_FRAMES = 16, + VT_INTERPOLATION_COLOR_SPACE = 18 + }; + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CompObj *base() const { + return GetPointer(VT_BASE); + } + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::AnimationKind kind() const { + return static_cast(GetField(VT_KIND, 0)); + } + uint32_t target() const { + return GetField(VT_TARGET, 4294967295); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *reference_parameters() const { + return GetPointer> *>(VT_REFERENCE_PARAMETERS); + } + uint32_t expression() const { + return GetField(VT_EXPRESSION, 4294967295); + } + int64_t duration_ticks() const { + return GetField(VT_DURATION_TICKS, 0); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *key_frames() const { + return GetPointer> *>(VT_KEY_FRAMES); + } + ::flatbuffers::Optional interpolation_color_space() const { + return GetOptional(VT_INTERPOLATION_COLOR_SPACE); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_BASE) && + verifier.VerifyTable(base()) && + VerifyField(verifier, VT_KIND, 1) && + VerifyField(verifier, VT_TARGET, 4) && + VerifyOffset(verifier, VT_REFERENCE_PARAMETERS) && + verifier.VerifyVector(reference_parameters()) && + verifier.VerifyVectorOfTables(reference_parameters()) && + VerifyField(verifier, VT_EXPRESSION, 4) && + VerifyField(verifier, VT_DURATION_TICKS, 8) && + VerifyOffset(verifier, VT_KEY_FRAMES) && + verifier.VerifyVector(key_frames()) && + verifier.VerifyVectorOfTables(key_frames()) && + VerifyField(verifier, VT_INTERPOLATION_COLOR_SPACE, 1) && + verifier.EndTable(); + } +}; + +struct AnimationBuilder { + typedef Animation Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_base(::flatbuffers::Offset base) { + fbb_.AddOffset(Animation::VT_BASE, base); + } + void add_kind(CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::AnimationKind kind) { + fbb_.AddElement(Animation::VT_KIND, static_cast(kind), 0); + } + void add_target(uint32_t target) { + fbb_.AddElement(Animation::VT_TARGET, target, 4294967295); + } + void add_reference_parameters(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> reference_parameters) { + fbb_.AddOffset(Animation::VT_REFERENCE_PARAMETERS, reference_parameters); + } + void add_expression(uint32_t expression) { + fbb_.AddElement(Animation::VT_EXPRESSION, expression, 4294967295); + } + void add_duration_ticks(int64_t duration_ticks) { + fbb_.AddElement(Animation::VT_DURATION_TICKS, duration_ticks, 0); + } + void add_key_frames(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> key_frames) { + fbb_.AddOffset(Animation::VT_KEY_FRAMES, key_frames); + } + void add_interpolation_color_space(uint8_t interpolation_color_space) { + fbb_.AddElement(Animation::VT_INTERPOLATION_COLOR_SPACE, interpolation_color_space); + } + explicit AnimationBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateAnimation( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset base = 0, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::AnimationKind kind = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::AnimationKind::Scalar, + uint32_t target = 4294967295, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> reference_parameters = 0, + uint32_t expression = 4294967295, + int64_t duration_ticks = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> key_frames = 0, + ::flatbuffers::Optional interpolation_color_space = ::flatbuffers::nullopt) { + AnimationBuilder builder_(_fbb); + builder_.add_duration_ticks(duration_ticks); + builder_.add_key_frames(key_frames); + builder_.add_expression(expression); + builder_.add_reference_parameters(reference_parameters); + builder_.add_target(target); + builder_.add_base(base); + if(interpolation_color_space) { builder_.add_interpolation_color_space(*interpolation_color_space); } + builder_.add_kind(kind); + return builder_.Finish(); +} + +inline ::flatbuffers::Offset CreateAnimationDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset base = 0, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::AnimationKind kind = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::AnimationKind::Scalar, + uint32_t target = 4294967295, + const std::vector<::flatbuffers::Offset> *reference_parameters = nullptr, + uint32_t expression = 4294967295, + int64_t duration_ticks = 0, + const std::vector<::flatbuffers::Offset> *key_frames = nullptr, + ::flatbuffers::Optional interpolation_color_space = ::flatbuffers::nullopt) { + auto reference_parameters__ = reference_parameters ? _fbb.CreateVector<::flatbuffers::Offset>(*reference_parameters) : 0; + auto key_frames__ = key_frames ? _fbb.CreateVector<::flatbuffers::Offset>(*key_frames) : 0; + return CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CreateAnimation( + _fbb, + base, + kind, + target, + reference_parameters__, + expression, + duration_ticks, + key_frames__, + interpolation_color_space); +} + +struct PropertySet FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef PropertySetBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BASE = 4, + VT_OWNER = 6, + VT_VALUES = 8 + }; + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CompObj *base() const { + return GetPointer(VT_BASE); + } + uint32_t owner() const { + return GetField(VT_OWNER, 4294967295); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *values() const { + return GetPointer> *>(VT_VALUES); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_BASE) && + verifier.VerifyTable(base()) && + VerifyField(verifier, VT_OWNER, 4) && + VerifyOffset(verifier, VT_VALUES) && + verifier.VerifyVector(values()) && + verifier.VerifyVectorOfTables(values()) && + verifier.EndTable(); + } +}; + +struct PropertySetBuilder { + typedef PropertySet Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_base(::flatbuffers::Offset base) { + fbb_.AddOffset(PropertySet::VT_BASE, base); + } + void add_owner(uint32_t owner) { + fbb_.AddElement(PropertySet::VT_OWNER, owner, 4294967295); + } + void add_values(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> values) { + fbb_.AddOffset(PropertySet::VT_VALUES, values); + } + explicit PropertySetBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreatePropertySet( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset base = 0, + uint32_t owner = 4294967295, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> values = 0) { + PropertySetBuilder builder_(_fbb); + builder_.add_values(values); + builder_.add_owner(owner); + builder_.add_base(base); + return builder_.Finish(); +} + +inline ::flatbuffers::Offset CreatePropertySetDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset base = 0, + uint32_t owner = 4294967295, + const std::vector<::flatbuffers::Offset> *values = nullptr) { + auto values__ = values ? _fbb.CreateVector<::flatbuffers::Offset>(*values) : 0; + return CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CreatePropertySet( + _fbb, + base, + owner, + values__); +} + +struct Controller FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef ControllerBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BASE = 4, + VT_TARGET_OBJECT = 6, + VT_TARGET_PROPERTY = 8, + VT_IS_PAUSED = 10, + VT_IS_CUSTOM = 12 + }; + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CompObj *base() const { + return GetPointer(VT_BASE); + } + uint32_t target_object() const { + return GetField(VT_TARGET_OBJECT, 4294967295); + } + uint32_t target_property() const { + return GetField(VT_TARGET_PROPERTY, 4294967295); + } + bool is_paused() const { + return GetField(VT_IS_PAUSED, 0) != 0; + } + bool is_custom() const { + return GetField(VT_IS_CUSTOM, 0) != 0; + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_BASE) && + verifier.VerifyTable(base()) && + VerifyField(verifier, VT_TARGET_OBJECT, 4) && + VerifyField(verifier, VT_TARGET_PROPERTY, 4) && + VerifyField(verifier, VT_IS_PAUSED, 1) && + VerifyField(verifier, VT_IS_CUSTOM, 1) && + verifier.EndTable(); + } +}; + +struct ControllerBuilder { + typedef Controller Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_base(::flatbuffers::Offset base) { + fbb_.AddOffset(Controller::VT_BASE, base); + } + void add_target_object(uint32_t target_object) { + fbb_.AddElement(Controller::VT_TARGET_OBJECT, target_object, 4294967295); + } + void add_target_property(uint32_t target_property) { + fbb_.AddElement(Controller::VT_TARGET_PROPERTY, target_property, 4294967295); + } + void add_is_paused(bool is_paused) { + fbb_.AddElement(Controller::VT_IS_PAUSED, static_cast(is_paused), 0); + } + void add_is_custom(bool is_custom) { + fbb_.AddElement(Controller::VT_IS_CUSTOM, static_cast(is_custom), 0); + } + explicit ControllerBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateController( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset base = 0, + uint32_t target_object = 4294967295, + uint32_t target_property = 4294967295, + bool is_paused = false, + bool is_custom = false) { + ControllerBuilder builder_(_fbb); + builder_.add_target_property(target_property); + builder_.add_target_object(target_object); + builder_.add_base(base); + builder_.add_is_custom(is_custom); + builder_.add_is_paused(is_paused); + return builder_.Finish(); +} + +struct PropertyBinding FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef PropertyBindingBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_DISPLAY_NAME = 6, + VT_ACTUAL_TYPE = 8, + VT_EXPOSED_TYPE = 10, + VT_DEFAULT_SCALAR = 12, + VT_DEFAULT_VECTOR = 14, + VT_DEFAULT_COLOR = 16 + }; + uint32_t name() const { + return GetField(VT_NAME, 0); + } + uint32_t display_name() const { + return GetField(VT_DISPLAY_NAME, 0); + } + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::PropertyValueType actual_type() const { + return static_cast(GetField(VT_ACTUAL_TYPE, 0)); + } + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::PropertyValueType exposed_type() const { + return static_cast(GetField(VT_EXPOSED_TYPE, 0)); + } + float default_scalar() const { + return GetField(VT_DEFAULT_SCALAR, 0.0f); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec4 *default_vector() const { + return GetStruct(VT_DEFAULT_VECTOR); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Color *default_color() const { + return GetStruct(VT_DEFAULT_COLOR); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_NAME, 4) && + VerifyField(verifier, VT_DISPLAY_NAME, 4) && + VerifyField(verifier, VT_ACTUAL_TYPE, 1) && + VerifyField(verifier, VT_EXPOSED_TYPE, 1) && + VerifyField(verifier, VT_DEFAULT_SCALAR, 4) && + VerifyField(verifier, VT_DEFAULT_VECTOR, 4) && + VerifyField(verifier, VT_DEFAULT_COLOR, 1) && + verifier.EndTable(); + } +}; + +struct PropertyBindingBuilder { + typedef PropertyBinding Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_name(uint32_t name) { + fbb_.AddElement(PropertyBinding::VT_NAME, name, 0); + } + void add_display_name(uint32_t display_name) { + fbb_.AddElement(PropertyBinding::VT_DISPLAY_NAME, display_name, 0); + } + void add_actual_type(CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::PropertyValueType actual_type) { + fbb_.AddElement(PropertyBinding::VT_ACTUAL_TYPE, static_cast(actual_type), 0); + } + void add_exposed_type(CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::PropertyValueType exposed_type) { + fbb_.AddElement(PropertyBinding::VT_EXPOSED_TYPE, static_cast(exposed_type), 0); + } + void add_default_scalar(float default_scalar) { + fbb_.AddElement(PropertyBinding::VT_DEFAULT_SCALAR, default_scalar, 0.0f); + } + void add_default_vector(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec4 *default_vector) { + fbb_.AddStruct(PropertyBinding::VT_DEFAULT_VECTOR, default_vector); + } + void add_default_color(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Color *default_color) { + fbb_.AddStruct(PropertyBinding::VT_DEFAULT_COLOR, default_color); + } + explicit PropertyBindingBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreatePropertyBinding( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint32_t name = 0, + uint32_t display_name = 0, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::PropertyValueType actual_type = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::PropertyValueType::None, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::PropertyValueType exposed_type = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::PropertyValueType::None, + float default_scalar = 0.0f, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Vec4 *default_vector = nullptr, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Color *default_color = nullptr) { + PropertyBindingBuilder builder_(_fbb); + builder_.add_default_color(default_color); + builder_.add_default_vector(default_vector); + builder_.add_default_scalar(default_scalar); + builder_.add_display_name(display_name); + builder_.add_name(name); + builder_.add_exposed_type(exposed_type); + builder_.add_actual_type(actual_type); + return builder_.Finish(); +} + +struct Marker FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef MarkerBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_PROGRESS = 6, + VT_DURATION_PROGRESS = 8 + }; + uint32_t name() const { + return GetField(VT_NAME, 0); + } + float progress() const { + return GetField(VT_PROGRESS, 0.0f); + } + float duration_progress() const { + return GetField(VT_DURATION_PROGRESS, 0.0f); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_NAME, 4) && + VerifyField(verifier, VT_PROGRESS, 4) && + VerifyField(verifier, VT_DURATION_PROGRESS, 4) && + verifier.EndTable(); + } +}; + +struct MarkerBuilder { + typedef Marker Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_name(uint32_t name) { + fbb_.AddElement(Marker::VT_NAME, name, 0); + } + void add_progress(float progress) { + fbb_.AddElement(Marker::VT_PROGRESS, progress, 0.0f); + } + void add_duration_progress(float duration_progress) { + fbb_.AddElement(Marker::VT_DURATION_PROGRESS, duration_progress, 0.0f); + } + explicit MarkerBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateMarker( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint32_t name = 0, + float progress = 0.0f, + float duration_progress = 0.0f) { + MarkerBuilder builder_(_fbb); + builder_.add_duration_progress(duration_progress); + builder_.add_progress(progress); + builder_.add_name(name); + return builder_.Finish(); +} + +struct Metadata FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef MetadataBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_WIDTH = 6, + VT_HEIGHT = 8, + VT_DURATION_TICKS = 10, + VT_FRAMES_PER_SECOND = 12, + VT_PROPERTY_BINDINGS = 14, + VT_MARKERS = 16, + VT_THEMING_PROPERTY_SET = 18 + }; + uint32_t name() const { + return GetField(VT_NAME, 4294967295); + } + float width() const { + return GetField(VT_WIDTH, 0.0f); + } + float height() const { + return GetField(VT_HEIGHT, 0.0f); + } + int64_t duration_ticks() const { + return GetField(VT_DURATION_TICKS, 0); + } + float frames_per_second() const { + return GetField(VT_FRAMES_PER_SECOND, 0.0f); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *property_bindings() const { + return GetPointer> *>(VT_PROPERTY_BINDINGS); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *markers() const { + return GetPointer> *>(VT_MARKERS); + } + uint32_t theming_property_set() const { + return GetField(VT_THEMING_PROPERTY_SET, 4294967295); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_NAME, 4) && + VerifyField(verifier, VT_WIDTH, 4) && + VerifyField(verifier, VT_HEIGHT, 4) && + VerifyField(verifier, VT_DURATION_TICKS, 8) && + VerifyField(verifier, VT_FRAMES_PER_SECOND, 4) && + VerifyOffset(verifier, VT_PROPERTY_BINDINGS) && + verifier.VerifyVector(property_bindings()) && + verifier.VerifyVectorOfTables(property_bindings()) && + VerifyOffset(verifier, VT_MARKERS) && + verifier.VerifyVector(markers()) && + verifier.VerifyVectorOfTables(markers()) && + VerifyField(verifier, VT_THEMING_PROPERTY_SET, 4) && + verifier.EndTable(); + } +}; + +struct MetadataBuilder { + typedef Metadata Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_name(uint32_t name) { + fbb_.AddElement(Metadata::VT_NAME, name, 4294967295); + } + void add_width(float width) { + fbb_.AddElement(Metadata::VT_WIDTH, width, 0.0f); + } + void add_height(float height) { + fbb_.AddElement(Metadata::VT_HEIGHT, height, 0.0f); + } + void add_duration_ticks(int64_t duration_ticks) { + fbb_.AddElement(Metadata::VT_DURATION_TICKS, duration_ticks, 0); + } + void add_frames_per_second(float frames_per_second) { + fbb_.AddElement(Metadata::VT_FRAMES_PER_SECOND, frames_per_second, 0.0f); + } + void add_property_bindings(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> property_bindings) { + fbb_.AddOffset(Metadata::VT_PROPERTY_BINDINGS, property_bindings); + } + void add_markers(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> markers) { + fbb_.AddOffset(Metadata::VT_MARKERS, markers); + } + void add_theming_property_set(uint32_t theming_property_set) { + fbb_.AddElement(Metadata::VT_THEMING_PROPERTY_SET, theming_property_set, 4294967295); + } + explicit MetadataBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateMetadata( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint32_t name = 4294967295, + float width = 0.0f, + float height = 0.0f, + int64_t duration_ticks = 0, + float frames_per_second = 0.0f, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> property_bindings = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> markers = 0, + uint32_t theming_property_set = 4294967295) { + MetadataBuilder builder_(_fbb); + builder_.add_duration_ticks(duration_ticks); + builder_.add_theming_property_set(theming_property_set); + builder_.add_markers(markers); + builder_.add_property_bindings(property_bindings); + builder_.add_frames_per_second(frames_per_second); + builder_.add_height(height); + builder_.add_width(width); + builder_.add_name(name); + return builder_.Finish(); +} + +inline ::flatbuffers::Offset CreateMetadataDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint32_t name = 4294967295, + float width = 0.0f, + float height = 0.0f, + int64_t duration_ticks = 0, + float frames_per_second = 0.0f, + const std::vector<::flatbuffers::Offset> *property_bindings = nullptr, + const std::vector<::flatbuffers::Offset> *markers = nullptr, + uint32_t theming_property_set = 4294967295) { + auto property_bindings__ = property_bindings ? _fbb.CreateVector<::flatbuffers::Offset>(*property_bindings) : 0; + auto markers__ = markers ? _fbb.CreateVector<::flatbuffers::Offset>(*markers) : 0; + return CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CreateMetadata( + _fbb, + name, + width, + height, + duration_ticks, + frames_per_second, + property_bindings__, + markers__, + theming_property_set); +} + +struct LottieComposition FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef LottieCompositionBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_SCHEMA_VERSION = 4, + VT_REQUIRED_UAP_VERSION = 6, + VT_METADATA = 8, + VT_ROOT_VISUAL = 10, + VT_STRINGS = 12, + VT_VISUALS = 14, + VT_SHAPES = 16, + VT_GEOMETRIES = 18, + VT_CANVAS_GEOMETRIES = 20, + VT_BRUSHES = 22, + VT_GRADIENT_STOPS = 24, + VT_VIEW_BOXES = 26, + VT_CLIPS = 28, + VT_SHADOWS = 30, + VT_SURFACES = 32, + VT_EFFECTS = 34, + VT_EASINGS = 36, + VT_ANIMATIONS = 38, + VT_PROPERTY_SETS = 40, + VT_CONTROLLERS = 42, + VT_CUSTOM_CONTROLLERS = 44 + }; + uint16_t schema_version() const { + return GetField(VT_SCHEMA_VERSION, 0); + } + uint16_t required_uap_version() const { + return GetField(VT_REQUIRED_UAP_VERSION, 0); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Metadata *metadata() const { + return GetPointer(VT_METADATA); + } + uint32_t root_visual() const { + return GetField(VT_ROOT_VISUAL, 4294967295); + } + const ::flatbuffers::Vector<::flatbuffers::Offset<::flatbuffers::String>> *strings() const { + return GetPointer> *>(VT_STRINGS); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *visuals() const { + return GetPointer> *>(VT_VISUALS); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *shapes() const { + return GetPointer> *>(VT_SHAPES); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *geometries() const { + return GetPointer> *>(VT_GEOMETRIES); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *canvas_geometries() const { + return GetPointer> *>(VT_CANVAS_GEOMETRIES); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *brushes() const { + return GetPointer> *>(VT_BRUSHES); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *gradient_stops() const { + return GetPointer> *>(VT_GRADIENT_STOPS); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *view_boxes() const { + return GetPointer> *>(VT_VIEW_BOXES); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *clips() const { + return GetPointer> *>(VT_CLIPS); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *shadows() const { + return GetPointer> *>(VT_SHADOWS); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *surfaces() const { + return GetPointer> *>(VT_SURFACES); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *effects() const { + return GetPointer> *>(VT_EFFECTS); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *easings() const { + return GetPointer> *>(VT_EASINGS); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *animations() const { + return GetPointer> *>(VT_ANIMATIONS); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *property_sets() const { + return GetPointer> *>(VT_PROPERTY_SETS); + } + const ::flatbuffers::Vector<::flatbuffers::Offset> *controllers() const { + return GetPointer> *>(VT_CONTROLLERS); + } + const ::flatbuffers::Vector *custom_controllers() const { + return GetPointer *>(VT_CUSTOM_CONTROLLERS); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_SCHEMA_VERSION, 2) && + VerifyField(verifier, VT_REQUIRED_UAP_VERSION, 2) && + VerifyOffset(verifier, VT_METADATA) && + verifier.VerifyTable(metadata()) && + VerifyField(verifier, VT_ROOT_VISUAL, 4) && + VerifyOffset(verifier, VT_STRINGS) && + verifier.VerifyVector(strings()) && + verifier.VerifyVectorOfStrings(strings()) && + VerifyOffset(verifier, VT_VISUALS) && + verifier.VerifyVector(visuals()) && + verifier.VerifyVectorOfTables(visuals()) && + VerifyOffset(verifier, VT_SHAPES) && + verifier.VerifyVector(shapes()) && + verifier.VerifyVectorOfTables(shapes()) && + VerifyOffset(verifier, VT_GEOMETRIES) && + verifier.VerifyVector(geometries()) && + verifier.VerifyVectorOfTables(geometries()) && + VerifyOffset(verifier, VT_CANVAS_GEOMETRIES) && + verifier.VerifyVector(canvas_geometries()) && + verifier.VerifyVectorOfTables(canvas_geometries()) && + VerifyOffset(verifier, VT_BRUSHES) && + verifier.VerifyVector(brushes()) && + verifier.VerifyVectorOfTables(brushes()) && + VerifyOffset(verifier, VT_GRADIENT_STOPS) && + verifier.VerifyVector(gradient_stops()) && + verifier.VerifyVectorOfTables(gradient_stops()) && + VerifyOffset(verifier, VT_VIEW_BOXES) && + verifier.VerifyVector(view_boxes()) && + verifier.VerifyVectorOfTables(view_boxes()) && + VerifyOffset(verifier, VT_CLIPS) && + verifier.VerifyVector(clips()) && + verifier.VerifyVectorOfTables(clips()) && + VerifyOffset(verifier, VT_SHADOWS) && + verifier.VerifyVector(shadows()) && + verifier.VerifyVectorOfTables(shadows()) && + VerifyOffset(verifier, VT_SURFACES) && + verifier.VerifyVector(surfaces()) && + verifier.VerifyVectorOfTables(surfaces()) && + VerifyOffset(verifier, VT_EFFECTS) && + verifier.VerifyVector(effects()) && + verifier.VerifyVectorOfTables(effects()) && + VerifyOffset(verifier, VT_EASINGS) && + verifier.VerifyVector(easings()) && + verifier.VerifyVectorOfTables(easings()) && + VerifyOffset(verifier, VT_ANIMATIONS) && + verifier.VerifyVector(animations()) && + verifier.VerifyVectorOfTables(animations()) && + VerifyOffset(verifier, VT_PROPERTY_SETS) && + verifier.VerifyVector(property_sets()) && + verifier.VerifyVectorOfTables(property_sets()) && + VerifyOffset(verifier, VT_CONTROLLERS) && + verifier.VerifyVector(controllers()) && + verifier.VerifyVectorOfTables(controllers()) && + VerifyOffset(verifier, VT_CUSTOM_CONTROLLERS) && + verifier.VerifyVector(custom_controllers()) && + verifier.EndTable(); + } +}; + +struct LottieCompositionBuilder { + typedef LottieComposition Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_schema_version(uint16_t schema_version) { + fbb_.AddElement(LottieComposition::VT_SCHEMA_VERSION, schema_version, 0); + } + void add_required_uap_version(uint16_t required_uap_version) { + fbb_.AddElement(LottieComposition::VT_REQUIRED_UAP_VERSION, required_uap_version, 0); + } + void add_metadata(::flatbuffers::Offset metadata) { + fbb_.AddOffset(LottieComposition::VT_METADATA, metadata); + } + void add_root_visual(uint32_t root_visual) { + fbb_.AddElement(LottieComposition::VT_ROOT_VISUAL, root_visual, 4294967295); + } + void add_strings(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset<::flatbuffers::String>>> strings) { + fbb_.AddOffset(LottieComposition::VT_STRINGS, strings); + } + void add_visuals(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> visuals) { + fbb_.AddOffset(LottieComposition::VT_VISUALS, visuals); + } + void add_shapes(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> shapes) { + fbb_.AddOffset(LottieComposition::VT_SHAPES, shapes); + } + void add_geometries(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> geometries) { + fbb_.AddOffset(LottieComposition::VT_GEOMETRIES, geometries); + } + void add_canvas_geometries(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> canvas_geometries) { + fbb_.AddOffset(LottieComposition::VT_CANVAS_GEOMETRIES, canvas_geometries); + } + void add_brushes(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> brushes) { + fbb_.AddOffset(LottieComposition::VT_BRUSHES, brushes); + } + void add_gradient_stops(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> gradient_stops) { + fbb_.AddOffset(LottieComposition::VT_GRADIENT_STOPS, gradient_stops); + } + void add_view_boxes(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> view_boxes) { + fbb_.AddOffset(LottieComposition::VT_VIEW_BOXES, view_boxes); + } + void add_clips(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> clips) { + fbb_.AddOffset(LottieComposition::VT_CLIPS, clips); + } + void add_shadows(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> shadows) { + fbb_.AddOffset(LottieComposition::VT_SHADOWS, shadows); + } + void add_surfaces(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> surfaces) { + fbb_.AddOffset(LottieComposition::VT_SURFACES, surfaces); + } + void add_effects(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> effects) { + fbb_.AddOffset(LottieComposition::VT_EFFECTS, effects); + } + void add_easings(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> easings) { + fbb_.AddOffset(LottieComposition::VT_EASINGS, easings); + } + void add_animations(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> animations) { + fbb_.AddOffset(LottieComposition::VT_ANIMATIONS, animations); + } + void add_property_sets(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> property_sets) { + fbb_.AddOffset(LottieComposition::VT_PROPERTY_SETS, property_sets); + } + void add_controllers(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> controllers) { + fbb_.AddOffset(LottieComposition::VT_CONTROLLERS, controllers); + } + void add_custom_controllers(::flatbuffers::Offset<::flatbuffers::Vector> custom_controllers) { + fbb_.AddOffset(LottieComposition::VT_CUSTOM_CONTROLLERS, custom_controllers); + } + explicit LottieCompositionBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateLottieComposition( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint16_t schema_version = 0, + uint16_t required_uap_version = 0, + ::flatbuffers::Offset metadata = 0, + uint32_t root_visual = 4294967295, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset<::flatbuffers::String>>> strings = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> visuals = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> shapes = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> geometries = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> canvas_geometries = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> brushes = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> gradient_stops = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> view_boxes = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> clips = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> shadows = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> surfaces = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> effects = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> easings = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> animations = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> property_sets = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> controllers = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> custom_controllers = 0) { + LottieCompositionBuilder builder_(_fbb); + builder_.add_custom_controllers(custom_controllers); + builder_.add_controllers(controllers); + builder_.add_property_sets(property_sets); + builder_.add_animations(animations); + builder_.add_easings(easings); + builder_.add_effects(effects); + builder_.add_surfaces(surfaces); + builder_.add_shadows(shadows); + builder_.add_clips(clips); + builder_.add_view_boxes(view_boxes); + builder_.add_gradient_stops(gradient_stops); + builder_.add_brushes(brushes); + builder_.add_canvas_geometries(canvas_geometries); + builder_.add_geometries(geometries); + builder_.add_shapes(shapes); + builder_.add_visuals(visuals); + builder_.add_strings(strings); + builder_.add_root_visual(root_visual); + builder_.add_metadata(metadata); + builder_.add_required_uap_version(required_uap_version); + builder_.add_schema_version(schema_version); + return builder_.Finish(); +} + +inline ::flatbuffers::Offset CreateLottieCompositionDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint16_t schema_version = 0, + uint16_t required_uap_version = 0, + ::flatbuffers::Offset metadata = 0, + uint32_t root_visual = 4294967295, + const std::vector<::flatbuffers::Offset<::flatbuffers::String>> *strings = nullptr, + const std::vector<::flatbuffers::Offset> *visuals = nullptr, + const std::vector<::flatbuffers::Offset> *shapes = nullptr, + const std::vector<::flatbuffers::Offset> *geometries = nullptr, + const std::vector<::flatbuffers::Offset> *canvas_geometries = nullptr, + const std::vector<::flatbuffers::Offset> *brushes = nullptr, + const std::vector<::flatbuffers::Offset> *gradient_stops = nullptr, + const std::vector<::flatbuffers::Offset> *view_boxes = nullptr, + const std::vector<::flatbuffers::Offset> *clips = nullptr, + const std::vector<::flatbuffers::Offset> *shadows = nullptr, + const std::vector<::flatbuffers::Offset> *surfaces = nullptr, + const std::vector<::flatbuffers::Offset> *effects = nullptr, + const std::vector<::flatbuffers::Offset> *easings = nullptr, + const std::vector<::flatbuffers::Offset> *animations = nullptr, + const std::vector<::flatbuffers::Offset> *property_sets = nullptr, + const std::vector<::flatbuffers::Offset> *controllers = nullptr, + const std::vector *custom_controllers = nullptr) { + auto strings__ = strings ? _fbb.CreateVector<::flatbuffers::Offset<::flatbuffers::String>>(*strings) : 0; + auto visuals__ = visuals ? _fbb.CreateVector<::flatbuffers::Offset>(*visuals) : 0; + auto shapes__ = shapes ? _fbb.CreateVector<::flatbuffers::Offset>(*shapes) : 0; + auto geometries__ = geometries ? _fbb.CreateVector<::flatbuffers::Offset>(*geometries) : 0; + auto canvas_geometries__ = canvas_geometries ? _fbb.CreateVector<::flatbuffers::Offset>(*canvas_geometries) : 0; + auto brushes__ = brushes ? _fbb.CreateVector<::flatbuffers::Offset>(*brushes) : 0; + auto gradient_stops__ = gradient_stops ? _fbb.CreateVector<::flatbuffers::Offset>(*gradient_stops) : 0; + auto view_boxes__ = view_boxes ? _fbb.CreateVector<::flatbuffers::Offset>(*view_boxes) : 0; + auto clips__ = clips ? _fbb.CreateVector<::flatbuffers::Offset>(*clips) : 0; + auto shadows__ = shadows ? _fbb.CreateVector<::flatbuffers::Offset>(*shadows) : 0; + auto surfaces__ = surfaces ? _fbb.CreateVector<::flatbuffers::Offset>(*surfaces) : 0; + auto effects__ = effects ? _fbb.CreateVector<::flatbuffers::Offset>(*effects) : 0; + auto easings__ = easings ? _fbb.CreateVector<::flatbuffers::Offset>(*easings) : 0; + auto animations__ = animations ? _fbb.CreateVector<::flatbuffers::Offset>(*animations) : 0; + auto property_sets__ = property_sets ? _fbb.CreateVector<::flatbuffers::Offset>(*property_sets) : 0; + auto controllers__ = controllers ? _fbb.CreateVector<::flatbuffers::Offset>(*controllers) : 0; + auto custom_controllers__ = custom_controllers ? _fbb.CreateVector(*custom_controllers) : 0; + return CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CreateLottieComposition( + _fbb, + schema_version, + required_uap_version, + metadata, + root_visual, + strings__, + visuals__, + shapes__, + geometries__, + canvas_geometries__, + brushes__, + gradient_stops__, + view_boxes__, + clips__, + shadows__, + surfaces__, + effects__, + easings__, + animations__, + property_sets__, + controllers__, + custom_controllers__); +} + +struct CanvasGeometry FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef CanvasGeometryBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_KIND = 4, + VT_A = 6, + VT_B = 8, + VT_COMBINE_MODE = 10, + VT_MATRIX = 12, + VT_SOURCE = 14, + VT_GEOMETRIES = 16, + VT_FILL_RULE = 18, + VT_OPS = 20, + VT_OPERANDS = 22, + VT_X = 24, + VT_Y = 26, + VT_W = 28, + VT_H = 30, + VT_RADIUS_X = 32, + VT_RADIUS_Y = 34 + }; + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CanvasGeometryKind kind() const { + return static_cast(GetField(VT_KIND, 0)); + } + uint32_t a() const { + return GetField(VT_A, 4294967295); + } + uint32_t b() const { + return GetField(VT_B, 4294967295); + } + uint8_t combine_mode() const { + return GetField(VT_COMBINE_MODE, 0); + } + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Mat3x2 *matrix() const { + return GetStruct(VT_MATRIX); + } + uint32_t source() const { + return GetField(VT_SOURCE, 4294967295); + } + const ::flatbuffers::Vector *geometries() const { + return GetPointer *>(VT_GEOMETRIES); + } + uint8_t fill_rule() const { + return GetField(VT_FILL_RULE, 0); + } + const ::flatbuffers::Vector *ops() const { + return GetPointer *>(VT_OPS); + } + const ::flatbuffers::Vector *operands() const { + return GetPointer *>(VT_OPERANDS); + } + float x() const { + return GetField(VT_X, 0.0f); + } + float y() const { + return GetField(VT_Y, 0.0f); + } + float w() const { + return GetField(VT_W, 0.0f); + } + float h() const { + return GetField(VT_H, 0.0f); + } + float radius_x() const { + return GetField(VT_RADIUS_X, 0.0f); + } + float radius_y() const { + return GetField(VT_RADIUS_Y, 0.0f); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_KIND, 1) && + VerifyField(verifier, VT_A, 4) && + VerifyField(verifier, VT_B, 4) && + VerifyField(verifier, VT_COMBINE_MODE, 1) && + VerifyField(verifier, VT_MATRIX, 4) && + VerifyField(verifier, VT_SOURCE, 4) && + VerifyOffset(verifier, VT_GEOMETRIES) && + verifier.VerifyVector(geometries()) && + VerifyField(verifier, VT_FILL_RULE, 1) && + VerifyOffset(verifier, VT_OPS) && + verifier.VerifyVector(ops()) && + VerifyOffset(verifier, VT_OPERANDS) && + verifier.VerifyVector(operands()) && + VerifyField(verifier, VT_X, 4) && + VerifyField(verifier, VT_Y, 4) && + VerifyField(verifier, VT_W, 4) && + VerifyField(verifier, VT_H, 4) && + VerifyField(verifier, VT_RADIUS_X, 4) && + VerifyField(verifier, VT_RADIUS_Y, 4) && + verifier.EndTable(); + } +}; + +struct CanvasGeometryBuilder { + typedef CanvasGeometry Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_kind(CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CanvasGeometryKind kind) { + fbb_.AddElement(CanvasGeometry::VT_KIND, static_cast(kind), 0); + } + void add_a(uint32_t a) { + fbb_.AddElement(CanvasGeometry::VT_A, a, 4294967295); + } + void add_b(uint32_t b) { + fbb_.AddElement(CanvasGeometry::VT_B, b, 4294967295); + } + void add_combine_mode(uint8_t combine_mode) { + fbb_.AddElement(CanvasGeometry::VT_COMBINE_MODE, combine_mode, 0); + } + void add_matrix(const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Mat3x2 *matrix) { + fbb_.AddStruct(CanvasGeometry::VT_MATRIX, matrix); + } + void add_source(uint32_t source) { + fbb_.AddElement(CanvasGeometry::VT_SOURCE, source, 4294967295); + } + void add_geometries(::flatbuffers::Offset<::flatbuffers::Vector> geometries) { + fbb_.AddOffset(CanvasGeometry::VT_GEOMETRIES, geometries); + } + void add_fill_rule(uint8_t fill_rule) { + fbb_.AddElement(CanvasGeometry::VT_FILL_RULE, fill_rule, 0); + } + void add_ops(::flatbuffers::Offset<::flatbuffers::Vector> ops) { + fbb_.AddOffset(CanvasGeometry::VT_OPS, ops); + } + void add_operands(::flatbuffers::Offset<::flatbuffers::Vector> operands) { + fbb_.AddOffset(CanvasGeometry::VT_OPERANDS, operands); + } + void add_x(float x) { + fbb_.AddElement(CanvasGeometry::VT_X, x, 0.0f); + } + void add_y(float y) { + fbb_.AddElement(CanvasGeometry::VT_Y, y, 0.0f); + } + void add_w(float w) { + fbb_.AddElement(CanvasGeometry::VT_W, w, 0.0f); + } + void add_h(float h) { + fbb_.AddElement(CanvasGeometry::VT_H, h, 0.0f); + } + void add_radius_x(float radius_x) { + fbb_.AddElement(CanvasGeometry::VT_RADIUS_X, radius_x, 0.0f); + } + void add_radius_y(float radius_y) { + fbb_.AddElement(CanvasGeometry::VT_RADIUS_Y, radius_y, 0.0f); + } + explicit CanvasGeometryBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateCanvasGeometry( + ::flatbuffers::FlatBufferBuilder &_fbb, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CanvasGeometryKind kind = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CanvasGeometryKind::Combination, + uint32_t a = 4294967295, + uint32_t b = 4294967295, + uint8_t combine_mode = 0, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Mat3x2 *matrix = nullptr, + uint32_t source = 4294967295, + ::flatbuffers::Offset<::flatbuffers::Vector> geometries = 0, + uint8_t fill_rule = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> ops = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> operands = 0, + float x = 0.0f, + float y = 0.0f, + float w = 0.0f, + float h = 0.0f, + float radius_x = 0.0f, + float radius_y = 0.0f) { + CanvasGeometryBuilder builder_(_fbb); + builder_.add_radius_y(radius_y); + builder_.add_radius_x(radius_x); + builder_.add_h(h); + builder_.add_w(w); + builder_.add_y(y); + builder_.add_x(x); + builder_.add_operands(operands); + builder_.add_ops(ops); + builder_.add_geometries(geometries); + builder_.add_source(source); + builder_.add_matrix(matrix); + builder_.add_b(b); + builder_.add_a(a); + builder_.add_fill_rule(fill_rule); + builder_.add_combine_mode(combine_mode); + builder_.add_kind(kind); + return builder_.Finish(); +} + +inline ::flatbuffers::Offset CreateCanvasGeometryDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CanvasGeometryKind kind = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CanvasGeometryKind::Combination, + uint32_t a = 4294967295, + uint32_t b = 4294967295, + uint8_t combine_mode = 0, + const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::Mat3x2 *matrix = nullptr, + uint32_t source = 4294967295, + const std::vector *geometries = nullptr, + uint8_t fill_rule = 0, + const std::vector *ops = nullptr, + const std::vector *operands = nullptr, + float x = 0.0f, + float y = 0.0f, + float w = 0.0f, + float h = 0.0f, + float radius_x = 0.0f, + float radius_y = 0.0f) { + auto geometries__ = geometries ? _fbb.CreateVector(*geometries) : 0; + auto ops__ = ops ? _fbb.CreateVector(*ops) : 0; + auto operands__ = operands ? _fbb.CreateVector(*operands) : 0; + return CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::CreateCanvasGeometry( + _fbb, + kind, + a, + b, + combine_mode, + matrix, + source, + geometries__, + fill_rule, + ops__, + operands__, + x, + y, + w, + h, + radius_x, + radius_y); +} + +inline const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::LottieComposition *GetLottieComposition(const void *buf) { + return ::flatbuffers::GetRoot(buf); +} + +inline const CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema::LottieComposition *GetSizePrefixedLottieComposition(const void *buf) { + return ::flatbuffers::GetSizePrefixedRoot(buf); +} + +inline const char *LottieCompositionIdentifier() { + return "LCMP"; +} + +inline bool LottieCompositionBufferHasIdentifier(const void *buf) { + return ::flatbuffers::BufferHasIdentifier( + buf, LottieCompositionIdentifier()); +} + +inline bool SizePrefixedLottieCompositionBufferHasIdentifier(const void *buf) { + return ::flatbuffers::BufferHasIdentifier( + buf, LottieCompositionIdentifier(), true); +} + +inline bool VerifyLottieCompositionBuffer( + ::flatbuffers::Verifier &verifier) { + return verifier.VerifyBuffer(LottieCompositionIdentifier()); +} + +inline bool VerifySizePrefixedLottieCompositionBuffer( + ::flatbuffers::Verifier &verifier) { + return verifier.VerifySizePrefixedBuffer(LottieCompositionIdentifier()); +} + +inline const char *LottieCompositionExtension() { + return "lcomp"; +} + +inline void FinishLottieCompositionBuffer( + ::flatbuffers::FlatBufferBuilder &fbb, + ::flatbuffers::Offset root) { + fbb.Finish(root, LottieCompositionIdentifier()); +} + +inline void FinishSizePrefixedLottieCompositionBuffer( + ::flatbuffers::FlatBufferBuilder &fbb, + ::flatbuffers::Offset root) { + fbb.FinishSizePrefixed(root, LottieCompositionIdentifier()); +} + +} // namespace Schema +} // namespace CompDataFlatbuffer +} // namespace Lottie +} // namespace WinUI +} // namespace CommunityToolkit + +#endif // FLATBUFFERS_GENERATED_LOTTIECOMP_COMMUNITYTOOLKIT_WINUI_LOTTIE_COMPDATAFLATBUFFER_SCHEMA_H_ diff --git a/source/LottieRuntime/LottieRuntime.cpp b/source/LottieRuntime/LottieRuntime.cpp new file mode 100644 index 00000000..1041d478 --- /dev/null +++ b/source/LottieRuntime/LottieRuntime.cpp @@ -0,0 +1,2527 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// A runtime interpreter for serialized Lottie compositions. +// +// This is the native counterpart of Instantiator.cs. It walks the FlatBuffer produced +// by CompositionSerializer and issues the same sequence of Compositor calls that the +// managed instantiator and the generated code issue, so the three produce the same +// visual tree. +// +// Three things shape the code: +// +// * Size first. There is one function per node category rather than one per node +// type, and the shared state of every node is applied by a single function that +// takes the least derived type. Everything lives in one translation unit so that +// the linker can discard what an application does not reach. +// +// * Runtime cost second. Nodes and strings are realized once, then found by indexing +// dense arrays. The FlatBuffer remains the object model. +// +// * Transient memory third. Cache sizes come directly from the buffer. D2D geometry +// remains cached during interpretation so shared subgraphs stay shared. +// +// Calls are made through the least derived interface that has the member being used. +// A node is only ever known by its concrete type inside the function that creates it; +// everywhere else it is held as Visual, CompositionShape, CompositionBrush and so on. +// That is what keeps the interpreter free of casts: there is no point at which it has +// to ask what a node actually is, because the buffer already said, and the answer was +// consumed at the moment of creation. + +// Public SDK interop declarations must use ABI::Windows in every consumer. +#undef BUILD_WINDOWS + +// C++/WinRT requires before projected headers. +#include + +#if defined(LOTTIE_RUNTIME_WINUI2) == defined(LOTTIE_RUNTIME_WINUI3) +#error Define exactly one of LOTTIE_RUNTIME_WINUI2 or LOTTIE_RUNTIME_WINUI3. +#endif + +#include "LottieRuntime.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#undef GetCurrentTime +#if defined(LOTTIE_RUNTIME_WINUI3) +#include +#include +#else +#include +#include +#endif + +#include "Generated/lottie_comp_generated.h" + +namespace Fb = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema; + +using namespace winrt::Windows::Foundation::Numerics; +#if defined(LOTTIE_RUNTIME_WINUI3) +using namespace winrt::Microsoft::UI::Composition; +namespace XamlMedia = winrt::Microsoft::UI::Xaml::Media; +namespace Runtime = CommunityToolkit::WinUI3::Lottie; +#else +using namespace winrt::Windows::UI::Composition; +namespace XamlMedia = winrt::Windows::UI::Xaml::Media; +namespace Runtime = CommunityToolkit::WinUI2::Lottie; +#endif + +namespace +{ + // The index that the format uses for "no node". It is the same value in every + // field that can hold an index. + constexpr uint32_t NullIndex = 0xFFFFFFFFu; + + // The schema version this build understands. A buffer that declares a higher + // version is rejected, because it may use fields that are not read here. + constexpr uint16_t SupportedSchemaVersion = 1; + + // Recursive composition graphs are invalid. Limit nesting even for acyclic + // graphs so a small malicious buffer cannot exhaust the native stack. + constexpr uint32_t MaximumTraversalDepth = 128; + + // Object references that can point at more than one category pack the category + // into the top four bits. + constexpr uint32_t CategoryShift = 28; + constexpr uint32_t IndexMask = (1u << CategoryShift) - 1u; + + [[noreturn]] void ThrowMalformed() + { + throw winrt::hresult_invalid_argument(L"The buffer is not a well formed Lottie composition."); + } + + [[noreturn]] void ThrowUnsupported() + { + throw winrt::hresult_not_implemented(L"The composition uses a feature this build does not support."); + } + + _Post_satisfies_(condition) + void Check(bool condition) + { + if (!condition) + { + ThrowMalformed(); + } + } + + // Reads an entry from one of the buffer's node vectors. A vector that is absent + // is treated as empty, so an index into it is out of range rather than a crash. + template + T const* At(::flatbuffers::Vector<::flatbuffers::Offset> const* vector, uint32_t index) + { + Check(vector != nullptr && index < vector->size()); + auto const* result = vector->Get(index); + Check(result != nullptr); + return result; + } + + float3 ToFloat3(Fb::Vec3 const* value) + { + return { value->x(), value->y(), value->z() }; + } + + float2 ToFloat2(Fb::Vec2 const* value) + { + return { value->x(), value->y() }; + } + + float3x2 ToFloat3x2(Fb::Mat3x2 const* value) + { + return { + value->m11(), value->m12(), + value->m21(), value->m22(), + value->m31(), value->m32(), + }; + } + + float4x4 ToFloat4x4(Fb::Mat4x4 const* value) + { + return { + value->m11(), value->m12(), value->m13(), value->m14(), + value->m21(), value->m22(), value->m23(), value->m24(), + value->m31(), value->m32(), value->m33(), value->m34(), + value->m41(), value->m42(), value->m43(), value->m44(), + }; + } + + winrt::Windows::UI::Color ToColor(Fb::Color const* value) + { + if (value == nullptr) + { + return { 0, 0, 0, 0 }; + } + + return { value->a(), value->r(), value->g(), value->b() }; + } + + // CanvasGeometryCombine and D2D1_COMBINE_MODE do not agree on the order of their + // members, so the value from the buffer cannot simply be cast. + D2D1_COMBINE_MODE ToCombineMode(uint8_t value) + { + switch (value) + { + case 0: return D2D1_COMBINE_MODE_UNION; + case 1: return D2D1_COMBINE_MODE_EXCLUDE; + case 2: return D2D1_COMBINE_MODE_INTERSECT; + case 3: return D2D1_COMBINE_MODE_XOR; + default: ThrowMalformed(); + } + } + + // --------------------------------------------------------------------------- + // Geometry. + // + // A CompositionPath is built from anything that implements IGeometrySource2D, + // and the only way to give one real content is the interop interface that hands + // out a D2D geometry. This is the smallest object that does that. + // --------------------------------------------------------------------------- + struct GeometrySource : winrt::implements + { + GeometrySource(winrt::com_ptr geometry) : + m_geometry(std::move(geometry)) + { + } + + IFACEMETHODIMP GetGeometry(ID2D1Geometry** value) noexcept override + { + m_geometry.copy_to(value); + return S_OK; + } + + IFACEMETHODIMP TryGetGeometryUsingFactory(ID2D1Factory*, ID2D1Geometry** value) noexcept override + { + *value = nullptr; + return E_NOTIMPL; + } + + private: + winrt::com_ptr m_geometry; + }; + + ID2D1Factory* D2DFactory() + { + // One factory for the lifetime of the process. The geometries it makes are + // device independent, so nothing here depends on a device and the factory + // never has to be recreated. + static ID2D1Factory* const factory = [] + { + ID2D1Factory* result = nullptr; + winrt::check_hresult(D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &result)); + return result; + }(); + + return factory; + } + + // --------------------------------------------------------------------------- + // Effects. + // + // Windows.UI.Composition accepts any IGraphicsEffect that also implements the + // D2D interop interface, which is how it learns which D2D effect to instantiate + // and what to set on it. Implementing that directly avoids taking a dependency + // on Win2D for the two effects the translator emits. + // --------------------------------------------------------------------------- + struct Effect : winrt::implements< + Effect, + winrt::Windows::Graphics::Effects::IGraphicsEffect, + winrt::Windows::Graphics::Effects::IGraphicsEffectSource, + ABI::Windows::Graphics::Effects::IGraphicsEffectD2D1Interop> + { + Effect(GUID const& id, winrt::Windows::Foundation::IInspectable property) : + m_id(id), + m_property(std::move(property)) + { + } + + winrt::hstring Name() const noexcept + { + return m_name; + } + + void Name(winrt::hstring const& value) + { + m_name = value; + } + + void AddSource(winrt::Windows::Graphics::Effects::IGraphicsEffectSource const& source) + { + m_sources.push_back(source); + } + + IFACEMETHODIMP GetEffectId(GUID* id) noexcept override + { + *id = m_id; + return S_OK; + } + + IFACEMETHODIMP GetPropertyCount(UINT* count) noexcept override + { + *count = 1; + return S_OK; + } + + IFACEMETHODIMP GetProperty(UINT index, ABI::Windows::Foundation::IPropertyValue** value) noexcept override + { + *value = nullptr; + + if (index != 0) + { + return E_BOUNDS; + } + + auto pv = m_property.try_as(); + if (pv) + { + *value = pv.detach(); + return S_OK; + } + return E_NOINTERFACE; + } + + IFACEMETHODIMP GetSourceCount(UINT* count) noexcept override + { + *count = static_cast(m_sources.size()); + return S_OK; + } + + IFACEMETHODIMP GetSource(UINT index, ABI::Windows::Graphics::Effects::IGraphicsEffectSource** source) noexcept override + { + *source = nullptr; + + if (index >= m_sources.size()) + { + return E_BOUNDS; + } + + auto value = m_sources[index]; + *source = reinterpret_cast( + winrt::detach_abi(value)); + return S_OK; + } + + IFACEMETHODIMP GetNamedPropertyMapping( + LPCWSTR, + UINT*, + ABI::Windows::Graphics::Effects::GRAPHICS_EFFECT_PROPERTY_MAPPING*) noexcept override + { + return E_INVALIDARG; + } + + private: + GUID m_id; + winrt::Windows::Foundation::IInspectable m_property; + winrt::hstring m_name; + std::vector m_sources; + }; +} + +#if defined(LOTTIE_RUNTIME_WINUI3) +namespace CommunityToolkit::WinUI3::Lottie +#else +namespace CommunityToolkit::WinUI2::Lottie +#endif +{ + class CompositionAnimations + { + public: + struct ControllerAnimation + { + winrt::hstring Property; + CompositionAnimation Animation{ nullptr }; + }; + + // One keyframe animation started on a graph object, with how to restart it. + struct Binding + { + CompositionObject Target{ nullptr }; + winrt::hstring Property; + CompositionAnimation Animation{ nullptr }; + + // A custom controller outlives StopAnimation, so it is reused as is. + AnimationController Controller{ nullptr }; + + // An implicit controller is replaced on every StartAnimation, so it is + // realized again from this description. + bool HasImplicitController = false; + bool PauseImplicitController = false; + winrt::hstring ImplicitControllerComment; + std::vector ImplicitControllerAnimations; + }; + + std::vector Bindings; + bool Restartable = true; + bool Running = true; + }; +} + +namespace +{ + // --------------------------------------------------------------------------- + // The interpreter. + // + // One instance exists for the duration of one call to LoadComposition. It owns + // the realization caches, which is the only state the walk needs: every other + // question is answered by the buffer. + // --------------------------------------------------------------------------- + class Interpreter + { + public: + Interpreter( + Compositor const& compositor, + Fb::LottieComposition const& root, + std::span imageSurfaces = {}) : + m_compositor(compositor), + m_root(root), + m_strings(Count(root.strings())), + m_stringCached(Count(root.strings())), + m_visuals(Count(root.visuals()), nullptr), + m_shapes(Count(root.shapes()), nullptr), + m_geometries(Count(root.geometries()), nullptr), + m_paths(Count(root.canvas_geometries()), nullptr), + m_canvasGeometries(Count(root.canvas_geometries())), + m_canvasGeometryStates(Count(root.canvas_geometries())), + m_brushes(Count(root.brushes()), nullptr), + m_gradientStops(Count(root.gradient_stops()), nullptr), + m_viewBoxes(Count(root.view_boxes()), nullptr), + m_clips(Count(root.clips()), nullptr), + m_shadows(Count(root.shadows()), nullptr), + m_surfaces(Count(root.surfaces()), nullptr), + m_effects(Count(root.effects()), nullptr), + m_easings(Count(root.easings()), nullptr), + m_animations(Count(root.animations()), nullptr), + m_propertySets(Count(root.property_sets()), nullptr), + m_controllers(Count(root.controllers()), nullptr) + { + for (auto const& image : imageSurfaces) + { + auto const* source = At(root.surfaces(), image.Index); + Check(source->kind() == Fb::SurfaceKind::LoadedImageFromStream || + source->kind() == Fb::SurfaceKind::LoadedImageFromUri); + Check(image.Surface != nullptr && m_surfaces[image.Index] == nullptr); + Check(image.Surface.try_as() != nullptr); + m_surfaces[image.Index] = image.Surface; + } + } + + Visual Run() + { + auto result = GetVisual(m_root.root_visual()); + Check(result != nullptr); + return result; + } + + Runtime::LoadedComposition RunWithMetadata() + { + auto const* metadata = m_root.metadata(); + if (metadata == nullptr) + { + ThrowMalformed(); + } + Check(std::isfinite(metadata->width()) && metadata->width() >= 0); + Check(std::isfinite(metadata->height()) && metadata->height() >= 0); + Check(metadata->duration_ticks() >= 0); + Check(std::isfinite(metadata->frames_per_second()) && metadata->frames_per_second() >= 0); + + // Check even the metadata string references that are not exposed by this API. + GetString(metadata->name()); + if (auto const* bindings = metadata->property_bindings(); bindings != nullptr) + { + for (uint32_t i = 0; i != bindings->size(); ++i) + { + auto const* binding = At(bindings, i); + Check(binding->name() != NullIndex && binding->display_name() != NullIndex); + GetString(binding->name()); + GetString(binding->display_name()); + Check(binding->actual_type() >= Fb::PropertyValueType::Color && + binding->actual_type() <= Fb::PropertyValueType::Vector4); + Check(binding->exposed_type() >= Fb::PropertyValueType::Color && + binding->exposed_type() <= Fb::PropertyValueType::Vector4); + Check(std::isfinite(binding->default_scalar())); + if (auto const* value = binding->default_vector(); value != nullptr) + { + Check(std::isfinite(value->x()) && std::isfinite(value->y()) && + std::isfinite(value->z()) && std::isfinite(value->w())); + } + } + } + + auto const themeIndex = metadata->theming_property_set(); + if (themeIndex != NullIndex) + { + // Metadata must not expose an object's owned property set as a theme. + Check(At(m_root.property_sets(), themeIndex)->owner() == NullIndex); + } + + Runtime::LoadedComposition result; + result.Duration = winrt::Windows::Foundation::TimeSpan{ metadata->duration_ticks() }; + result.Size = { metadata->width(), metadata->height() }; + result.FramesPerSecond = metadata->frames_per_second(); + if (auto const* markers = metadata->markers(); markers != nullptr) + { + result.Markers.reserve(markers->size()); + for (uint32_t i = 0; i != markers->size(); ++i) + { + auto const* marker = At(markers, i); + Check(marker->name() != NullIndex); + Check(std::isfinite(marker->progress())); + Check(std::isfinite(marker->duration_progress()) && marker->duration_progress() >= 0); + result.Markers.push_back({ + GetString(marker->name()), marker->progress(), marker->duration_progress() }); + } + } + + result.Root = Run(); + if (themeIndex != NullIndex) + { + result.ThemeProperties = GetPropertySet(themeIndex); + } + + for (uint32_t i = 0; i != m_surfaces.size(); ++i) + { + if (m_surfaces[i] != nullptr) + { + auto const kind = At(m_root.surfaces(), i)->kind(); + if (kind == Fb::SurfaceKind::LoadedImageFromStream || + kind == Fb::SurfaceKind::LoadedImageFromUri) + { + result.ImageSurfaces.push_back({ i, m_surfaces[i] }); + } + } + } + + auto animations = std::make_shared(); + animations->Bindings = m_animationBindings; + animations->Restartable = m_animationsRestartable; + result.Animations = std::move(animations); + + return result; + } + + private: + class TraversalGuard + { + public: + explicit TraversalGuard(Interpreter& owner) : + m_owner(owner) + { + Check(m_owner.m_traversalDepth < MaximumTraversalDepth); + ++m_owner.m_traversalDepth; + } + + ~TraversalGuard() + { + --m_owner.m_traversalDepth; + } + + TraversalGuard(TraversalGuard const&) = delete; + TraversalGuard& operator=(TraversalGuard const&) = delete; + + private: + Interpreter& m_owner; + }; + + template + static size_t Count(T const* vector) + { + return vector == nullptr ? 0 : vector->size(); + } + + winrt::hstring GetString(uint32_t index) + { + if (index == NullIndex) + { + return {}; + } + + auto const* strings = m_root.strings(); + if (strings == nullptr || index >= strings->size()) + { + ThrowMalformed(); + } + if (!m_stringCached[index]) + { + auto const* value = strings->Get(index); + if (value == nullptr) + { + ThrowMalformed(); + } + + m_strings[index] = + winrt::to_hstring(std::string_view(value->c_str(), value->size())); + m_stringCached[index] = true; + } + + return m_strings[index]; + } + + // ----------------------------------------------------------------------- + // Shared state. + // + // This is the reason the caches hold base types: everything an interpreter + // does to every node is available on CompositionObject. + // ----------------------------------------------------------------------- + void Initialize(CompositionObject const& target, Fb::CompObj const* source) + { + InitializeProperties(target, source); + StartAnimations(target, source); + } + + void InitializeProperties(CompositionObject const& target, Fb::CompObj const* source) + { + if (source == nullptr) + { + return; + } + + if (auto comment = source->comment(); comment != NullIndex) + { + target.Comment(GetString(comment)); + } + + // The property set is realized through its owner rather than on its own, + // so that a property set and the object that owns it cannot both create + // it. Doing it here also breaks the cycle between the two. + if (auto properties = source->properties(); properties != NullIndex) + { + RealizePropertySet(properties, target.Properties()); + } + + } + + void StartAnimations(CompositionObject const& target, Fb::CompObj const* source) + { + if (source == nullptr) + { + return; + } + + auto const* animators = source->animators(); + if (animators == nullptr) + { + return; + } + + for (uint32_t i = 0; i != animators->size(); ++i) + { + auto const* animator = animators->Get(i); + Check(animator != nullptr); + + auto property = GetString(animator->property()); + auto animation = GetAnimation(animator->animation()); + Check(animation != nullptr); + + auto controllerIndex = animator->controller(); + auto customController = + controllerIndex != NullIndex && IsCustomController(controllerIndex) + ? GetController(controllerIndex) + : nullptr; + + if (customController != nullptr && + animation.try_as() != nullptr) + { + ThrowMalformed(); + } + + if (customController != nullptr) + { + target.StartAnimation(property, animation, customController); + } + else + { + target.StartAnimation(property, animation); + } + + auto const implicitController = controllerIndex != NullIndex && customController == nullptr; + if (implicitController) + { + RealizeController(controllerIndex, target, property); + } + + RecordAnimation(target, property, animation, customController, + implicitController ? controllerIndex : NullIndex); + } + } + + // Records a started keyframe animation so that StopAnimations and StartAnimations + // can replay it. Expression animations, and animations of the controllers + // themselves, are bindings that stay in place, as in LottieGen's generated code. + void RecordAnimation( + CompositionObject const& target, + winrt::hstring const& property, + CompositionAnimation const& animation, + AnimationController const& customController, + uint32_t implicitControllerIndex) + { + if (animation.try_as() != nullptr || + target.try_as() != nullptr) + { + return; + } + + Runtime::CompositionAnimations::Binding binding{ target, property, animation, customController }; + if (implicitControllerIndex != NullIndex) + { + // Each implicit controller must belong to exactly one animation, or a + // restart could not reproduce which animations it paused. + if (m_implicitControllerUsed.empty()) + { + m_implicitControllerUsed.resize(m_controllers.size()); + } + if (m_implicitControllerUsed[implicitControllerIndex]) + { + m_animationsRestartable = false; + } + m_implicitControllerUsed[implicitControllerIndex] = true; + + auto const* source = At(m_root.controllers(), implicitControllerIndex); + binding.HasImplicitController = true; + binding.PauseImplicitController = source->is_paused(); + if (auto const* base = source->base(); base != nullptr) + { + if (base->properties() != NullIndex) + { + // Other expressions may reference the set the first controller owned. + m_animationsRestartable = false; + } + if (auto comment = base->comment(); comment != NullIndex) + { + binding.ImplicitControllerComment = GetString(comment); + } + if (auto const* animators = base->animators(); animators != nullptr) + { + for (uint32_t i = 0; i != animators->size(); ++i) + { + auto const* animator = animators->Get(i); + Check(animator != nullptr); + if (animator->controller() != NullIndex) + { + m_animationsRestartable = false; + } + binding.ImplicitControllerAnimations.push_back({ + GetString(animator->property()), GetAnimation(animator->animation()) }); + } + } + } + } + + m_animationBindings.push_back(std::move(binding)); + } + + bool IsCustomController(uint32_t index) const + { + auto const* controller = At(m_root.controllers(), index); + return controller->is_custom(); + } + + // ----------------------------------------------------------------------- + // Property sets. + // ----------------------------------------------------------------------- + void RealizePropertySet(uint32_t index, CompositionPropertySet const& target) + { + Check(index < m_propertySets.size()); + + if (m_propertySets[index] != nullptr) + { + return; + } + + // Cached before the values are applied, because a value may be an + // expression that refers back to this property set. + m_propertySets[index] = target; + + auto const* source = At(m_root.property_sets(), index); + + if (auto const* values = source->values(); values != nullptr) + { + for (uint32_t i = 0; i != values->size(); ++i) + { + auto const* value = values->Get(i); + Check(value != nullptr); + + auto name = GetString(value->name()); + + switch (value->type()) + { + case Fb::PropertyValueType::Color: + target.InsertColor(name, ToColor(value->color())); + break; + case Fb::PropertyValueType::Scalar: + target.InsertScalar(name, value->scalar()); + break; + case Fb::PropertyValueType::Vector2: + { + auto const* vector = Vector(value); + target.InsertVector2(name, { vector->x(), vector->y() }); + break; + } + case Fb::PropertyValueType::Vector3: + { + auto const* vector = Vector(value); + target.InsertVector3(name, { vector->x(), vector->y(), vector->z() }); + break; + } + case Fb::PropertyValueType::Vector4: + { + auto const* vector = Vector(value); + target.InsertVector4( + name, + { vector->x(), vector->y(), vector->z(), vector->w() }); + break; + } + case Fb::PropertyValueType::None: + break; + default: + ThrowMalformed(); + } + } + } + + StartAnimations(target, source->base()); + } + + static Fb::Vec4 const* Vector(Fb::PropertyValue const* value) + { + auto const* result = value->vector(); + Check(result != nullptr); + return result; + } + + CompositionPropertySet GetPropertySet(uint32_t index) + { + Check(index < m_propertySets.size()); + + if (m_propertySets[index] == nullptr) + { + auto const* source = At(m_root.property_sets(), index); + + if (auto owner = source->owner(); owner != NullIndex) + { + // The owner may be cached while its children are still being + // initialized. A child's expression can reference these properties + // before the owner's InitializeProperties call is reached. + auto target = GetObjectReference(owner); + Check(target != nullptr); + RealizePropertySet(index, target.Properties()); + } + else + { + // A property set with no owner is a standalone one, which is how + // the translator exposes theming properties. + RealizePropertySet(index, m_compositor.CreatePropertySet()); + } + } + + Check(m_propertySets[index] != nullptr); + return m_propertySets[index]; + } + + // ----------------------------------------------------------------------- + // Controllers. + // ----------------------------------------------------------------------- + void RealizeController(uint32_t index, AnimationController const& controller) + { + Check(index < m_controllers.size()); + + if (m_controllers[index] != nullptr) + { + return; + } + + m_controllers[index] = controller; + + auto const* source = At(m_root.controllers(), index); + + if (source->is_paused()) + { + controller.Pause(); + } + + Initialize(controller, source->base()); + } + + void RealizeController( + uint32_t index, + CompositionObject const& target, + winrt::hstring const& property) + { + auto controller = target.TryGetAnimationController(property); + Check(controller != nullptr); + RealizeController(index, controller); + } + + AnimationController GetController(uint32_t index) + { + Check(index < m_controllers.size()); + auto const* source = At(m_root.controllers(), index); + + if (m_controllers[index] == nullptr) + { + if (source->is_custom()) + { + RealizeController(index, m_compositor.CreateAnimationController()); + } + else + { + GetObjectReference(source->target_object()); + } + } + + if (!source->is_custom()) + { + // The reference would outlive the implicit controller a restart replaces. + m_animationsRestartable = false; + } + + Check(m_controllers[index] != nullptr); + return m_controllers[index]; + } + + // ----------------------------------------------------------------------- + // Object references. + // + // Only the three fields that can point at more than one kind of node are + // packed this way, so this is the only place a category has to be decoded. + // ----------------------------------------------------------------------- + CompositionObject GetObjectReference(uint32_t reference) + { + if (reference == NullIndex) + { + return nullptr; + } + + auto const index = reference & IndexMask; + + switch (static_cast(reference >> CategoryShift)) + { + case Fb::ObjectCategory::Visual: return GetVisual(index); + case Fb::ObjectCategory::Shape: return GetShape(index); + case Fb::ObjectCategory::Geometry: return GetGeometry(index); + case Fb::ObjectCategory::Brush: return GetBrush(index); + case Fb::ObjectCategory::Animation: return GetAnimation(index); + case Fb::ObjectCategory::Easing: return GetEasing(index); + case Fb::ObjectCategory::PropertySet: return GetPropertySet(index); + case Fb::ObjectCategory::Clip: return GetClip(index); + case Fb::ObjectCategory::Shadow: return GetShadow(index); + case Fb::ObjectCategory::GradientStop: return GetGradientStop(index); + case Fb::ObjectCategory::ViewBox: return GetViewBox(index); + case Fb::ObjectCategory::Surface: + { + // Only a visual surface is a CompositionObject; an image surface is + // not, and nothing can legitimately reference one this way. + auto surface = GetSurface(index); + auto result = surface.try_as(); + Check(result != nullptr); + return result; + } + case Fb::ObjectCategory::Controller: return GetController(index); + default: + ThrowMalformed(); + } + } + + // ----------------------------------------------------------------------- + // Visuals. + // ----------------------------------------------------------------------- + Visual GetVisual(uint32_t index) + { + if (index == NullIndex) + { + return nullptr; + } + + Check(index < m_visuals.size()); + + if (m_visuals[index] != nullptr) + { + return m_visuals[index]; + } + + TraversalGuard const traversalGuard(*this); + auto const* source = At(m_root.visuals(), index); + + // The concrete type is known only here. Everything below this point, + // including the recursive walk into the children, uses the base type. + ContainerVisual container{ nullptr }; + + switch (source->kind()) + { + case Fb::VisualKind::Container: + container = m_compositor.CreateContainerVisual(); + break; + case Fb::VisualKind::Sprite: + { + auto sprite = m_compositor.CreateSpriteVisual(); + m_visuals[index] = sprite; + if (auto brush = source->brush(); brush != NullIndex) + { + sprite.Brush(GetBrush(brush)); + } + + if (auto shadow = source->shadow(); shadow != NullIndex) + { + sprite.Shadow(GetShadow(shadow)); + } + + container = sprite; + break; + } + case Fb::VisualKind::Shape: + { + auto shapeVisual = m_compositor.CreateShapeVisual(); + m_visuals[index] = shapeVisual; + + if (auto viewBox = source->view_box(); viewBox != NullIndex) + { + shapeVisual.ViewBox(GetViewBox(viewBox)); + } + + if (auto const* shapes = source->shapes(); shapes != nullptr) + { + auto collection = shapeVisual.Shapes(); + for (uint32_t i = 0; i != shapes->size(); ++i) + { + auto shape = GetShape(shapes->Get(i)); + Check(shape != nullptr); + collection.Append(shape); + } + } + + container = shapeVisual; + break; + } + case Fb::VisualKind::Layer: + { + auto layer = m_compositor.CreateLayerVisual(); + m_visuals[index] = layer; + + if (auto shadow = source->shadow(); shadow != NullIndex) + { + layer.Shadow(GetShadow(shadow)); + } + + container = layer; + break; + } + default: + ThrowMalformed(); + } + + // Any case that resolves referenced objects must populate m_visuals + // first. The assignment below only precedes the child walk. + // Cached before the children are walked, so that a cycle terminates. + m_visuals[index] = container; + + ApplyVisualProperties(container, source); + InitializeProperties(container, source->base()); + + if (auto const* children = source->children(); children != nullptr) + { + auto collection = container.Children(); + for (uint32_t i = 0; i != children->size(); ++i) + { + auto child = GetVisual(children->Get(i)); + Check(child != nullptr); + collection.InsertAtTop(child); + } + } + + StartAnimations(container, source->base()); + + return container; + } + + // Takes a Visual rather than any of the four concrete kinds, because every + // property here is declared on Visual. + void ApplyVisualProperties(Visual const& target, Fb::Visual const* source) + { + if (auto value = source->border_mode()) + { + target.BorderMode(static_cast(*value)); + } + + if (auto const* value = source->center_point()) + { + target.CenterPoint(ToFloat3(value)); + } + + if (auto value = source->clip(); value != NullIndex) + { + target.Clip(GetClip(value)); + } + + if (auto value = source->is_visible()) + { + target.IsVisible(*value); + } + + if (auto const* value = source->offset()) + { + target.Offset(ToFloat3(value)); + } + + if (auto value = source->opacity()) + { + target.Opacity(*value); + } + + if (auto value = source->rotation_angle_in_degrees()) + { + target.RotationAngleInDegrees(*value); + } + + if (auto const* value = source->rotation_axis()) + { + target.RotationAxis(ToFloat3(value)); + } + + if (auto const* value = source->scale()) + { + target.Scale(ToFloat3(value)); + } + + if (auto const* value = source->size()) + { + target.Size(ToFloat2(value)); + } + + if (auto const* value = source->transform_matrix()) + { + target.TransformMatrix(ToFloat4x4(value)); + } + } + + // ----------------------------------------------------------------------- + // Shapes. + // ----------------------------------------------------------------------- + CompositionShape GetShape(uint32_t index) + { + if (index == NullIndex) + { + return nullptr; + } + + Check(index < m_shapes.size()); + + if (m_shapes[index] != nullptr) + { + return m_shapes[index]; + } + + TraversalGuard const traversalGuard(*this); + auto const* source = At(m_root.shapes(), index); + + CompositionShape result{ nullptr }; + + switch (source->kind()) + { + case Fb::ShapeKind::Container: + { + auto container = m_compositor.CreateContainerShape(); + m_shapes[index] = container; + + if (auto const* shapes = source->shapes(); shapes != nullptr) + { + auto collection = container.Shapes(); + for (uint32_t i = 0; i != shapes->size(); ++i) + { + auto shape = GetShape(shapes->Get(i)); + Check(shape != nullptr); + collection.Append(shape); + } + } + + result = container; + break; + } + case Fb::ShapeKind::Sprite: + { + auto sprite = m_compositor.CreateSpriteShape(); + m_shapes[index] = sprite; + ApplySpriteShapeProperties(sprite, source); + result = sprite; + break; + } + default: + ThrowMalformed(); + } + + // Any case that resolves referenced objects must populate m_shapes + // first. The assignment below cannot terminate recursive graphs. + m_shapes[index] = result; + + ApplyShapeProperties(result, source); + Initialize(result, source->base()); + + return result; + } + + void ApplyShapeProperties(CompositionShape const& target, Fb::Shape const* source) + { + if (auto const* value = source->center_point()) + { + target.CenterPoint(ToFloat2(value)); + } + + if (auto const* value = source->offset()) + { + target.Offset(ToFloat2(value)); + } + + if (auto value = source->rotation_angle_in_degrees()) + { + target.RotationAngleInDegrees(*value); + } + + if (auto const* value = source->scale()) + { + target.Scale(ToFloat2(value)); + } + + if (auto const* value = source->transform_matrix()) + { + target.TransformMatrix(ToFloat3x2(value)); + } + } + + void ApplySpriteShapeProperties(CompositionSpriteShape const& target, Fb::Shape const* source) + { + if (auto value = source->geometry(); value != NullIndex) + { + target.Geometry(GetGeometry(value)); + } + + if (auto value = source->fill_brush(); value != NullIndex) + { + target.FillBrush(GetBrush(value)); + } + + if (auto value = source->stroke_brush(); value != NullIndex) + { + target.StrokeBrush(GetBrush(value)); + } + + if (auto value = source->is_stroke_non_scaling()) + { + target.IsStrokeNonScaling(*value); + } + + if (auto value = source->stroke_dash_offset()) + { + target.StrokeDashOffset(*value); + } + + if (auto const* values = source->stroke_dash_array(); values != nullptr) + { + auto dashes = target.StrokeDashArray(); + for (uint32_t i = 0; i != values->size(); ++i) + { + dashes.Append(values->Get(i)); + } + } + + if (auto value = source->stroke_dash_cap()) + { + target.StrokeDashCap(static_cast(*value)); + } + + if (auto value = source->stroke_start_cap()) + { + target.StrokeStartCap(static_cast(*value)); + } + + if (auto value = source->stroke_end_cap()) + { + target.StrokeEndCap(static_cast(*value)); + } + + if (auto value = source->stroke_line_join()) + { + target.StrokeLineJoin(static_cast(*value)); + } + + if (auto value = source->stroke_miter_limit()) + { + target.StrokeMiterLimit(static_cast(*value)); + } + + if (auto value = source->stroke_thickness()) + { + target.StrokeThickness(*value); + } + } + + // ----------------------------------------------------------------------- + // Geometries. + // ----------------------------------------------------------------------- + CompositionGeometry GetGeometry(uint32_t index) + { + if (index == NullIndex) + { + return nullptr; + } + + Check(index < m_geometries.size()); + + if (m_geometries[index] != nullptr) + { + return m_geometries[index]; + } + + auto const* source = At(m_root.geometries(), index); + + CompositionGeometry result{ nullptr }; + + switch (source->kind()) + { + case Fb::GeometryKind::Path: + { + auto path = source->path(); + result = m_compositor.CreatePathGeometry( + path == NullIndex ? nullptr : GetPath(path)); + break; + } + case Fb::GeometryKind::Rectangle: + { + auto rectangle = m_compositor.CreateRectangleGeometry(); + if (auto const* value = source->offset()) + { + rectangle.Offset(ToFloat2(value)); + } + + if (auto const* value = source->size()) + { + rectangle.Size(ToFloat2(value)); + } + + result = rectangle; + break; + } + case Fb::GeometryKind::RoundedRectangle: + { + auto rounded = m_compositor.CreateRoundedRectangleGeometry(); + if (auto const* value = source->offset()) + { + rounded.Offset(ToFloat2(value)); + } + + if (auto const* value = source->size()) + { + rounded.Size(ToFloat2(value)); + } + + if (auto const* value = source->corner_radius()) + { + rounded.CornerRadius(ToFloat2(value)); + } + + result = rounded; + break; + } + case Fb::GeometryKind::Ellipse: + { + auto ellipse = m_compositor.CreateEllipseGeometry(); + if (auto const* value = source->center()) + { + ellipse.Center(ToFloat2(value)); + } + + if (auto const* value = source->radius()) + { + ellipse.Radius(ToFloat2(value)); + } + + result = ellipse; + break; + } + default: + ThrowMalformed(); + } + + m_geometries[index] = result; + + if (auto value = source->trim_start()) + { + result.TrimStart(*value); + } + + if (auto value = source->trim_end()) + { + result.TrimEnd(*value); + } + + if (auto value = source->trim_offset()) + { + result.TrimOffset(*value); + } + + Initialize(result, source->base()); + + return result; + } + + // ----------------------------------------------------------------------- + // Paths. + // + // A path is not a CompositionObject, so it has no shared state and no + // animators; it is only ever a value. + // ----------------------------------------------------------------------- + CompositionPath GetPath(uint32_t index) + { + Check(index < m_paths.size()); + + if (m_paths[index] == nullptr) + { + auto geometry = BuildGeometry(index); + m_paths[index] = CompositionPath(winrt::make(std::move(geometry))); + } + + return m_paths[index]; + } + + winrt::com_ptr BuildGeometry(uint32_t index) + { + Check(index < m_canvasGeometries.size()); + + switch (m_canvasGeometryStates[index]) + { + case CanvasGeometryState::Realized: + return m_canvasGeometries[index]; + case CanvasGeometryState::Realizing: + ThrowMalformed(); + case CanvasGeometryState::Unrealized: + break; + } + + TraversalGuard const traversalGuard(*this); + m_canvasGeometryStates[index] = CanvasGeometryState::Realizing; + auto result = BuildGeometryCore(index); + Check(result != nullptr); + m_canvasGeometries[index] = result; + m_canvasGeometryStates[index] = CanvasGeometryState::Realized; + return result; + } + + winrt::com_ptr BuildGeometryCore(uint32_t index) + { + auto const* source = At(m_root.canvas_geometries(), index); + + switch (source->kind()) + { + case Fb::CanvasGeometryKind::Combination: + { + auto a = BuildGeometry(Required(source->a())); + auto b = BuildGeometry(Required(source->b())); + + winrt::com_ptr result; + winrt::check_hresult(D2DFactory()->CreatePathGeometry(result.put())); + + winrt::com_ptr sink; + winrt::check_hresult(result->Open(sink.put())); + + auto const matrix = source->matrix(); + auto const transform = matrix == nullptr + ? D2D1::Matrix3x2F::Identity() + : D2D1::Matrix3x2F( + matrix->m11(), matrix->m12(), + matrix->m21(), matrix->m22(), + matrix->m31(), matrix->m32()); + + winrt::check_hresult(a->CombineWithGeometry( + b.get(), + ToCombineMode(source->combine_mode()), + transform, + sink.get())); + + winrt::check_hresult(sink->Close()); + return result; + } + case Fb::CanvasGeometryKind::Ellipse: + { + winrt::com_ptr result; + winrt::check_hresult(D2DFactory()->CreateEllipseGeometry( + D2D1::Ellipse( + D2D1::Point2F(source->x(), source->y()), + source->radius_x(), + source->radius_y()), + result.put())); + return result; + } + case Fb::CanvasGeometryKind::RoundedRectangle: + { + winrt::com_ptr result; + winrt::check_hresult(D2DFactory()->CreateRoundedRectangleGeometry( + D2D1::RoundedRect( + D2D1::RectF( + source->x(), + source->y(), + source->x() + source->w(), + source->y() + source->h()), + source->radius_x(), + source->radius_y()), + result.put())); + return result; + } + case Fb::CanvasGeometryKind::TransformedGeometry: + { + auto inner = BuildGeometry(Required(source->source())); + + auto const* matrix = source->matrix(); + Check(matrix != nullptr); + + winrt::com_ptr result; + winrt::check_hresult(D2DFactory()->CreateTransformedGeometry( + inner.get(), + D2D1::Matrix3x2F( + matrix->m11(), matrix->m12(), + matrix->m21(), matrix->m22(), + matrix->m31(), matrix->m32()), + result.put())); + return result; + } + case Fb::CanvasGeometryKind::Group: + { + auto const* geometries = source->geometries(); + Check(geometries != nullptr); + + std::vector> owned; + std::vector raw; + owned.reserve(geometries->size()); + raw.reserve(geometries->size()); + + for (uint32_t i = 0; i != geometries->size(); ++i) + { + owned.push_back(BuildGeometry(geometries->Get(i))); + raw.push_back(owned.back().get()); + } + + winrt::com_ptr result; + winrt::check_hresult(D2DFactory()->CreateGeometryGroup( + static_cast(source->fill_rule()), + raw.data(), + static_cast(raw.size()), + result.put())); + return result; + } + case Fb::CanvasGeometryKind::Path: + return BuildPath(source); + default: + ThrowMalformed(); + } + } + + // Replays the flattened command stream. The operands of every command are + // consecutive in one array, which is why there is no table per command. + winrt::com_ptr BuildPath(Fb::CanvasGeometry const* source) + { + winrt::com_ptr result; + winrt::check_hresult(D2DFactory()->CreatePathGeometry(result.put())); + + winrt::com_ptr sink; + winrt::check_hresult(result->Open(sink.put())); + + sink->SetFillMode(static_cast(source->fill_rule())); + + auto const* ops = source->ops(); + auto const* operands = source->operands(); + + uint32_t next = 0; + bool inFigure = false; + + auto take = [&](uint32_t count) -> float const* + { + Check(operands != nullptr && next + count <= operands->size()); + auto const* values = operands->data() + next; + next += count; + return values; + }; + + for (uint32_t i = 0; ops != nullptr && i != ops->size(); ++i) + { + switch (static_cast(ops->Get(i))) + { + case Fb::PathOp::BeginFigure: + { + Check(!inFigure); + auto const* v = take(2); + + // Every figure the translator emits is filled; a hollow figure + // would need a begin flag in the format, which it does not have + // because the object model has no way to express one. + sink->BeginFigure(D2D1::Point2F(v[0], v[1]), D2D1_FIGURE_BEGIN_FILLED); + inFigure = true; + break; + } + case Fb::PathOp::EndFigure: + { + Check(inFigure); + auto const* v = take(1); + sink->EndFigure(v[0] != 0 ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN); + inFigure = false; + break; + } + case Fb::PathOp::AddLine: + { + Check(inFigure); + auto const* v = take(2); + sink->AddLine(D2D1::Point2F(v[0], v[1])); + break; + } + case Fb::PathOp::AddCubicBezier: + { + Check(inFigure); + auto const* v = take(6); + sink->AddBezier(D2D1::BezierSegment( + D2D1::Point2F(v[0], v[1]), + D2D1::Point2F(v[2], v[3]), + D2D1::Point2F(v[4], v[5]))); + break; + } + default: + ThrowMalformed(); + } + } + + Check(!inFigure); + winrt::check_hresult(sink->Close()); + + return result; + } + + static uint32_t Required(uint32_t index) + { + Check(index != NullIndex); + return index; + } + + // ----------------------------------------------------------------------- + // Brushes. + // ----------------------------------------------------------------------- + CompositionBrush GetBrush(uint32_t index) + { + if (index == NullIndex) + { + return nullptr; + } + + Check(index < m_brushes.size()); + + if (m_brushes[index] != nullptr) + { + return m_brushes[index]; + } + + auto const* source = At(m_root.brushes(), index); + + CompositionBrush result{ nullptr }; + + switch (source->kind()) + { + case Fb::BrushKind::Color: + result = m_compositor.CreateColorBrush(ToColor(source->color())); + break; + case Fb::BrushKind::LinearGradient: + { + auto brush = m_compositor.CreateLinearGradientBrush(); + m_brushes[index] = brush; + + if (auto const* value = source->start_point()) + { + brush.StartPoint(ToFloat2(value)); + } + + if (auto const* value = source->end_point()) + { + brush.EndPoint(ToFloat2(value)); + } + + ApplyGradientBrushProperties(brush, source); + result = brush; + break; + } + case Fb::BrushKind::RadialGradient: + { + auto brush = m_compositor.CreateRadialGradientBrush(); + m_brushes[index] = brush; + + if (auto const* value = source->ellipse_center()) + { + brush.EllipseCenter(ToFloat2(value)); + } + + if (auto const* value = source->ellipse_radius()) + { + brush.EllipseRadius(ToFloat2(value)); + } + + if (auto const* value = source->gradient_origin_offset()) + { + brush.GradientOriginOffset(ToFloat2(value)); + } + + ApplyGradientBrushProperties(brush, source); + result = brush; + break; + } + case Fb::BrushKind::Surface: + result = m_compositor.CreateSurfaceBrush(GetSurface(Required(source->surface()))); + break; + case Fb::BrushKind::Mask: + { + auto brush = m_compositor.CreateMaskBrush(); + m_brushes[index] = brush; + brush.Source(GetBrush(source->source())); + brush.Mask(GetBrush(source->mask())); + result = brush; + break; + } + case Fb::BrushKind::Effect: + { + auto effect = GetEffect(Required(source->effect())); + auto brush = m_compositor.CreateEffectFactory(effect).CreateBrush(); + m_brushes[index] = brush; + + if (auto const* parameters = source->source_parameters(); parameters != nullptr) + { + for (uint32_t i = 0; i != parameters->size(); ++i) + { + auto const* parameter = parameters->Get(i); + Check(parameter != nullptr); + brush.SetSourceParameter( + GetString(parameter->name()), + GetBrush(parameter->brush())); + } + } + + result = brush; + break; + } + default: + ThrowMalformed(); + } + + // Any case that resolves referenced objects must populate m_brushes + // first. The assignment below cannot terminate recursive graphs. + m_brushes[index] = result; + + Initialize(result, source->base()); + + return result; + } + + void ApplyGradientBrushProperties(CompositionGradientBrush const& target, Fb::Brush const* source) + { + if (auto const* value = source->anchor_point()) + { + target.AnchorPoint(ToFloat2(value)); + } + + if (auto const* value = source->center_point()) + { + target.CenterPoint(ToFloat2(value)); + } + + if (auto value = source->extend_mode()) + { + target.ExtendMode(static_cast(*value)); + } + + if (auto value = source->interpolation_space()) + { + target.InterpolationSpace(static_cast(*value)); + } + + if (auto value = source->mapping_mode()) + { + target.MappingMode(static_cast(*value)); + } + + if (auto const* value = source->offset()) + { + target.Offset(ToFloat2(value)); + } + + if (auto value = source->rotation_angle_in_degrees()) + { + target.RotationAngleInDegrees(*value); + } + + if (auto const* value = source->scale()) + { + target.Scale(ToFloat2(value)); + } + + if (auto const* value = source->transform_matrix()) + { + target.TransformMatrix(ToFloat3x2(value)); + } + + if (auto const* stops = source->color_stops(); stops != nullptr) + { + auto collection = target.ColorStops(); + for (uint32_t i = 0; i != stops->size(); ++i) + { + collection.Append(GetGradientStop(stops->Get(i))); + } + } + } + + CompositionColorGradientStop GetGradientStop(uint32_t index) + { + Check(index < m_gradientStops.size()); + + if (m_gradientStops[index] == nullptr) + { + auto const* source = At(m_root.gradient_stops(), index); + + auto stop = m_compositor.CreateColorGradientStop( + source->offset(), + ToColor(source->color())); + + m_gradientStops[index] = stop; + Initialize(stop, source->base()); + } + + return m_gradientStops[index]; + } + + // ----------------------------------------------------------------------- + // Clips, view boxes, shadows and surfaces. + // ----------------------------------------------------------------------- + CompositionClip GetClip(uint32_t index) + { + Check(index < m_clips.size()); + + if (m_clips[index] != nullptr) + { + return m_clips[index]; + } + + auto const* source = At(m_root.clips(), index); + + CompositionClip result{ nullptr }; + + switch (source->kind()) + { + case Fb::ClipKind::Inset: + { + auto clip = m_compositor.CreateInsetClip(); + + if (auto value = source->left_inset()) + { + clip.LeftInset(*value); + } + + if (auto value = source->right_inset()) + { + clip.RightInset(*value); + } + + if (auto value = source->top_inset()) + { + clip.TopInset(*value); + } + + if (auto value = source->bottom_inset()) + { + clip.BottomInset(*value); + } + + result = clip; + break; + } + case Fb::ClipKind::Geometric: + { + auto clip = m_compositor.CreateGeometricClip(); + m_clips[index] = clip; + clip.Geometry(GetGeometry(source->geometry())); + result = clip; + break; + } + default: + ThrowMalformed(); + } + + // Any case that resolves referenced objects must populate m_clips + // first. The assignment below cannot terminate recursive graphs. + m_clips[index] = result; + + if (auto const* value = source->center_point()) + { + result.CenterPoint(ToFloat2(value)); + } + + if (auto const* value = source->scale()) + { + result.Scale(ToFloat2(value)); + } + + Initialize(result, source->base()); + + return result; + } + + CompositionViewBox GetViewBox(uint32_t index) + { + Check(index < m_viewBoxes.size()); + + if (m_viewBoxes[index] == nullptr) + { + auto const* source = At(m_root.view_boxes(), index); + + auto viewBox = m_compositor.CreateViewBox(); + m_viewBoxes[index] = viewBox; + + if (auto const* value = source->size()) + { + viewBox.Size(ToFloat2(value)); + } + + Initialize(viewBox, source->base()); + } + + return m_viewBoxes[index]; + } + + CompositionShadow GetShadow(uint32_t index) + { + Check(index < m_shadows.size()); + + if (m_shadows[index] != nullptr) + { + return m_shadows[index]; + } + + auto const* source = At(m_root.shadows(), index); + Check(source->kind() == Fb::ShadowKind::Drop); + + auto shadow = m_compositor.CreateDropShadow(); + m_shadows[index] = shadow; + + if (auto value = source->blur_radius()) + { + shadow.BlurRadius(*value); + } + + if (auto const* value = source->color()) + { + shadow.Color(ToColor(value)); + } + + if (auto mask = source->mask(); mask != NullIndex) + { + shadow.Mask(GetBrush(mask)); + } + + if (auto const* value = source->offset()) + { + shadow.Offset(ToFloat3(value)); + } + + if (auto value = source->opacity()) + { + shadow.Opacity(*value); + } + + if (auto value = source->source_policy()) + { + shadow.SourcePolicy(static_cast(*value)); + } + + Initialize(shadow, source->base()); + + return shadow; + } + + ICompositionSurface GetSurface(uint32_t index) + { + Check(index < m_surfaces.size()); + + if (m_surfaces[index] != nullptr) + { + return m_surfaces[index]; + } + + auto const* source = At(m_root.surfaces(), index); + + switch (source->kind()) + { + case Fb::SurfaceKind::VisualSurface: + { + auto surface = m_compositor.CreateVisualSurface(); + m_surfaces[index] = surface; + + if (auto value = source->source_visual(); value != NullIndex) + { + surface.SourceVisual(GetVisual(value)); + } + + if (auto const* value = source->source_size()) + { + surface.SourceSize(ToFloat2(value)); + } + + if (auto const* value = source->source_offset()) + { + surface.SourceOffset(ToFloat2(value)); + } + + Initialize(surface, source->base()); + break; + } + case Fb::SurfaceKind::LoadedImageFromUri: + { + auto const uri = source->uri(); + Check(uri != NullIndex); + m_surfaces[index] = + XamlMedia::LoadedImageSurface::StartLoadFromUri( + winrt::Windows::Foundation::Uri(GetString(uri))); + break; + } + case Fb::SurfaceKind::LoadedImageFromStream: + { + auto const* bytes = source->bytes(); + Check(bytes != nullptr); + + winrt::com_ptr byteStream; + byteStream.attach(SHCreateMemStream(bytes->data(), bytes->size())); + Check(byteStream != nullptr); + + winrt::Windows::Storage::Streams::IRandomAccessStream stream{ nullptr }; + winrt::check_hresult(CreateRandomAccessStreamOverStream( + byteStream.get(), + BSOS_DEFAULT, + winrt::guid_of(), + winrt::put_abi(stream))); + + m_surfaces[index] = + XamlMedia::LoadedImageSurface::StartLoadFromStream( + stream); + break; + } + default: + ThrowMalformed(); + } + + return m_surfaces[index]; + } + + winrt::Windows::Graphics::Effects::IGraphicsEffect GetEffect(uint32_t index) + { + Check(index < m_effects.size()); + + if (m_effects[index] != nullptr) + { + return m_effects[index]; + } + + auto const* source = At(m_root.effects(), index); + + winrt::com_ptr effect; + + switch (source->kind()) + { + case Fb::EffectKind::Composite: + // CanvasComposite and D2D1_COMPOSITE_MODE agree on every member, so + // the mode from the buffer is the D2D value. + effect = winrt::make_self( + CLSID_D2D1Composite, + winrt::box_value(static_cast(source->mode()))); + break; + case Fb::EffectKind::GaussianBlur: + effect = winrt::make_self( + CLSID_D2D1GaussianBlur, + winrt::box_value(source->blur_amount())); + break; + default: + ThrowMalformed(); + } + + // The sources are the names the brush later binds real brushes to. The + // composition engine matches them up by name. + if (auto const* sources = source->sources(); sources != nullptr) + { + for (uint32_t i = 0; i != sources->size(); ++i) + { + effect->AddSource(CompositionEffectSourceParameter(GetString(sources->Get(i)))); + } + } + + auto result = effect.as(); + m_effects[index] = result; + return result; + } + + // ----------------------------------------------------------------------- + // Easings. + // ----------------------------------------------------------------------- + CompositionEasingFunction GetEasing(uint32_t index) + { + if (index == NullIndex) + { + return nullptr; + } + + Check(index < m_easings.size()); + + if (m_easings[index] != nullptr) + { + return m_easings[index]; + } + + auto const* source = At(m_root.easings(), index); + + CompositionEasingFunction result{ nullptr }; + + switch (source->kind()) + { + case Fb::EasingKind::Linear: + result = m_compositor.CreateLinearEasingFunction(); + break; + case Fb::EasingKind::CubicBezier: + { + auto const* first = source->control_point_1(); + auto const* second = source->control_point_2(); + result = m_compositor.CreateCubicBezierEasingFunction( + first == nullptr ? float2{ 0, 0 } : ToFloat2(first), + second == nullptr ? float2{ 0, 0 } : ToFloat2(second)); + break; + } + case Fb::EasingKind::Step: + { + auto stepCount = source->step_count(); + auto step = m_compositor.CreateStepEasingFunction( + stepCount ? *stepCount : 1); + + if (auto value = source->initial_step()) + { + step.InitialStep(*value); + } + + if (auto value = source->final_step()) + { + step.FinalStep(*value); + } + + if (auto value = source->is_initial_step_single_frame()) + { + step.IsInitialStepSingleFrame(*value); + } + + if (auto value = source->is_final_step_single_frame()) + { + step.IsFinalStepSingleFrame(*value); + } + + result = step; + break; + } + default: + ThrowMalformed(); + } + + m_easings[index] = result; + Initialize(result, source->base()); + + return result; + } + + // ----------------------------------------------------------------------- + // Animations. + // ----------------------------------------------------------------------- + CompositionAnimation GetAnimation(uint32_t index) + { + if (index == NullIndex) + { + return nullptr; + } + + Check(index < m_animations.size()); + + if (m_animations[index] != nullptr) + { + return m_animations[index]; + } + + auto const* source = At(m_root.animations(), index); + + CompositionAnimation result = source->kind() == Fb::AnimationKind::Expression + ? CreateExpressionAnimation(source) + : CreateKeyFrameAnimation(source); + + m_animations[index] = result; + + if (auto target = source->target(); target != NullIndex) + { + result.Target(GetString(target)); + } + + if (auto const* parameters = source->reference_parameters(); parameters != nullptr) + { + for (uint32_t i = 0; i != parameters->size(); ++i) + { + auto const* parameter = parameters->Get(i); + Check(parameter != nullptr); + + auto value = GetObjectReference(parameter->target()); + Check(value != nullptr); + result.SetReferenceParameter(GetString(parameter->name()), value); + } + } + + Initialize(result, source->base()); + + return result; + } + + CompositionAnimation CreateExpressionAnimation(Fb::Animation const* source) + { + return m_compositor.CreateExpressionAnimation(GetString(Required(source->expression()))); + } + + // Creates the animation and inserts its key frames in one place, because the + // concrete type is only needed in order to insert a value key frame and it + // would otherwise have to be recovered with a cast. + CompositionAnimation CreateKeyFrameAnimation(Fb::Animation const* source) + { + auto const* frames = source->key_frames(); + + KeyFrameAnimation result{ nullptr }; + + switch (source->kind()) + { + case Fb::AnimationKind::Scalar: + { + auto animation = m_compositor.CreateScalarKeyFrameAnimation(); + ForEachValueKeyFrame(frames, [&](Fb::KeyFrame const* frame) + { + animation.InsertKeyFrame(frame->progress(), frame->scalar(), GetEasing(frame->easing())); + }); + result = animation; + break; + } + case Fb::AnimationKind::Vector2: + { + auto animation = m_compositor.CreateVector2KeyFrameAnimation(); + ForEachValueKeyFrame(frames, [&](Fb::KeyFrame const* frame) + { + auto const* v = RequireVector(frame); + animation.InsertKeyFrame(frame->progress(), { v->x(), v->y() }, GetEasing(frame->easing())); + }); + result = animation; + break; + } + case Fb::AnimationKind::Vector3: + { + auto animation = m_compositor.CreateVector3KeyFrameAnimation(); + ForEachValueKeyFrame(frames, [&](Fb::KeyFrame const* frame) + { + auto const* v = RequireVector(frame); + animation.InsertKeyFrame(frame->progress(), { v->x(), v->y(), v->z() }, GetEasing(frame->easing())); + }); + result = animation; + break; + } + case Fb::AnimationKind::Vector4: + { + auto animation = m_compositor.CreateVector4KeyFrameAnimation(); + ForEachValueKeyFrame(frames, [&](Fb::KeyFrame const* frame) + { + auto const* v = RequireVector(frame); + animation.InsertKeyFrame(frame->progress(), { v->x(), v->y(), v->z(), v->w() }, GetEasing(frame->easing())); + }); + result = animation; + break; + } + case Fb::AnimationKind::Color: + { + auto animation = m_compositor.CreateColorKeyFrameAnimation(); + + if (auto value = source->interpolation_color_space()) + { + animation.InterpolationColorSpace(static_cast(*value)); + } + + ForEachValueKeyFrame(frames, [&](Fb::KeyFrame const* frame) + { + animation.InsertKeyFrame(frame->progress(), ToColor(frame->color()), GetEasing(frame->easing())); + }); + result = animation; + break; + } + case Fb::AnimationKind::Boolean: + { + auto animation = m_compositor.CreateBooleanKeyFrameAnimation(); + + // A boolean cannot be interpolated, so it has no easing. + ForEachValueKeyFrame(frames, [&](Fb::KeyFrame const* frame) + { + animation.InsertKeyFrame(frame->progress(), frame->scalar() != 0); + }); + result = animation; + break; + } + case Fb::AnimationKind::Path: + { + auto animation = m_compositor.CreatePathKeyFrameAnimation(); + ForEachValueKeyFrame(frames, [&](Fb::KeyFrame const* frame) + { + animation.InsertKeyFrame(frame->progress(), GetPath(Required(frame->path())), GetEasing(frame->easing())); + }); + result = animation; + break; + } + default: + ThrowMalformed(); + } + + // Expression key frames are inserted through the base type, so they do + // not have to be repeated in every branch above. They are inserted after + // the value key frames, which is safe because a key frame animation is a + // map keyed on progress rather than a list. + if (frames != nullptr) + { + for (uint32_t i = 0; i != frames->size(); ++i) + { + auto const* frame = frames->Get(i); + Check(frame != nullptr); + + if (frame->kind() == Fb::KeyFrameKind::Expression) + { + result.InsertExpressionKeyFrame( + frame->progress(), + GetString(Required(frame->expression())), + GetEasing(frame->easing())); + } + } + } + + if (auto ticks = source->duration_ticks(); ticks != 0) + { + result.Duration(winrt::Windows::Foundation::TimeSpan{ ticks }); + } + + return result; + } + + template + void ForEachValueKeyFrame(::flatbuffers::Vector<::flatbuffers::Offset> const* frames, F&& apply) + { + if (frames == nullptr) + { + return; + } + + for (uint32_t i = 0; i != frames->size(); ++i) + { + auto const* frame = frames->Get(i); + Check(frame != nullptr); + + if (frame->kind() == Fb::KeyFrameKind::Value) + { + apply(frame); + } + } + } + + static Fb::Vec4 const* RequireVector(Fb::KeyFrame const* frame) + { + auto const* result = frame->vector(); + Check(result != nullptr); + return result; + } + + Compositor const& m_compositor; + Fb::LottieComposition const& m_root; + + enum class CanvasGeometryState : uint8_t + { + Unrealized, + Realizing, + Realized, + }; + + // The caches. Each is exactly as long as the matching vector in the buffer, + // so a lookup is a bounds check and an index. Each holds the least derived + // type that any reference to that category needs, which is what stops a + // realized node from ever having to be cast back to what it was. + std::vector m_strings; + std::vector m_stringCached; + std::vector m_visuals; + std::vector m_shapes; + std::vector m_geometries; + std::vector m_paths; + std::vector> m_canvasGeometries; + std::vector m_canvasGeometryStates; + std::vector m_brushes; + std::vector m_gradientStops; + std::vector m_viewBoxes; + std::vector m_clips; + std::vector m_shadows; + std::vector m_surfaces; + std::vector m_effects; + std::vector m_easings; + std::vector m_animations; + std::vector m_propertySets; + std::vector m_controllers; + std::vector m_animationBindings; + std::vector m_implicitControllerUsed; + bool m_animationsRestartable = true; + uint32_t m_traversalDepth = 0; + }; + + Fb::LottieComposition const& VerifyComposition(std::span buffer) + { + // The buffer is untrusted, so nothing is read out of it until the verifier + // has agreed that every offset in it is inside it. + ::flatbuffers::Verifier verifier( + reinterpret_cast(buffer.data()), + buffer.size()); + + if (buffer.size() < sizeof(uint32_t) + 4 || + !Fb::LottieCompositionBufferHasIdentifier(buffer.data()) || + !Fb::VerifyLottieCompositionBuffer(verifier)) + { + ThrowMalformed(); + } + + auto const* root = Fb::GetLottieComposition(buffer.data()); + Check(root != nullptr); + + // A newer schema may store things in fields this build does not read, so a + // buffer that declares one is refused rather than silently misinterpreted. + if (root->schema_version() > SupportedSchemaVersion) + { + ThrowUnsupported(); + } + + auto const requiredUapVersion = root->required_uap_version(); +#if !defined(LOTTIE_RUNTIME_WINUI3) + if (requiredUapVersion != 0 && + !winrt::Windows::Foundation::Metadata::ApiInformation::IsApiContractPresent( + L"Windows.Foundation.UniversalApiContract", + requiredUapVersion)) + { + ThrowUnsupported(); + } +#else + // Windows App SDK carries its Composition implementation with the app rather + // than exposing it through the OS UniversalApiContract. The consumer selects + // a buffer variant whose required APIs are present in its WASDK version. + static_cast(requiredUapVersion); +#endif + + return *root; + } +} + +#if defined(LOTTIE_RUNTIME_WINUI3) +namespace CommunityToolkit::WinUI3::Lottie +#else +namespace CommunityToolkit::WinUI2::Lottie +#endif +{ + Visual LoadComposition(Compositor const& compositor, std::span buffer) + { + return Interpreter(compositor, VerifyComposition(buffer)).Run(); + } + + LoadedComposition LoadCompositionWithMetadata(Compositor const& compositor, std::span buffer) + { + return LoadCompositionWithMetadata(compositor, buffer, {}); + } + + LoadedComposition LoadCompositionWithMetadata( + Compositor const& compositor, + std::span buffer, + std::span imageSurfaces) + { + return Interpreter(compositor, VerifyComposition(buffer), imageSurfaces).RunWithMetadata(); + } + + CompositionPropertySet ProgressPropertySet(Visual const& root) + { + return root.Properties(); + } + + bool CanRestartAnimations(LoadedComposition const& composition) noexcept + { + return composition.Animations != nullptr && composition.Animations->Restartable; + } + + void StopAnimations(LoadedComposition const& composition) + { + if (!CanRestartAnimations(composition) || !composition.Animations->Running) + { + return; + } + + for (auto const& binding : composition.Animations->Bindings) + { + binding.Target.StopAnimation(binding.Property); + } + composition.Animations->Running = false; + } + + void StartAnimations(LoadedComposition const& composition) + { + if (!CanRestartAnimations(composition) || composition.Animations->Running) + { + return; + } + + for (auto const& binding : composition.Animations->Bindings) + { + if (binding.Controller != nullptr) + { + binding.Target.StartAnimation(binding.Property, binding.Animation, binding.Controller); + } + else + { + binding.Target.StartAnimation(binding.Property, binding.Animation); + } + + if (binding.HasImplicitController) + { + // Same order as the load: pause, then the controller's own state. + auto controller = binding.Target.TryGetAnimationController(binding.Property); + if (controller == nullptr) + { + throw winrt::hresult_error(E_UNEXPECTED); + } + if (binding.PauseImplicitController) + { + controller.Pause(); + } + if (!binding.ImplicitControllerComment.empty()) + { + controller.Comment(binding.ImplicitControllerComment); + } + for (auto const& animation : binding.ImplicitControllerAnimations) + { + controller.StartAnimation(animation.Property, animation.Animation); + } + } + } + composition.Animations->Running = true; + } +} diff --git a/source/LottieRuntime/LottieRuntime.h b/source/LottieRuntime/LottieRuntime.h new file mode 100644 index 00000000..a4308d1c --- /dev/null +++ b/source/LottieRuntime/LottieRuntime.h @@ -0,0 +1,139 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include + +#if defined(LOTTIE_RUNTIME_WINUI2) == defined(LOTTIE_RUNTIME_WINUI3) +#error Define exactly one of LOTTIE_RUNTIME_WINUI2 or LOTTIE_RUNTIME_WINUI3. +#endif + +#if defined(LOTTIE_RUNTIME_WINUI3) +#include +namespace CommunityToolkit::WinUI3::Lottie +{ + using namespace winrt::Microsoft::UI::Composition; +#else +#include +namespace CommunityToolkit::WinUI2::Lottie +{ + using namespace winrt::Windows::UI::Composition; +#endif + + // Define LOTTIE_RUNTIME_WINUI2 for Windows.UI.Composition or + // LOTTIE_RUNTIME_WINUI3 for Microsoft.UI.Composition. + // Builds the composition described by a serialized Lottie composition. + // + // The buffer is the output of LottieGen -Language flatbuffer, or equivalently of + // CompositionSerializer. It is treated as untrusted: it is verified before it is + // read, and every index in it is range checked, so a malformed buffer produces an + // exception rather than undefined behaviour. + // + // The returned visual is the root of a tree that is already animated and ready to + // be attached to a target with SetElementChildVisual or as a child of another + // visual. The animations are bound to the "Progress" property of the property set + // returned by ProgressPropertySet, so playback is driven by animating that single + // property. + // + // Visual is sufficient for parenting the root and driving its progress. + // + // Throws winrt::hresult_error with E_INVALIDARG if the buffer is not a well formed + // composition, and E_NOTIMPL if it requires a feature this build does not have. + Visual LoadComposition( + Compositor const& compositor, + std::span buffer); + + struct CompositionMarker + { + winrt::hstring Name; + float Progress = 0; + float DurationProgress = 0; + }; + + struct CompositionImageSurface + { + uint32_t Index = 0; + ICompositionSurface Surface{ nullptr }; + }; + + // The keyframe animations a loaded tree started, recorded so that a host can stop + // and restart them. Shared by copies of the LoadedComposition that owns it. + class CompositionAnimations; + + struct LoadedComposition + { + Visual Root{ nullptr }; + winrt::Windows::Foundation::TimeSpan Duration{}; + winrt::Windows::Foundation::Numerics::float2 Size{}; + float FramesPerSecond = 0; + std::vector Markers; + CompositionPropertySet ThemeProperties{ nullptr }; + std::vector ImageSurfaces; + std::shared_ptr Animations; + }; + + // Loads the same animated tree as LoadComposition, together with its serialized + // metadata. Duration uses 100ns ticks. Marker progress and duration are fractions + // of the animation duration; order and duplicate names are preserved. Markers + // outside the animation's playback range are not clamped or discarded. + // + // ThemeProperties is the actual standalone property set referenced by the + // loaded graph's expressions, or nullptr when no theme set is declared. + // Inserting values into it updates the existing graph, not a separate copy. + // + // ImageSurfaces contains the actual realized LoadedImageSurface objects and + // their serialized surface indices, in index order. Visual surfaces and + // unrealized images are excluded. A host can observe image completion and + // reuse these objects when loading another tree from the same buffer. + // + // Requires a metadata table. Missing metadata, invalid numeric metadata, or + // invalid metadata indices throw winrt::hresult_invalid_argument. The returned + // metadata owns its values and does not require the buffer to remain alive. + LoadedComposition LoadCompositionWithMetadata( + Compositor const& compositor, + std::span buffer); + + // Reuses images from a previous load of the same buffer on the same XAML host + // compositor. Null surfaces, duplicate/out-of-range indices, nonimage indices, + // and objects that are not this projection's LoadedImageSurface are rejected. + // Other images are loaded normally. Completion events and playback policy + // remain the host's responsibility; this overload does not wait for images. + LoadedComposition LoadCompositionWithMetadata( + Compositor const& compositor, + std::span buffer, + std::span imageSurfaces); + + // The property set that drives the animation. Animating its "Progress" scalar from + // 0 to 1 plays the animation once. + // + // Returns the root Visual's property set. + CompositionPropertySet ProgressPropertySet(Visual const& root); + + // Stop and restart support for IAnimatedVisual2::DestroyAnimations and + // CreateAnimations, matching LottieGen's generated C++ and C# sources. + // + // StopAnimations stops the keyframe animations the load started, leaving every + // animated property at its current value and keeping expression bindings (Progress, + // theme and other bindings) in place. StartAnimations starts them again with their + // original controllers, so the tree once more follows its Progress property. A loaded + // composition starts with its animations running. Both calls are idempotent. + // + // CanRestartAnimations returns false when the tree cannot be restarted faithfully: + // another object references an implicit animation controller, an implicit controller + // owns a property set, two animations share one implicit controller, or an implicit + // controller's own animation has a controller. For such trees, and for a default + // LoadedComposition, StopAnimations and StartAnimations do nothing. + bool CanRestartAnimations(LoadedComposition const& composition) noexcept; + void StopAnimations(LoadedComposition const& composition); + void StartAnimations(LoadedComposition const& composition); +} diff --git a/source/LottieRuntime/LottieRuntimeTool.cpp b/source/LottieRuntime/LottieRuntimeTool.cpp new file mode 100644 index 00000000..da80b7c8 --- /dev/null +++ b/source/LottieRuntime/LottieRuntimeTool.cpp @@ -0,0 +1,322 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// Loads a serialized Lottie composition through the statically linked WinUI 2 reader. + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace winrt; +using namespace winrt::Windows::UI::Composition; +using namespace winrt::Windows::Foundation; +using namespace winrt::Windows::Foundation::Collections; + +namespace +{ + winrt::Windows::System::DispatcherQueueController CreateDispatcherQueue() + { + DispatcherQueueOptions const options{ + sizeof(DispatcherQueueOptions), + DQTYPE_THREAD_CURRENT, + DQTAT_COM_NONE, + }; + + winrt::Windows::System::DispatcherQueueController controller{ nullptr }; + winrt::check_hresult(CreateDispatcherQueueController( + options, + reinterpret_cast(winrt::put_abi(controller)))); + return controller; + } + + std::vector ReadFileBytes(wchar_t const* path) + { + std::ifstream file(path, std::ios::binary | std::ios::ate); + if (!file) + { + throw std::runtime_error("Could not open input file."); + } + + auto const size = static_cast(file.tellg()); + std::vector result(size); + file.seekg(0); + file.read(reinterpret_cast(result.data()), static_cast(size)); + return result; + } + + void PrintLine(int depth, std::wstring_view text) + { + std::wstring indent(static_cast(depth) * 2, L' '); + std::wcout << indent << text << L"\n"; + } + + hstring RuntimeClassName(winrt::Windows::Foundation::IInspectable const& node) + { + if (node == nullptr) + { + return L"(null)"; + } + + return winrt::get_class_name(node); + } + + hstring CommentOf(CompositionObject const& node) + { + auto comment = node.Comment(); + return comment.empty() ? L"" : (L" \"" + comment + L"\""); + } + + void DumpBrush(CompositionBrush const& brush, int depth); + void DumpVisual(Visual const& visual, int depth); + void DumpShape(CompositionShape const& shape, int depth); + + void DumpShape(CompositionShape const& shape, int depth) + { + if (shape == nullptr) + { + return; + } + + PrintLine(depth, RuntimeClassName(shape) + CommentOf(shape)); + + if (auto containerShape = shape.try_as()) + { + for (auto const& child : containerShape.Shapes()) + { + DumpShape(child, depth + 1); + } + } + + if (auto spriteShape = shape.try_as()) + { + if (auto fill = spriteShape.FillBrush()) + { + PrintLine(depth + 1, L"FillBrush:"); + DumpBrush(fill, depth + 2); + } + + if (auto stroke = spriteShape.StrokeBrush()) + { + PrintLine(depth + 1, L"StrokeBrush:"); + DumpBrush(stroke, depth + 2); + } + } + } + + void DumpBrush(CompositionBrush const& brush, int depth) + { + if (brush == nullptr) + { + return; + } + + PrintLine(depth, RuntimeClassName(brush) + CommentOf(brush)); + + if (auto linearGradient = brush.try_as()) + { + for (auto const& stop : linearGradient.ColorStops()) + { + PrintLine(depth + 1, L"ColorStop " + RuntimeClassName(stop)); + } + } + } + + void DumpVisual(Visual const& visual, int depth) + { + if (visual == nullptr) + { + return; + } + + PrintLine(depth, RuntimeClassName(visual) + CommentOf(visual)); + + if (auto spriteVisual = visual.try_as()) + { + if (auto brush = spriteVisual.Brush()) + { + PrintLine(depth + 1, L"Brush:"); + DumpBrush(brush, depth + 2); + } + + if (auto shapeVisual = visual.try_as()) + { + for (auto const& shape : shapeVisual.Shapes()) + { + DumpShape(shape, depth + 1); + } + } + } + else if (auto shapeVisual = visual.try_as()) + { + for (auto const& shape : shapeVisual.Shapes()) + { + DumpShape(shape, depth + 1); + } + } + + if (auto containerVisual = visual.try_as()) + { + for (auto const& child : containerVisual.Children()) + { + DumpVisual(child, depth + 1); + } + } + } + + LRESULT CALLBACK WindowProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam) + { + if (message == WM_DESTROY) + { + PostQuitMessage(0); + return 0; + } + + return DefWindowProcW(window, message, wParam, lParam); + } + + void ShowVisual(Visual const& root) + { + auto const instance = GetModuleHandleW(nullptr); + wchar_t const className[] = L"LottieRuntimeWindow"; + + WNDCLASSW windowClass{}; + windowClass.lpfnWndProc = WindowProc; + windowClass.hInstance = instance; + windowClass.hCursor = LoadCursorW(nullptr, IDC_ARROW); + windowClass.hbrBackground = static_cast(GetStockObject(WHITE_BRUSH)); + windowClass.lpszClassName = className; + winrt::check_bool(RegisterClassW(&windowClass) != 0); + + auto const window = CreateWindowExW( + 0, + className, + L"LottieRuntime", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + 900, + 700, + nullptr, + nullptr, + instance, + nullptr); + winrt::check_bool(window != nullptr); + + auto compositor = root.Compositor(); + auto compositorInterop = + compositor.as(); + winrt::Windows::UI::Composition::Desktop::DesktopWindowTarget target{ nullptr }; + winrt::check_hresult(compositorInterop->CreateDesktopWindowTarget( + window, + false, + reinterpret_cast( + winrt::put_abi(target)))); + target.Root(root); + + auto progress = compositor.CreateScalarKeyFrameAnimation(); + progress.InsertKeyFrame(0.0f, 0.0f); + progress.InsertKeyFrame(1.0f, 1.0f); + progress.Duration(std::chrono::seconds(5)); + progress.IterationBehavior(AnimationIterationBehavior::Forever); + root.Properties().StartAnimation(L"Progress", progress); + + ShowWindow(window, SW_SHOW); + UpdateWindow(window); + + MSG message{}; + while (GetMessageW(&message, nullptr, 0, 0) > 0) + { + TranslateMessage(&message); + DispatchMessageW(&message); + } + } +} + +int wmain(int argc, wchar_t* argv[]) +{ + if (argc < 2 || argc > 3) + { + std::wcerr << L"Usage: LottieRuntime.exe [--dump|--show]\n"; + return 1; + } + + try + { + enum class Mode + { + Validate, + Dump, + Show, + }; + + auto mode = Mode::Validate; + if (argc == 3) + { + if (std::wstring_view(argv[2]) == L"--dump") + { + mode = Mode::Dump; + } + else if (std::wstring_view(argv[2]) == L"--show") + { + mode = Mode::Show; + } + else + { + throw std::invalid_argument("Mode must be --dump or --show."); + } + } + + winrt::check_hresult(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED)); + auto dispatcherQueueController = CreateDispatcherQueue(); + auto bytes = ReadFileBytes(argv[1]); + + Compositor compositor; + auto root = CommunityToolkit::WinUI2::Lottie::LoadComposition(compositor, bytes); + + switch (mode) + { + case Mode::Validate: + std::wcout << L"Composition loaded successfully.\n"; + break; + case Mode::Dump: + std::wcout << L"Composition object hierarchy:\n"; + DumpVisual(root, 0); + break; + case Mode::Show: + ShowVisual(root); + break; + } + + root = nullptr; + dispatcherQueueController.ShutdownQueueAsync(); + } + catch (winrt::hresult_error const& e) + { + std::wcerr << L"Failed to load composition: " << e.message().c_str() << L"\n"; + return 1; + } + catch (std::exception const& e) + { + std::cerr << "Failed: " << e.what() << "\n"; + return 1; + } + + return 0; +} diff --git a/source/LottieRuntime/LottieRuntimeTool.vcxproj b/source/LottieRuntime/LottieRuntimeTool.vcxproj new file mode 100644 index 00000000..bc407905 --- /dev/null +++ b/source/LottieRuntime/LottieRuntimeTool.vcxproj @@ -0,0 +1,81 @@ + + + + + Debug + x64 + + + Release + x64 + + + Debug + ARM64 + + + Release + ARM64 + + + + + {9A7B4C2E-1F3D-4B7A-9C3E-2D5A8F0B2E48} + LottieRuntime + LottieRuntime + Application + v143 + Unicode + 10.0.22621.0 + 10.0.17763.0 + false + PrepareForBuild + + + + + + + + true + false + true + false + + + + + stdcpp20 + WIN32_LEAN_AND_MEAN;NOMINMAX;LOTTIE_RUNTIME_WINUI2;%(PreprocessorDefinitions) + $(MSBuildThisFileDirectory);$(FlatBuffersIncludeDirectory);%(AdditionalIncludeDirectories) + Level4 + true + Sync + + + Console + CoreMessaging.lib;d2d1.lib;dxguid.lib;ole32.lib;shcore.lib;shlwapi.lib;user32.lib;windowsapp.lib;%(AdditionalDependencies) + + + + + + MinSpace + true + true + true + + + UseLinkTimeCodeGeneration + true + true + + + + + + + + + + diff --git a/source/LottieRuntime/LottieVisualSource.cpp b/source/LottieRuntime/LottieVisualSource.cpp new file mode 100644 index 00000000..a429ec3d --- /dev/null +++ b/source/LottieRuntime/LottieVisualSource.cpp @@ -0,0 +1,611 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// An IAnimatedVisualSource2 over the runtime, replacing the classes LottieGen generates +// for each animation. + +#include +#include +#include + +#if defined(LOTTIE_RUNTIME_WINUI2) == defined(LOTTIE_RUNTIME_WINUI3) +#error Define exactly one of LOTTIE_RUNTIME_WINUI2 or LOTTIE_RUNTIME_WINUI3. +#endif + +#include "LottieVisualSource.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#undef GetCurrentTime +#if defined(LOTTIE_RUNTIME_WINUI3) +#include +#include +#else +#include +#include +#endif + +#include "Generated/lottie_comp_generated.h" + +#if defined(LOTTIE_RUNTIME_WINUI3) +namespace CommunityToolkit::WinUI3::Lottie +#else +namespace CommunityToolkit::WinUI2::Lottie +#endif +{ + namespace + { + namespace Fb = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema; + using namespace winrt::Microsoft::UI::Xaml::Controls; + using namespace winrt::Windows::Foundation; + using namespace winrt::Windows::Foundation::Collections; + using namespace winrt::Windows::Foundation::Numerics; + using winrt::hstring; + using winrt::Windows::Foundation::IInspectable; +#if defined(LOTTIE_RUNTIME_WINUI3) + namespace XamlData = winrt::Microsoft::UI::Xaml::Data; + namespace XamlMedia = winrt::Microsoft::UI::Xaml::Media; +#else + namespace XamlData = winrt::Windows::UI::Xaml::Data; + namespace XamlMedia = winrt::Windows::UI::Xaml::Media; +#endif + + // IAnimatedVisualSource2 has no scalar setter, so sources expose it privately. +#if defined(LOTTIE_RUNTIME_WINUI3) + struct __declspec(uuid("ae67b9f9-0afe-467c-9d06-f6a2dbaa46da")) __declspec(novtable) IScalarProperties : ::IUnknown +#else + struct __declspec(uuid("c36aecea-4fd6-42ae-ac25-7cb9c564476e")) __declspec(novtable) IScalarProperties : ::IUnknown +#endif + { + virtual HRESULT __stdcall SetScalar(HSTRING name, double value) noexcept = 0; + }; + + bool IsUapPresent(uint16_t version) + { + return winrt::Windows::Foundation::Metadata::ApiInformation::IsApiContractPresent( + L"Windows.Foundation.UniversalApiContract", version); + } + + Fb::LottieComposition const* Verify(std::span buffer) + { + flatbuffers::Verifier verifier(reinterpret_cast(buffer.data()), buffer.size()); + if (buffer.empty() || !Fb::VerifyLottieCompositionBuffer(verifier)) + { + throw winrt::hresult_invalid_argument(L"Invalid serialized Lottie composition."); + } + return Fb::GetLottieComposition(buffer.data()); + } + + bool HasImages(Fb::LottieComposition const& composition) + { + if (auto surfaces = composition.surfaces()) + { + for (auto surface : *surfaces) + { + if (surface->kind() == Fb::SurfaceKind::LoadedImageFromStream || + surface->kind() == Fb::SurfaceKind::LoadedImageFromUri) + { + return true; + } + } + } + return false; + } + + struct AnimatedVisual : winrt::implements + { + explicit AnimatedVisual(LoadedComposition composition) : m_composition(std::move(composition)) + { + } + + Visual RootVisual() const { return m_composition.Root; } + TimeSpan Duration() const { return m_composition.Duration; } + float2 Size() const { return m_composition.Size; } + CompositionPropertySet ThemeProperties() const { return m_composition.ThemeProperties; } + + void CreateAnimations() { StartAnimations(m_composition); } + void DestroyAnimations() { StopAnimations(m_composition); } + + void Close() + { + if (m_composition.Root) + { + m_composition.Root.Close(); + } + m_composition = {}; + } + + private: + LoadedComposition m_composition; + }; + + template + struct SourceInterfaces : winrt::implements + { + }; + + template + struct SourceInterfaces : winrt::implements + { + }; + + template + struct AnimatedVisualSource : SourceInterfaces, TImages> + { + AnimatedVisualSource( + std::span buffer, + Fb::LottieComposition const* composition, + AnimatedVisualSourceOptions const& options) : + m_buffer(buffer), m_composition(composition), m_options(options) + { + auto metadata = m_composition->metadata(); + if (!metadata) + { + throw winrt::hresult_invalid_argument(L"Lottie composition has no metadata."); + } + auto duration = metadata->duration_ticks(); + auto framerate = metadata->frames_per_second(); + if (duration <= 0 || !std::isfinite(framerate) || framerate <= 0) + { + throw winrt::hresult_invalid_argument(L"Lottie composition has no duration."); + } + m_frameCount = std::round(duration * static_cast(framerate) / 10000000.0); + if (m_frameCount <= 0) + { + throw winrt::hresult_invalid_argument(L"Lottie composition has no frames."); + } + if (auto bindings = metadata->property_bindings()) + { + for (auto binding : *bindings) + { + (void)StringAt(binding->name()); + } + } + m_markers = m_options.Markers == MarkerNames::Unique ? UniqueMarkers() : FirstWinsMarkers(); + } + + ~AnimatedVisualSource() + { + // The handlers hold weak references, so a failed unregistration (for example + // a release off the UI thread) is harmless and must not escape the destructor. + for (auto const& [surface, token] : m_imageSubscriptions) + { + try + { + surface.LoadCompleted(token); + } + catch (...) + { + } + } + } + + IAnimatedVisual TryCreateAnimatedVisual(Compositor const& compositor, IInspectable& diagnostics) + { + diagnostics = nullptr; + if (!IsUapPresent(m_composition->required_uap_version())) + { + return nullptr; + } + if (!m_options.ReportLoadErrors) + { + return CreateAnimatedVisual(compositor); + } + try + { + return CreateAnimatedVisual(compositor); + } + catch (winrt::hresult_error const& error) + { + diagnostics = winrt::box_value(error.message()); + return nullptr; + } + } + + IMapView Markers() const { return m_markers; } + + void SetColorProperty(hstring const& name, winrt::Windows::UI::Color value) + { + if (HasBinding(name, Fb::PropertyValueType::Color)) + { + float4 color{ static_cast(value.R), static_cast(value.G), + static_cast(value.B), static_cast(value.A) }; + m_colors.insert_or_assign(name, color); + UpdateThemes([&](auto const& theme) { theme.InsertVector4(name, color); }); + } + } + + void SetScalarProperty(hstring const& name, double value) + { + if (HasBinding(name, Fb::PropertyValueType::Scalar)) + { + auto scalar = static_cast(value); + m_scalars.insert_or_assign(name, scalar); + UpdateThemes([&](auto const& theme) { theme.InsertScalar(name, scalar); }); + } + } + + HRESULT __stdcall SetScalar(HSTRING name, double value) noexcept override + { + try + { + SetScalarProperty(reinterpret_cast(name), value); + return S_OK; + } + catch (...) + { + return winrt::to_hresult(); + } + } + + winrt::event_token AnimatedVisualInvalidated( + TypedEventHandler const& handler) + { + return m_invalidated.add(handler); + } + + void AnimatedVisualInvalidated(winrt::event_token const& token) noexcept + { + m_invalidated.remove(token); + } + + winrt::event_token PropertyChanged(XamlData::PropertyChangedEventHandler const& handler) + { + return m_propertyChanged.add(handler); + } + + void PropertyChanged(winrt::event_token const& token) noexcept + { + m_propertyChanged.remove(token); + } + + private: + IAnimatedVisual CreateAnimatedVisual(Compositor const& compositor) + { + LoadedComposition composition; + if (m_pendingComposition) + { + if (m_imageCompositor != compositor) + { + throw winrt::hresult_invalid_argument(L"Images were loaded with another compositor."); + } + if (!m_imageLoadingCompleted) + { + return nullptr; + } + composition = std::move(*m_pendingComposition); + m_pendingComposition.reset(); + } + else + { + if (!m_imageSurfaces.empty() && m_imageCompositor != compositor) + { + throw winrt::hresult_invalid_argument(L"Images were loaded with another compositor."); + } + composition = LoadCompositionWithMetadata(compositor, m_buffer, m_imageSurfaces); + if constexpr (TImages) + { + if (!m_imageLoadingStarted) + { + ObserveImages(compositor, composition.ImageSurfaces); + } + if (m_options.AsynchronousImageLoading && !m_imageLoadingCompleted) + { + m_pendingComposition.emplace(std::move(composition)); + return nullptr; + } + } + } + + auto theme = composition.ThemeProperties; + auto visual = winrt::make_self(std::move(composition)); + if (theme) + { + for (auto const& [name, color] : m_colors) + { + theme.InsertVector4(name, color); + } + for (auto const& [name, scalar] : m_scalars) + { + theme.InsertScalar(name, scalar); + } + std::erase_if(m_visuals, [](auto const& weak) { return !weak.get(); }); + m_visuals.emplace_back(visual->get_weak()); + } + return visual.as(); + } + + void ObserveImages(Compositor const& compositor, std::vector const& images) + { + m_imageLoadingStarted = true; + m_imageCompositor = compositor; + m_imageSurfaces = images; + m_imagesRemaining = m_imageSurfaces.size(); + m_imageLoadingCompleted = m_imagesRemaining == 0; + auto weak = this->get_weak(); + for (auto const& image : m_imageSurfaces) + { + auto surface = image.Surface.as(); + auto token = surface.LoadCompleted([weak](auto const&, auto const&) + { + if (auto source = weak.get()) + { + source->ImageLoadCompleted(); + } + }); + m_imageSubscriptions.emplace_back(surface, token); + } + } + + void ImageLoadCompleted() + { + if (m_imagesRemaining && --m_imagesRemaining == 0) + { + m_imageLoadingCompleted = true; + m_propertyChanged(*this, XamlData::PropertyChangedEventArgs(L"IsImageLoadingCompleted")); + if (m_options.AsynchronousImageLoading) + { + m_invalidated(*this, nullptr); + } + } + } + + hstring StringAt(uint32_t index) const + { + auto strings = m_composition->strings(); + if (!strings || index >= strings->size()) + { + throw winrt::hresult_invalid_argument(L"Invalid Lottie composition string index."); + } + return winrt::to_hstring(strings->Get(index)->string_view()); + } + + bool HasBinding(hstring const& name, Fb::PropertyValueType type) const + { + if (auto bindings = m_composition->metadata()->property_bindings()) + { + for (auto binding : *bindings) + { + if (binding->exposed_type() == type && StringAt(binding->name()) == name) + { + return true; + } + } + } + return false; + } + + template + void UpdateThemes(TUpdate const& update) + { + std::erase_if(m_visuals, [&](auto const& weak) + { + if (auto visual = weak.get()) + { + if (auto theme = visual->ThemeProperties()) + { + update(theme); + return false; + } + } + return true; + }); + } + + double MarkerProgress(double frame) const + { + return frame == 0 ? 0 : std::clamp((frame + 0.05) / m_frameCount, 0.0, 1.0); + } + + IMapView FirstWinsMarkers() const + { + auto markers = winrt::single_threaded_map(); + if (auto entries = m_composition->metadata()->markers()) + { + for (auto marker : *entries) + { + if (!std::isfinite(marker->progress()) || !std::isfinite(marker->duration_progress())) + { + throw winrt::hresult_invalid_argument(L"Invalid Lottie composition marker."); + } + auto name = StringAt(marker->name()); + auto frame = std::round(marker->progress() * m_frameCount); + auto last = m_options.IncludeFinalFrameMarkers ? m_frameCount : m_frameCount - 1; + if (frame >= 0 && frame <= last && !markers.HasKey(name)) + { + markers.Insert(name, MarkerProgress(frame)); + } + } + } + return markers.GetView(); + } + + IMapView UniqueMarkers() const + { + struct Marker + { + std::wstring Name; + double Frame; + }; + std::vector markers; + if (auto entries = m_composition->metadata()->markers()) + { + for (auto entry : *entries) + { + if (!std::isfinite(entry->progress()) || !std::isfinite(entry->duration_progress())) + { + throw winrt::hresult_invalid_argument(L"Invalid Lottie composition marker."); + } + auto frame = std::round(entry->progress() * m_frameCount); + auto end = frame + std::round(entry->duration_progress() * m_frameCount); + auto last = m_options.IncludeFinalFrameMarkers ? m_frameCount : m_frameCount - 1; + if ((frame < 0 && end < 0) || frame > last) + { + continue; + } + std::wstring name; + for (auto ch : StringAt(entry->name())) + { + if (ch == L'\t') + { + name += L' '; + } + else if (ch >= 32 && (ch < 127 || ch > 159)) + { + name += ch; + } + } + if (name.find_first_not_of(L" \t\r\n") == std::wstring::npos) + { + name = L"anonymous"; + } + markers.push_back({ std::move(name), std::max(0.0, frame) }); + } + } + std::stable_sort(markers.begin(), markers.end(), + [](auto const& a, auto const& b) { return a.Frame < b.Frame; }); + + // Suffix every duplicate, repeating if a suffixed name collides with an authored one. + for (bool duplicate = true; duplicate;) + { + duplicate = false; + std::map> groups; + for (size_t i = 0; i != markers.size(); ++i) + { + groups[markers[i].Name].push_back(i); + } + for (auto const& [name, indices] : groups) + { + if (indices.size() > 1) + { + duplicate = true; + for (size_t i = 0; i != indices.size(); ++i) + { + markers[indices[i]].Name = name + L"_" + std::to_wstring(i); + } + } + } + } + + auto result = winrt::single_threaded_map(); + for (auto const& marker : markers) + { + result.Insert(hstring(marker.Name), MarkerProgress(marker.Frame)); + } + return result.GetView(); + } + + std::span m_buffer; + Fb::LottieComposition const* m_composition{}; + AnimatedVisualSourceOptions m_options; + double m_frameCount{}; + IMapView m_markers{ nullptr }; + std::map m_colors; + std::map m_scalars; + // Composition objects do not expose weak references; their owning visuals do. + std::vector> m_visuals; + + bool m_imageLoadingStarted{}; + bool m_imageLoadingCompleted{ !TImages }; + size_t m_imagesRemaining{}; + Compositor m_imageCompositor{ nullptr }; + std::optional m_pendingComposition; + std::vector m_imageSurfaces; + std::vector> m_imageSubscriptions; + winrt::event> m_invalidated; + winrt::event m_propertyChanged; + }; + } + + std::span LoadEmbeddedComposition( + void const* moduleAddress, + std::span variants) + { + EmbeddedCompositionVariant const* selected = nullptr; + EmbeddedCompositionVariant const* lowest = nullptr; + for (auto const& variant : variants) + { + if (!lowest || variant.RequiredUapVersion < lowest->RequiredUapVersion) + { + lowest = &variant; + } + if ((!selected || selected->RequiredUapVersion < variant.RequiredUapVersion) && + IsUapPresent(variant.RequiredUapVersion)) + { + selected = &variant; + } + } + if (!selected) + { + selected = lowest; + } + if (!selected || !selected->ResourceName) + { + throw winrt::hresult_invalid_argument(L"No embedded Lottie composition variant."); + } + + HMODULE module{}; + winrt::check_bool(GetModuleHandleExW( + GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + static_cast(moduleAddress), &module)); + auto resource = FindResourceW(module, selected->ResourceName, MAKEINTRESOURCEW(10) /* RT_RCDATA */); + if (!resource) + { + throw winrt::hresult_error(HRESULT_FROM_WIN32(ERROR_RESOURCE_NAME_NOT_FOUND), + L"Missing embedded Lottie composition."); + } + auto size = SizeofResource(module, resource); + auto loaded = LoadResource(module, resource); + auto data = loaded ? LockResource(loaded) : nullptr; + if (!data || !size) + { + throw winrt::hresult_error(HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND), + L"Empty embedded Lottie composition."); + } + std::span buffer{ static_cast(data), size }; + if (Verify(buffer)->required_uap_version() != selected->RequiredUapVersion) + { + throw winrt::hresult_invalid_argument(L"Embedded Lottie composition has the wrong UAP version."); + } + return buffer; + } + + IAnimatedVisualSource2 CreateAnimatedVisualSource( + std::span buffer, + AnimatedVisualSourceOptions const& options) + { + auto composition = Verify(buffer); + if (HasImages(*composition)) + { + return winrt::make>(buffer, composition, options).as(); + } + return winrt::make>(buffer, composition, options).as(); + } + + void SetScalarProperty( + winrt::Windows::Foundation::IInspectable const& source, + winrt::hstring const& name, + double value) + { + auto properties = source.try_as(); + if (!properties) + { + throw winrt::hresult_invalid_argument(L"Source was not created by CreateAnimatedVisualSource."); + } + winrt::check_hresult(properties->SetScalar(static_cast(winrt::get_abi(name)), value)); + } +} diff --git a/source/LottieRuntime/LottieVisualSource.h b/source/LottieRuntime/LottieVisualSource.h new file mode 100644 index 00000000..8198a375 --- /dev/null +++ b/source/LottieRuntime/LottieVisualSource.h @@ -0,0 +1,93 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#pragma once + +#include "LottieRuntime.h" + +#undef GetCurrentTime +#include + +#if defined(LOTTIE_RUNTIME_WINUI3) +namespace CommunityToolkit::WinUI3::Lottie +#else +namespace CommunityToolkit::WinUI2::Lottie +#endif +{ + // One UAP-specific serialization of an animation, embedded as an RCDATA resource. + struct EmbeddedCompositionVariant + { + uint16_t RequiredUapVersion = 0; + wchar_t const* ResourceName = nullptr; + }; + + // Returns the bytes of the variant with the highest UniversalApiContract version + // present, or of the lowest variant when none is present so that the source still + // has metadata and TryCreateAnimatedVisual returns null. The resource is read from + // the module containing moduleAddress and lives as long as that module. + // + // Throws winrt::hresult_error if there are no variants or the resource is missing or + // empty, and winrt::hresult_invalid_argument if the buffer is not a verified + // composition requiring exactly the variant's UAP version. + std::span LoadEmbeddedComposition( + void const* moduleAddress, + std::span variants); + + // How serialized markers become IAnimatedVisualSource2::Markers. Each policy matches a + // LottieGen version's generated code. Frames are recovered from the marker progress + // and the first nonzero frame is nudged by 0.05 frames, as LottieGen does. + enum class MarkerNames : uint8_t + { + // A marker whose frame lies outside the animation is dropped; the first marker + // of a name wins. + FirstWins, + + // Names are sanitized as LottieGen does. A marker is dropped only when it lies + // entirely outside the animation. Markers are ordered by frame and every + // duplicate name gets a "_" suffix. + Unique, + }; + + struct AnimatedVisualSourceOptions + { + MarkerNames Markers = MarkerNames::FirstWins; + + // Whether a marker on the final frame is kept. + bool IncludeFinalFrameMarkers = true; + + // When true, TryCreateAnimatedVisual returns null and reports the error message + // through diagnostics if loading fails. When false, the error propagates. + bool ReportLoadErrors = false; + + // For animations with images: return null from TryCreateAnimatedVisual until + // every image has loaded, then raise AnimatedVisualInvalidated. + bool AsynchronousImageLoading = false; + }; + + // Creates an IAnimatedVisualSource2 that loads the serialized composition with the + // runtime. The buffer is not copied and must outlive the source; an embedded + // resource does. + // + // Created visuals implement IAnimatedVisual2, so AnimatedVisualPlayer's + // AnimationOptimization="Resources" stops their animations while idle. + // SetColorProperty and SetScalarProperty (below) update the theme properties of every + // live visual and of visuals created later; names that are not bound properties of that + // type are ignored. Animations with images also implement + // IDynamicAnimatedVisualSource and INotifyPropertyChanged, raising + // "IsImageLoadingCompleted" once every image has loaded. + // + // Throws winrt::hresult_invalid_argument if the buffer is not a verified composition + // with metadata, a positive duration and a positive frame rate. + winrt::Microsoft::UI::Xaml::Controls::IAnimatedVisualSource2 CreateAnimatedVisualSource( + std::span buffer, + AnimatedVisualSourceOptions const& options = {}); + + // Sets a bound scalar theme property, as LottieGen's generated SetScalarProperty does. + // IAnimatedVisualSource2 only declares SetColorProperty. Throws + // winrt::hresult_invalid_argument if source was not created by CreateAnimatedVisualSource. + void SetScalarProperty( + winrt::Windows::Foundation::IInspectable const& source, + winrt::hstring const& name, + double value); +} diff --git a/source/LottieRuntime/README.md b/source/LottieRuntime/README.md new file mode 100644 index 00000000..8231945b --- /dev/null +++ b/source/LottieRuntime/README.md @@ -0,0 +1,372 @@ +# LottieRuntime + +Native C++/WinRT source builders for serialized Lottie animations. + +The reader builds a Composition visual tree directly with the caller's +`Compositor`. There is no COM activation layer and no runtime DLL. The consumer +compiles `LottieRuntime.cpp` with exactly one projection definition: + +| Composition API | Preprocessor definition | +| --- | --- | +| `Windows.UI.Composition` (WinUI 2/UWP) | `LOTTIE_RUNTIME_WINUI2` | +| `Microsoft.UI.Composition` (WinUI 3/Windows App SDK) | `LOTTIE_RUNTIME_WINUI3` | + +The source and header reject builds where neither or both definitions are set. +This keeps the ABI-incompatible projections separate without duplicating the +interpreter. + +## Producing buffers + +```powershell +LottieGen -InputFile animation.json -Language flatbuffer -OutputFolder . +``` + +If one translation covers the requested UAP range, this writes +`Animation.lcomp`. If fallbacks are required, LottieGen writes one file per +supported range, for example: + +```text +Animation.uap14-plus.lcomp +Animation.uap10-13.lcomp +Animation.uap7-9.lcomp +``` + +The consumer selects the file matching its Composition API contract. The data is +not tied to either projection: the same variant can be read by the WinUI 2 or +WinUI 3 builder when that projection provides the APIs required by the variant. + +## Incorporating the reader + +Add `LottieRuntime.cpp` to the native project, define the matching projection +flag, and add `source\LottieRuntime` and the include directory from the vcpkg +`flatbuffers` port to its include paths. The checked-in C++ binding requires +FlatBuffers **25.2.10**. Build as C++20 and link: + +```text +d2d1.lib +dxguid.lib +shcore.lib +shlwapi.lib +windowsapp.lib +``` + +Include `LottieRuntime.h`, create the compositor in the host, and pass it to the +reader: + +```cpp +#include + +auto bytes = ReadFileBytes(L"Animation.lcomp"); +auto root = CommunityToolkit::WinUI2::Lottie::LoadComposition(compositor, bytes); +``` + +The same projection definition must be visible to every file that includes +`LottieRuntime.h`. WinUI 3 builds use the corresponding +`CommunityToolkit::WinUI3::Lottie` namespace. The distinct namespaces allow both +projection-specific objects to be linked into the same binary. + +`LoadComposition` returns the root `Visual`. `ProgressPropertySet(root)` returns +the Composition property set containing the `Progress` scalar. For +`AnimatedVisualPlayer`, use `LottieVisualSource` (below) rather than wrapping the +root yourself. + +Animations containing loaded image surfaces must be loaded on the XAML UI thread +with the XAML host's compositor (for example, the compositor obtained from +`ElementCompositionPreview::GetElementVisual(element)`). `LoadedImageSurface` +uses XAML's image pipeline; initializing only a dispatcher queue or supplying an +unrelated `Compositor` is not sufficient for these assets. + +### Loading metadata and live theme properties + +```cpp +namespace Lottie = CommunityToolkit::WinUI2::Lottie; +auto animation = Lottie::LoadCompositionWithMetadata(compositor, bytes); +auto root = animation.Root; // Visual +auto duration = animation.Duration; // Windows::Foundation::TimeSpan +auto size = animation.Size; // Windows::Foundation::Numerics::float2 +auto framesPerSecond = animation.FramesPerSecond; // float +auto progress = Lottie::ProgressPropertySet(root); +for (auto const& marker : animation.Markers) +{ + // marker.Name is hstring; Progress and DurationProgress are floats. + RegisterMarker(marker.Name, marker.Progress, marker.DurationProgress); +} +if (animation.ThemeProperties) +{ + // Use the actual serialized property name and Composition storage type. + animation.ThemeProperties.InsertVector4(L"Foreground", foregroundVector); +} +``` + +`LoadedComposition` owns its metadata and retains the Composition objects; the +input buffer may be released after loading. `Duration.count()` is the serialized +duration in **100ns ticks**, not milliseconds. `Size` and `FramesPerSecond` are +the serialized source dimensions and frame rate, not inferred from the visual +tree. Serialized zero values are preserved, including buffers produced without +source timing metadata. + +`Markers` is a `std::vector` with `Name`, `Progress`, and +`DurationProgress`. Both numeric values are fractions of the entire animation's +duration, not frame numbers or seconds. Names, order, duplicates, and finite +out-of-playback-range markers are preserved, matching the serializer's unfiltered +source markers. A host projecting markers to `IMapView` must +choose its own duplicate-name and out-of-range policy. The runtime does not +invent separate start/end marker names, clamp markers, or nudge frame positions. + +`ThemeProperties` is nullable. When present it is the **same standalone +CompositionPropertySet** used by expressions in the loaded graph, not the root's +progress property set and not a new set populated from metadata defaults. +Updating an existing property therefore targets the loaded animation. Color +bindings may be stored as `Vector4`; use the names/types generated for the asset. +Theme lifetime follows the returned Composition objects. + +### Observing and reusing loaded images + +`LoadedComposition.ImageSurfaces` is a +`std::vector`. Each descriptor contains `Index` +(`uint32_t`, the serialized surface-table index) and `Surface` +(`ICompositionSurface`). These are the **actual cached `LoadedImageSurface` +objects used by the returned graph**, not new image loads. Descriptors are in +serialized index order; visual surfaces and unrealized images are excluded. +The runtime header does not add a XAML dependency for this field. + +A WinUI 2 host can include ``, cast a descriptor's +`Surface` to `winrt::Windows::UI::Xaml::Media::LoadedImageSurface`, and subscribe +to its `LoadCompleted` event. A WinUI 3 host uses the matching +`Microsoft.UI.Xaml.Media` projection. Image completion, asynchronous-loading +policy, notifications, retry/fallback, and event revocation belong to the host. +The runtime starts image loading but does not wait for decoding or substitute +a static visual. A host waiting for images should retain the first +`LoadedComposition` and attach its already-created root once ready. + +To create another tree without restarting those image loads: + +```cpp +auto another = Lottie::LoadCompositionWithMetadata( + compositor, bytes, animation.ImageSurfaces); +``` + +This additive three-argument overload seeds the new interpreter's image cache. +The original two-argument overload and `LoadComposition` remain available. +Only reuse descriptors from the **same serialized buffer and XAML host +compositor**; indices do not identify images across different files or UAP +variants. Null objects, duplicate/out-of-range indices, nonimage surface indices, +and objects that are not the selected projection's `LoadedImageSurface` are +rejected with `winrt::hresult_invalid_argument`. Images without a supplied +descriptor are loaded normally. + +### Stopping and restarting animations + +Loading starts every animation, paused and driven by `Progress`. A host that +implements `IAnimatedVisual2` (for `AnimatedVisualPlayer`'s +`AnimationOptimization="Resources"`) can release and recreate them: + +```cpp +void DestroyAnimations() { Lottie::StopAnimations(animation); } +void CreateAnimations() { Lottie::StartAnimations(animation); } +``` + +`StopAnimations` stops every keyframe animation the load started; expression +bindings, including those to `Progress` and `ThemeProperties`, stay live. +`StartAnimations` restarts them on the same controllers, restoring each implicit +controller's pause state, comment and controller animations, so playback +resumes from the current `Progress`. Both calls are idempotent and no-ops on a +default `LoadedComposition`. + +`CanRestartAnimations(animation)` returns false when the graph cannot be +restarted faithfully, for example when another object references an implicit +controller that a restart would replace. Both calls are then no-ops and the +animations stay running, so a host can keep advertising `IAnimatedVisual2`. +Restart state is shared by copies of the same `LoadedComposition`. + +### Hosting in AnimatedVisualPlayer + +`LottieVisualSource.cpp` and `LottieVisualSource.h` adapt a buffer to +`Microsoft.UI.Xaml.Controls.IAnimatedVisualSource2`, replacing per-animation +LottieGen classes. Compile `LottieVisualSource.cpp` alongside `LottieRuntime.cpp` +with the same projection flag; it also needs the C++/WinRT projection of +Microsoft.UI.Xaml 2.8 (WinUI 2) or the Windows App SDK (WinUI 3). + +```cpp +#include + +namespace Lottie = CommunityToolkit::WinUI2::Lottie; + +// One RCDATA resource per UAP variant; the highest available contract wins. +static constexpr Lottie::EmbeddedCompositionVariant variants[]{ + { 15, L"SPINNER_UAP15" }, + { 7, L"SPINNER_UAP7" }, +}; + +static int anchor; +auto bytes = Lottie::LoadEmbeddedComposition(&anchor, variants); +player.Source(Lottie::CreateAnimatedVisualSource(bytes)); +``` + +`CreateAnimatedVisualSource` does not copy the buffer, so pass one that outlives +the source, such as an embedded resource. The source: + +- exposes the metadata's duration, frame rate, size and markers; +- forwards `SetColorProperty` to every live and future visual, ignoring names + that are not bound properties. `IAnimatedVisualSource2` has no scalar setter, + so use the free function `SetScalarProperty(source, name, value)` for scalars; +- creates visuals that implement `IAnimatedVisual2`, so + `AnimationOptimization="Resources"` stops their animations while idle, and + `IClosable`; +- for animations with images, also implements `IDynamicAnimatedVisualSource` + and `INotifyPropertyChanged`. + +`AnimatedVisualSourceOptions` reproduces the behaviour of each LottieGen +version's generated code: + +| Option | Default | Effect | +|---|---|---| +| `Markers` | `FirstWins` | `FirstWins` keeps the first marker of each name; `Unique` sanitizes names and suffixes duplicates with `_`. | +| `IncludeFinalFrameMarkers` | `true` | Whether a marker on the final frame is kept. | +| `ReportLoadErrors` | `false` | Return null and report the message through `diagnostics` instead of throwing. | +| `AsynchronousImageLoading` | `false` | Return null until every image has loaded, then raise `AnimatedVisualInvalidated`. | + +`LoadCompositionWithMetadata` requires a metadata table and rejects negative +duration/dimensions/frame rate/marker duration, nonfinite numeric metadata, +invalid string/property-set indices and a theme index that refers to an owned +property set. Missing markers mean an empty vector; the theme sentinel means +`nullptr`. These are explicit format conventions, not exception fallbacks. +`LoadComposition` retains its original Visual-only contract and can still load +buffers without metadata. + +## Validation and safety + +The reader verifies the FlatBuffer identifier and structure, range-checks every +node index, rejects unsupported schema or API-contract versions, detects geometry +cycles, and limits recursive visual, shape, and geometry traversal to 128 levels. +Malformed input throws `winrt::hresult_invalid_argument`; unsupported content +throws `winrt::hresult_not_implemented`. + +## Validation tool + +`LottieRuntimeTool.vcxproj` builds `LottieRuntime.exe`, a WinUI 2 validation and +inspection harness that compiles the reader directly. + +MSBuild restores the `flatbuffers` port from the root `vcpkg.json` before native +compilation. The manifest pins the registry baseline and FlatBuffers version. +Headers, tools, and the upstream license are restored under `vcpkg_installed`; +the repository does not carry a copy of the FlatBuffers headers. + +The build selects vcpkg in this order: `FlatBuffersVcpkgRoot`, `VcpkgRoot`, +`VCPKG_ROOT`, Visual Studio's bundled `VC\vcpkg`, then a repo-local `.vcpkg` +checkout. If none is installed, the first native build fetches and bootstraps +the repo-local copy at the manifest's baseline. Git, PowerShell, the MSVC C++ +tools, and network access are required for that first restore. Subsequent +builds reuse installed packages and vcpkg's binary cache. + +The restore runs vcpkg explicitly; `vcpkg integrate install` is unnecessary. +User-wide vcpkg auto-linking is disabled for this header-only consumer. Managed +builds do not restore vcpkg dependencies. Packing `LottieGen` also restores the +port to include the native headers and license. IDE design-time builds skip restore. + +Defaults are `x64-windows` for x64 and `arm64-windows` for ARM64, with native-host +`flatc` installed through the port's host dependency. Override +`FlatBuffersVcpkgTriplet`, `FlatBuffersVcpkgHostTriplet`, or +`FlatBuffersVcpkgInstalledDir` when using a different layout. + +An explicit `/p:FlatBuffersIncludeDirectory=C:\deps\flatbuffers\include` +skips vcpkg discovery and restore. That directory must contain FlatBuffers +25.2.10 headers; the generated binding checks the version at compile time. +An explicitly selected vcpkg root without `vcpkg.exe` is an error. + +### Package layout and private FlatBuffers versions + +The `LottieGen` NuGet package contains `LottieRuntime\lottie_comp.fbs`, the native +`.cpp` files under `LottieRuntime`, and all headers under `inc\lottiecomp`: +`LottieRuntime.h`, `LottieVisualSource.h`, `Generated\lottie_comp_generated.h`, +and `flatbuffers\*.h`. The port's upstream license is included as +`LottieRuntime\flatbuffers.LICENSE.txt`. Add `inc\lottiecomp` to the compiler's +include paths when using the packaged reader. + +To use a private FlatBuffers version, regenerate the binding with that version's +`flatc.exe` and compile against its matching headers. From the extracted package +root: + +```powershell +& C:\deps\flatbuffers\flatc.exe --cpp --scoped-enums -o .\inc\lottiecomp\Generated .\LottieRuntime\lottie_comp.fbs +``` + +Put the private FlatBuffers include directory before `inc\lottiecomp` in the +compiler's include search order, or replace `inc\lottiecomp\flatbuffers` with +that version's headers. The generated binding's version assertion remains in +force. Keep the schema and generator options unchanged to preserve the format. + +```powershell +& "C:\Program Files\Microsoft Visual Studio\18\Professional\Common7\Tools\Launch-VsDevShell.ps1" -SkipAutomaticLocation +msbuild .\source\LottieRuntime\LottieRuntimeTool.vcxproj /p:Platform=x64 /p:Configuration=Release +``` + +The executable is written to: + +```text +source\LottieRuntime\x64\Release\LottieRuntime.exe +``` + +It validates a buffer by default, prints the interpreted Composition hierarchy +with `--dump`, or displays and animates it with `--show`: + +```powershell +.\source\LottieRuntime\x64\Release\LottieRuntime.exe Animation.lcomp +.\source\LottieRuntime\x64\Release\LottieRuntime.exe Animation.lcomp --dump +.\source\LottieRuntime\x64\Release\LottieRuntime.exe Animation.lcomp --show +``` + +### Focused native metadata tests + +`tests\LottieRuntime.Tests\MetadataTests.cpp` exercises the native API, malformed +metadata, buffer verification, the legacy no-metadata contract, and theme-cache +identity, including a child's expression referencing its not-yet-initialized +parent's owned properties, image/brush cache identity, image reuse across new +trees, and invalid image-cache descriptors. It uses the existing generated schema +and vcpkg's FlatBuffers headers, without an additional test framework. The harness initializes XAML +on its dispatcher thread and uses its host visual's compositor to exercise image +assets through `LoadedImageSurface`; its manifest declares the Windows version +required for desktop XAML hosting. +From an x64 Visual Studio Developer Command Prompt at the repository root: + +```cmd +msbuild source\LottieRuntime\LottieRuntimeTool.vcxproj /t:RestoreFlatBuffers /p:Platform=x64 +mkdir tests\LottieRuntime.Tests\bin +cl /nologo /std:c++20 /EHsc /W4 /WX /DWIN32_LEAN_AND_MEAN /DNOMINMAX /DLOTTIE_RUNTIME_WINUI2 /Ivcpkg_installed\x64-windows\include tests\LottieRuntime.Tests\MetadataTests.cpp /Fotests\LottieRuntime.Tests\bin\MetadataTests.obj /Fetests\LottieRuntime.Tests\bin\MetadataTests.exe /link /MANIFEST:EMBED /MANIFESTINPUT:tests\LottieRuntime.Tests\MetadataTests.manifest CoreMessaging.lib d2d1.lib dxguid.lib ole32.lib shcore.lib shlwapi.lib windowsapp.lib +tests\LottieRuntime.Tests\bin\MetadataTests.exe +``` + +Pass optional `.lcomp` paths to also load real generator output and print its +dimensions, duration, frame rate, marker count, and realized image count. For +image-bearing files the runner also creates another tree with the returned image +descriptors and asserts that every image object is reused rather than reloaded. +Prefix the paths with `--legacy` to exercise the Visual-only `LoadComposition` +path instead, separating graph-realization failures from metadata validation. + +### Visual source tests + +`tests\LottieRuntime.Tests\VisualSourceTests.cpp` exercises `LottieVisualSource` +on each `.lcomp` path passed to it, checking: + +- duration, markers and image detection; +- that `IAnimatedVisual2` stops and restarts animations; +- that bound theme colors and scalars reach live and later visuals, and unbound + names are ignored; +- that `Close` releases the visual; +- for image assets, that another compositor throws by default and is reported + through `diagnostics` with `ReportLoadErrors`. + +It includes `LottieVisualSource.cpp` directly so it can read each visual's theme +properties. + +It needs a C++/WinRT projection that includes Microsoft.UI.Xaml 2.8. Generate it +with cppwinrt from the `Microsoft.UI.Xaml` 2.8 and `Microsoft.Web.WebView2` +NuGet packages (substitute their local paths): + +```cmd +msbuild source\LottieRuntime\LottieRuntimeTool.vcxproj /t:RestoreFlatBuffers /p:Platform=x64 +cppwinrt.exe -base -in sdk+ -in \lib\uap10.0\Microsoft.UI.Xaml.winmd -in \lib\Microsoft.Web.WebView2.Core.winmd -out tests\LottieRuntime.Tests\bin\mux +mkdir tests\LottieRuntime.Tests\bin\vst +cl /nologo /std:c++20 /EHsc /W4 /WX /bigobj /DWIN32_LEAN_AND_MEAN /DNOMINMAX /DLOTTIE_RUNTIME_WINUI2 /Itests\LottieRuntime.Tests\bin\mux /Ivcpkg_installed\x64-windows\include /Isource\LottieRuntime tests\LottieRuntime.Tests\VisualSourceTests.cpp source\LottieRuntime\LottieRuntime.cpp /Fotests\LottieRuntime.Tests\bin\vst\ /Fetests\LottieRuntime.Tests\bin\VisualSourceTests.exe /link /MANIFEST:EMBED /MANIFESTINPUT:tests\LottieRuntime.Tests\MetadataTests.manifest CoreMessaging.lib d2d1.lib dxguid.lib ole32.lib shcore.lib shlwapi.lib windowsapp.lib +tests\LottieRuntime.Tests\bin\VisualSourceTests.exe Animation.lcomp +``` diff --git a/tests/CompDataFlatbuffer.Tests/CompDataFlatbuffer.Tests.csproj b/tests/CompDataFlatbuffer.Tests/CompDataFlatbuffer.Tests.csproj new file mode 100644 index 00000000..5eaab357 --- /dev/null +++ b/tests/CompDataFlatbuffer.Tests/CompDataFlatbuffer.Tests.csproj @@ -0,0 +1,39 @@ + + + + net9.0 + latest + enable + false + false + CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Tests + CompDataFlatbuffer.Tests + false + + + <_SourceDir>..\..\source\ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/CompDataFlatbuffer.Tests/CompositionTreeDumper.cs b/tests/CompDataFlatbuffer.Tests/CompositionTreeDumper.cs new file mode 100644 index 00000000..ccc2fab0 --- /dev/null +++ b/tests/CompDataFlatbuffer.Tests/CompositionTreeDumper.cs @@ -0,0 +1,851 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable enable + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Numerics; +using System.Text; +using CommunityToolkit.WinUI.Lottie.WinCompData; +using CommunityToolkit.WinUI.Lottie.WinCompData.MetaData; +using CommunityToolkit.WinUI.Lottie.WinCompData.Mgce; +using CommunityToolkit.WinUI.Lottie.WinCompData.Mgcg; +using CommunityToolkit.WinUI.Lottie.WinUIXamlMediaData; +using Expressions = CommunityToolkit.WinUI.Lottie.WinCompData.Expressions; +using Wui = CommunityToolkit.WinUI.Lottie.WinCompData.Wui; + +namespace CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Tests +{ + /// + /// Renders a WinCompData graph as canonical text. + /// + /// + /// Two graphs produce identical text if and only if they are structurally + /// equivalent, including the sharing of nodes: each node is given an id the first + /// time it is reached by a depth first walk from the root, and every later reference + /// to it is written as that id. So a graph in which two parents share one child + /// cannot produce the same text as one in which they have a child each. + /// + /// This is the oracle for the round trip tests. It is deliberately independent of + /// both the serializer and the deserializer, and it fails loudly on a node type it + /// does not know about, so that a type added to WinCompData cannot silently escape + /// comparison. + /// + static class CompositionTreeDumper + { + /// + /// Renders a graph as canonical text. + /// + /// The root of the graph. + /// The canonical text of the graph. + public static string Dump(Visual root) + { + var writer = new Writer(); + writer.WriteVisual(root); + return writer.ToString(); + } + + sealed class Writer + { + readonly StringBuilder _builder = new StringBuilder(); + + // Ids are assigned per object, in the order that the objects are first + // reached. Reference equality is what matters here: two distinct objects with + // identical contents are different nodes and must get different ids. + readonly Dictionary _ids = + new Dictionary(ReferenceEqualityComparer.Instance); + + int _indent; + + public override string ToString() => _builder.ToString(); + + public void WriteVisual(Visual? value) + { + if (WriteNodeHeader(value, "Visual")) + { + return; + } + + WriteCompositionObject(value!); + + WriteOptional("BorderMode", value!.BorderMode); + WriteOptional("CenterPoint", value.CenterPoint); + WriteChild("Clip", value.Clip, WriteClip); + WriteOptional("IsVisible", value.IsVisible); + WriteOptional("Offset", value.Offset); + WriteOptional("Opacity", value.Opacity); + WriteOptional("RotationAngleInDegrees", value.RotationAngleInDegrees); + WriteOptional("RotationAxis", value.RotationAxis); + WriteOptional("Scale", value.Scale); + WriteOptional("Size", value.Size); + WriteOptional("TransformMatrix", value.TransformMatrix); + + if (value is ContainerVisual container) + { + WriteList("Children", container.Children, WriteVisual); + } + + switch (value) + { + case ShapeVisual shapeVisual: + WriteList("Shapes", shapeVisual.Shapes, WriteShape); + WriteChild("ViewBox", shapeVisual.ViewBox, WriteViewBox); + break; + case SpriteVisual spriteVisual: + WriteChild("Brush", spriteVisual.Brush, WriteBrush); + WriteChild("Shadow", spriteVisual.Shadow, WriteShadow); + break; + case LayerVisual layerVisual: + WriteChild("Shadow", layerVisual.Shadow, WriteShadow); + break; + case ContainerVisual _: + break; + default: + throw new InvalidOperationException($"Unexpected visual {value.Type}."); + } + + _indent--; + } + + public void WriteShape(CompositionShape? value) + { + if (WriteNodeHeader(value, "Shape")) + { + return; + } + + WriteCompositionObject(value!); + + WriteOptional("CenterPoint", value!.CenterPoint); + WriteOptional("Offset", value.Offset); + WriteOptional("RotationAngleInDegrees", value.RotationAngleInDegrees); + WriteOptional("Scale", value.Scale); + WriteOptional("TransformMatrix", value.TransformMatrix); + + switch (value) + { + case CompositionContainerShape containerShape: + WriteList("Shapes", containerShape.Shapes, WriteShape); + break; + case CompositionSpriteShape spriteShape: + WriteChild("FillBrush", spriteShape.FillBrush, WriteBrush); + WriteChild("StrokeBrush", spriteShape.StrokeBrush, WriteBrush); + WriteChild("Geometry", spriteShape.Geometry, WriteGeometry); + WriteOptional("IsStrokeNonScaling", spriteShape.IsStrokeNonScaling); + WriteOptional("StrokeDashOffset", spriteShape.StrokeDashOffset); + WriteFloats("StrokeDashArray", spriteShape.StrokeDashArray); + WriteOptional("StrokeDashCap", spriteShape.StrokeDashCap); + WriteOptional("StrokeStartCap", spriteShape.StrokeStartCap); + WriteOptional("StrokeEndCap", spriteShape.StrokeEndCap); + WriteOptional("StrokeLineJoin", spriteShape.StrokeLineJoin); + WriteOptional("StrokeMiterLimit", spriteShape.StrokeMiterLimit); + WriteOptional("StrokeThickness", spriteShape.StrokeThickness); + break; + default: + throw new InvalidOperationException($"Unexpected shape {value.Type}."); + } + + _indent--; + } + + public void WriteGeometry(CompositionGeometry? value) + { + if (WriteNodeHeader(value, "Geometry")) + { + return; + } + + WriteCompositionObject(value!); + + WriteOptional("TrimStart", value!.TrimStart); + WriteOptional("TrimEnd", value.TrimEnd); + WriteOptional("TrimOffset", value.TrimOffset); + + switch (value) + { + case CompositionPathGeometry pathGeometry: + WriteChild( + "Path", + pathGeometry.Path is null ? null : (CanvasGeometry)pathGeometry.Path.Source, + WriteCanvasGeometry); + break; + case CompositionRoundedRectangleGeometry roundedRectangle: + WriteOptional("Offset", roundedRectangle.Offset); + WriteOptional("Size", roundedRectangle.Size); + Write("CornerRadius", roundedRectangle.CornerRadius); + break; + case CompositionRectangleGeometry rectangle: + WriteOptional("Offset", rectangle.Offset); + WriteOptional("Size", rectangle.Size); + break; + case CompositionEllipseGeometry ellipse: + Write("Center", ellipse.Center); + Write("Radius", ellipse.Radius); + break; + default: + throw new InvalidOperationException($"Unexpected geometry {value.Type}."); + } + + _indent--; + } + + public void WriteBrush(CompositionBrush? value) + { + if (WriteNodeHeader(value, "Brush")) + { + return; + } + + WriteCompositionObject(value!); + + switch (value) + { + case CompositionColorBrush colorBrush: + WriteOptional("Color", colorBrush.Color); + break; + case CompositionMaskBrush maskBrush: + WriteChild("Source", maskBrush.Source, WriteBrush); + WriteChild("Mask", maskBrush.Mask, WriteBrush); + break; + case CompositionSurfaceBrush surfaceBrush: + WriteChild("Surface", surfaceBrush.Surface, WriteSurface); + break; + case CompositionEffectBrush effectBrush: + var effect = effectBrush.GetEffectFactory().Effect; + WriteChild("Effect", effect, WriteEffect); + + foreach (var source in effect.Sources) + { + WriteChild( + $"Source({source.Name})", + effectBrush.GetSourceParameter(source.Name), + WriteBrush); + } + + break; + case CompositionLinearGradientBrush _: + case CompositionRadialGradientBrush _: + break; + default: + throw new InvalidOperationException($"Unexpected brush {value!.Type}."); + } + + if (value is CompositionGradientBrush gradientBrush) + { + WriteOptional("AnchorPoint", gradientBrush.AnchorPoint); + WriteOptional("CenterPoint", gradientBrush.CenterPoint); + WriteList("ColorStops", gradientBrush.ColorStops, WriteGradientStop); + WriteOptional("ExtendMode", gradientBrush.ExtendMode); + WriteOptional("InterpolationSpace", gradientBrush.InterpolationSpace); + WriteOptional("MappingMode", gradientBrush.MappingMode); + WriteOptional("Offset", gradientBrush.Offset); + WriteOptional("RotationAngleInDegrees", gradientBrush.RotationAngleInDegrees); + WriteOptional("Scale", gradientBrush.Scale); + WriteOptional("TransformMatrix", gradientBrush.TransformMatrix); + + switch (gradientBrush) + { + case CompositionLinearGradientBrush linear: + WriteOptional("StartPoint", linear.StartPoint); + WriteOptional("EndPoint", linear.EndPoint); + break; + case CompositionRadialGradientBrush radial: + WriteOptional("EllipseCenter", radial.EllipseCenter); + WriteOptional("EllipseRadius", radial.EllipseRadius); + WriteOptional("GradientOriginOffset", radial.GradientOriginOffset); + break; + } + } + + _indent--; + } + + public void WriteGradientStop(CompositionColorGradientStop? value) + { + if (WriteNodeHeader(value, "GradientStop")) + { + return; + } + + WriteCompositionObject(value!); + Write("Color", value!.Color); + Write("Offset", value.Offset); + _indent--; + } + + public void WriteViewBox(CompositionViewBox? value) + { + if (WriteNodeHeader(value, "ViewBox")) + { + return; + } + + WriteCompositionObject(value!); + Write("Size", value!.Size); + _indent--; + } + + public void WriteClip(CompositionClip? value) + { + if (WriteNodeHeader(value, "Clip")) + { + return; + } + + WriteCompositionObject(value!); + WriteOptional("CenterPoint", value!.CenterPoint); + WriteOptional("Scale", value.Scale); + + switch (value) + { + case InsetClip inset: + WriteOptional("LeftInset", inset.LeftInset); + WriteOptional("RightInset", inset.RightInset); + WriteOptional("TopInset", inset.TopInset); + WriteOptional("BottomInset", inset.BottomInset); + break; + case CompositionGeometricClip geometric: + WriteChild("Geometry", geometric.Geometry, WriteGeometry); + break; + default: + throw new InvalidOperationException($"Unexpected clip {value.Type}."); + } + + _indent--; + } + + public void WriteShadow(CompositionShadow? value) + { + if (WriteNodeHeader(value, "Shadow")) + { + return; + } + + WriteCompositionObject(value!); + + switch (value) + { + case DropShadow dropShadow: + WriteOptional("BlurRadius", dropShadow.BlurRadius); + WriteOptional("Color", dropShadow.Color); + WriteChild("Mask", dropShadow.Mask, WriteBrush); + WriteOptional("Offset", dropShadow.Offset); + WriteOptional("Opacity", dropShadow.Opacity); + WriteOptional("SourcePolicy", dropShadow.SourcePolicy); + break; + default: + throw new InvalidOperationException($"Unexpected shadow {value!.Type}."); + } + + _indent--; + } + + public void WriteSurface(ICompositionSurface? value) + { + if (WriteNodeHeader(value, "Surface")) + { + return; + } + + switch (value) + { + case CompositionVisualSurface visualSurface: + WriteCompositionObject(visualSurface); + WriteChild("SourceVisual", visualSurface.SourceVisual, WriteVisual); + WriteOptional("SourceSize", visualSurface.SourceSize); + WriteOptional("SourceOffset", visualSurface.SourceOffset); + break; + case LoadedImageSurfaceFromUri fromUri: + WriteLine($"Kind: FromUri"); + WriteLine($"Uri: {fromUri.Uri}"); + break; + case LoadedImageSurfaceFromStream fromStream: + WriteLine($"Kind: FromStream"); + WriteLine($"Bytes: {Convert.ToBase64String(fromStream.Bytes)}"); + break; + default: + throw new InvalidOperationException($"Unexpected surface {value!.GetType().Name}."); + } + + _indent--; + } + + public void WriteEffect(GraphicsEffectBase? value) + { + if (WriteNodeHeader(value, "Effect")) + { + return; + } + + WriteLine($"Sources: {string.Join(", ", value!.Sources.Select(s => s.Name))}"); + + switch (value) + { + case CompositeEffect composite: + Write("Mode", composite.Mode); + break; + case GaussianBlurEffect blur: + Write("BlurAmount", blur.BlurAmount); + break; + default: + throw new InvalidOperationException($"Unexpected effect {value.Type}."); + } + + _indent--; + } + + public void WriteEasing(CompositionEasingFunction? value) + { + if (WriteNodeHeader(value, "Easing")) + { + return; + } + + WriteCompositionObject(value!); + + switch (value) + { + case LinearEasingFunction _: + break; + case CubicBezierEasingFunction cubicBezier: + Write("ControlPoint1", cubicBezier.ControlPoint1); + Write("ControlPoint2", cubicBezier.ControlPoint2); + break; + case StepEasingFunction step: + WriteOptional("StepCount", step.StepCount); + WriteOptional("InitialStep", step.InitialStep); + WriteOptional("FinalStep", step.FinalStep); + WriteOptional("IsInitialStepSingleFrame", step.IsInitialStepSingleFrame); + WriteOptional("IsFinalStepSingleFrame", step.IsFinalStepSingleFrame); + break; + default: + throw new InvalidOperationException($"Unexpected easing {value!.Type}."); + } + + _indent--; + } + + public void WriteAnimation(CompositionAnimation? value) + { + if (WriteNodeHeader(value, "Animation")) + { + return; + } + + WriteCompositionObject(value!); + WriteLine($"Target: {Text(value!.Target)}"); + + // ReferenceParameters is a dictionary, so it is sorted to make the dump + // independent of hash ordering. + foreach (var parameter in value.ReferenceParameters.OrderBy(p => p.Key, StringComparer.Ordinal)) + { + WriteChild($"Reference({parameter.Key})", parameter.Value, WriteCompositionObjectReference); + } + + switch (value) + { + case ExpressionAnimation expression: + // Expressions are compared as text because that is how they are + // stored in the buffer, and how Windows.UI.Composition accepts them. + WriteLine($"Expression: {expression.Expression.ToText()}"); + break; + case KeyFrameAnimation_ keyFrameAnimation: + WriteLine($"Duration: {keyFrameAnimation.Duration.Ticks}"); + + if (value is ColorKeyFrameAnimation color) + { + Write("InterpolationColorSpace", color.InterpolationColorSpace); + } + + foreach (var keyFrame in keyFrameAnimation.KeyFrames) + { + WriteKeyFrame(keyFrame); + } + + break; + default: + throw new InvalidOperationException($"Unexpected animation {value.Type}."); + } + + _indent--; + } + + void WriteKeyFrame(KeyFrameAnimation_.KeyFrame value) + { + WriteLine($"KeyFrame @{Text(value.Progress)}"); + _indent++; + WriteChild("Easing", value.Easing, WriteEasing); + + switch (value) + { + case KeyFrameAnimation_.ExpressionKeyFrame expression: + WriteLine($"Expression: {expression.Expression.ToText()}"); + break; + case KeyFrameAnimation.ValueKeyFrame scalar: + WriteLine($"Value: {Text(scalar.Value)}"); + break; + case KeyFrameAnimation.ValueKeyFrame boolean: + WriteLine($"Value: {boolean.Value}"); + break; + case KeyFrameAnimation.ValueKeyFrame vector2: + WriteLine($"Value: {Text(vector2.Value)}"); + break; + case KeyFrameAnimation.ValueKeyFrame vector3: + WriteLine($"Value: {Text(vector3.Value)}"); + break; + case KeyFrameAnimation.ValueKeyFrame vector4: + WriteLine($"Value: {Text(vector4.Value)}"); + break; + case KeyFrameAnimation.ValueKeyFrame color: + WriteLine($"Value: {Text(color.Value)}"); + break; + case KeyFrameAnimation.ValueKeyFrame path: + WriteChild("Value", (CanvasGeometry)path.Value.Source, WriteCanvasGeometry); + break; + default: + throw new InvalidOperationException($"Unexpected key frame {value.Type}."); + } + + _indent--; + } + + public void WriteCanvasGeometry(CanvasGeometry? value) + { + if (WriteNodeHeader(value, "CanvasGeometry")) + { + return; + } + + switch (value) + { + case CanvasGeometry.Combination combination: + WriteChild("A", combination.A, WriteCanvasGeometry); + WriteChild("B", combination.B, WriteCanvasGeometry); + Write("CombineMode", combination.CombineMode); + Write("Matrix", combination.Matrix); + break; + case CanvasGeometry.TransformedGeometry transformed: + WriteChild("Source", transformed.SourceGeometry, WriteCanvasGeometry); + Write("TransformMatrix", transformed.TransformMatrix); + break; + case CanvasGeometry.Group group: + Write("FilledRegionDetermination", group.FilledRegionDetermination); + WriteList("Geometries", group.Geometries, WriteCanvasGeometry); + break; + case CanvasGeometry.Path path: + Write("FilledRegionDetermination", path.FilledRegionDetermination); + + foreach (var command in path.Commands) + { + WriteLine(Text(command)); + } + + break; + case CanvasGeometry.Ellipse ellipse: + WriteLine( + $"Ellipse: {Text(ellipse.X)} {Text(ellipse.Y)} " + + $"{Text(ellipse.RadiusX)} {Text(ellipse.RadiusY)}"); + break; + case CanvasGeometry.RoundedRectangle rectangle: + WriteLine( + $"RoundedRectangle: {Text(rectangle.X)} {Text(rectangle.Y)} " + + $"{Text(rectangle.W)} {Text(rectangle.H)} " + + $"{Text(rectangle.RadiusX)} {Text(rectangle.RadiusY)}"); + break; + default: + throw new InvalidOperationException($"Unexpected canvas geometry {value!.Type}."); + } + + _indent--; + } + + void WriteCompositionObjectReference(CompositionObject? value) + { + switch (value) + { + case null: + WriteLine("null"); + break; + case Visual visual: + WriteVisual(visual); + break; + case CompositionShape shape: + WriteShape(shape); + break; + case CompositionGeometry geometry: + WriteGeometry(geometry); + break; + case CompositionBrush brush: + WriteBrush(brush); + break; + case CompositionAnimation animation: + WriteAnimation(animation); + break; + case CompositionEasingFunction easing: + WriteEasing(easing); + break; + case CompositionPropertySet propertySet: + WritePropertySet(propertySet); + break; + case CompositionVisualSurface surface: + WriteSurface(surface); + break; + case CompositionClip clip: + WriteClip(clip); + break; + case AnimationController controller: + WriteController(controller); + break; + case CompositionShadow shadow: + WriteShadow(shadow); + break; + case CompositionColorGradientStop stop: + WriteGradientStop(stop); + break; + case CompositionViewBox viewBox: + WriteViewBox(viewBox); + break; + default: + throw new InvalidOperationException($"Unexpected reference to {value.Type}."); + } + } + + void WritePropertySet(CompositionPropertySet? value) + { + if (WriteNodeHeader(value, "PropertySet")) + { + return; + } + + WritePropertySetContents(value!); + _indent--; + } + + void WriteController(AnimationController? value) + { + if (WriteNodeHeader(value, "Controller")) + { + return; + } + + WriteLine($"IsCustom: {value!.IsCustom}"); + WriteLine($"IsPaused: {value.IsPaused}"); + WriteLine($"TargetProperty: {Text(value.TargetProperty)}"); + WriteCompositionObject(value); + _indent--; + } + + // Writes the state that every CompositionObject has. The property set is + // written inline rather than as a node, because it belongs to the object. + void WriteCompositionObject(CompositionObject value) + { + if (value.Comment is not null) + { + WriteLine($"Comment: {value.Comment}"); + } + + // Properties is created on demand, so it is only written when the object + // actually has some, which is exactly when it is serialized. + var properties = value.Properties; + if (value.Type != CompositionObjectType.CompositionPropertySet && + (properties.Names.Count > 0 || properties.Animators.Any())) + { + WriteLine("Properties"); + _indent++; + WritePropertySetContents(properties); + _indent--; + } + + foreach (var animator in value.Animators) + { + WriteLine($"Animator: {animator.AnimatedProperty}"); + _indent++; + WriteChild("Animation", animator.Animation, WriteAnimation); + + if (animator.Controller is not null) + { + WriteChild("Controller", animator.Controller, WriteController); + } + + _indent--; + } + } + + void WritePropertySetContents(CompositionPropertySet value) + { + // Names is a SortedDictionary, so this order is already canonical. + foreach (var (name, type) in value.Names.Select(n => (n.Key, n.Value))) + { + switch (type) + { + case PropertySetValueType.Color: + value.TryGetColor(name, out var color); + WriteLine($"{name}: {Text(color!.Value)}"); + break; + case PropertySetValueType.Scalar: + value.TryGetScalar(name, out var scalar); + WriteLine($"{name}: {Text(scalar!.Value)}"); + break; + case PropertySetValueType.Vector2: + value.TryGetVector2(name, out var vector2); + WriteLine($"{name}: {Text(vector2!.Value)}"); + break; + case PropertySetValueType.Vector3: + value.TryGetVector3(name, out var vector3); + WriteLine($"{name}: {Text(vector3!.Value)}"); + break; + case PropertySetValueType.Vector4: + value.TryGetVector4(name, out var vector4); + WriteLine($"{name}: {Text(vector4!.Value)}"); + break; + default: + throw new InvalidOperationException($"Unexpected property {type}."); + } + } + + foreach (var animator in value.Animators) + { + WriteLine($"Animator: {animator.AnimatedProperty}"); + _indent++; + WriteChild("Animation", animator.Animation, WriteAnimation); + _indent--; + } + } + + // Writes the "Kind #id" line that starts a node, and returns true if the node + // has been written before, in which case the caller must not write it again. + // Leaves the indent increased when it returns false. + bool WriteNodeHeader(object? value, string category) + { + if (value is null) + { + WriteLine($"{category}: null"); + return true; + } + + if (_ids.TryGetValue(value, out var existing)) + { + WriteLine($"{category} #{existing} (shared)"); + return true; + } + + var id = _ids.Count; + _ids.Add(value, id); + WriteLine($"{category} #{id} {TypeNameOf(value)}"); + _indent++; + return false; + } + + static string TypeNameOf(object value) + => value switch + { + CompositionObject compositionObject => compositionObject.Type.ToString(), + CanvasGeometry canvasGeometry => canvasGeometry.Type.ToString(), + GraphicsEffectBase effect => effect.Type.ToString(), + LoadedImageSurface surface => surface.Type.ToString(), + _ => value.GetType().Name, + }; + + void WriteChild(string name, T? value, Action write) + where T : class + { + WriteLine($"{name}:"); + _indent++; + write(value); + _indent--; + } + + void WriteList(string name, IEnumerable values, Action write) + where T : class + { + var array = values.ToArray(); + if (array.Length == 0) + { + return; + } + + WriteLine($"{name}: [{array.Length}]"); + _indent++; + foreach (var value in array) + { + write(value); + } + + _indent--; + } + + // Written only when the property has a value, so that "never set" and "set to + // the default" stay distinguishable, exactly as they are in the buffer. + void WriteOptional(string name, T? value) + where T : struct + { + if (value.HasValue) + { + WriteLine($"{name}: {Text(value.Value)}"); + } + } + + void Write(string name, T value) + where T : struct + => WriteLine($"{name}: {Text(value)}"); + + void WriteFloats(string name, IEnumerable values) + { + var array = values.ToArray(); + if (array.Length > 0) + { + WriteLine($"{name}: {string.Join(", ", array.Select(v => Text(v)))}"); + } + } + + void WriteLine(string text) + => _builder.Append(' ', _indent * 2).Append(text).Append('\n'); + + // Values are formatted with round trip precision and the invariant culture, so + // that the dump is exact and machine independent. + static string Text(object? value) + => value switch + { + null => "null", + float f => f.ToString("R", CultureInfo.InvariantCulture), + Vector2 v => $"<{Text(v.X)}, {Text(v.Y)}>", + Vector3 v => $"<{Text(v.X)}, {Text(v.Y)}, {Text(v.Z)}>", + Vector4 v => $"<{Text(v.X)}, {Text(v.Y)}, {Text(v.Z)}, {Text(v.W)}>", + Matrix3x2 m => + $"[{Text(m.M11)}, {Text(m.M12)}, {Text(m.M21)}, " + + $"{Text(m.M22)}, {Text(m.M31)}, {Text(m.M32)}]", + Matrix4x4 m => + $"[{Text(m.M11)}, {Text(m.M12)}, {Text(m.M13)}, {Text(m.M14)}, " + + $"{Text(m.M21)}, {Text(m.M22)}, {Text(m.M23)}, {Text(m.M24)}, " + + $"{Text(m.M31)}, {Text(m.M32)}, {Text(m.M33)}, {Text(m.M34)}, " + + $"{Text(m.M41)}, {Text(m.M42)}, {Text(m.M43)}, {Text(m.M44)}]", + Wui.Color c => $"#{c.A:X2}{c.R:X2}{c.G:X2}{c.B:X2}", + CanvasPathBuilder.Command.BeginFigure begin => $"BeginFigure {Text(begin.StartPoint)}", + CanvasPathBuilder.Command.EndFigure end => $"EndFigure {end.FigureLoop}", + CanvasPathBuilder.Command.AddLine line => $"AddLine {Text(line.EndPoint)}", + CanvasPathBuilder.Command.AddCubicBezier bezier => + $"AddCubicBezier {Text(bezier.ControlPoint1)} " + + $"{Text(bezier.ControlPoint2)} {Text(bezier.EndPoint)}", + _ => value.ToString() ?? string.Empty, + }; + } + + sealed class ReferenceEqualityComparer : IEqualityComparer + { + internal static readonly ReferenceEqualityComparer Instance = new ReferenceEqualityComparer(); + + ReferenceEqualityComparer() + { + } + + bool IEqualityComparer.Equals(object? x, object? y) => ReferenceEquals(x, y); + + int IEqualityComparer.GetHashCode(object obj) + => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj); + } + } +} diff --git a/tests/CompDataFlatbuffer.Tests/Corpus.cs b/tests/CompDataFlatbuffer.Tests/Corpus.cs new file mode 100644 index 00000000..69bddd44 --- /dev/null +++ b/tests/CompDataFlatbuffer.Tests/Corpus.cs @@ -0,0 +1,141 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable enable + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using CommunityToolkit.WinUI.Lottie.CompMetadata; +using CommunityToolkit.WinUI.Lottie.LottieData; +using CommunityToolkit.WinUI.Lottie.LottieData.Serialization; +using CommunityToolkit.WinUI.Lottie.LottieMetadata; +using CommunityToolkit.WinUI.Lottie.LottieToWinComp; +using CommunityToolkit.WinUI.Lottie.WinCompData; +using IoPath = System.IO.Path; + +namespace CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Tests +{ + /// + /// Loads the Lottie files that the tests run against and translates them to + /// WinCompData graphs. + /// + static class Corpus + { + // The well known keys under which the translator stores its metadata. These are + // the same values that LottieGen uses to retrieve it. + static readonly Guid LottieMetadataKey = new Guid("EA3D6538-361A-4B1C-960D-50A6C35DC0B4"); + static readonly Guid PropertyBindingNamesKey = new Guid("A115C46A-254C-43E6-A3C7-9DE516C3C3C8"); + + /// + /// Gets the names of the Lottie files that the tests run against. + /// + /// A test case per Lottie file. + public static IEnumerable FileNames() + => Directory.EnumerateFiles(AssetsFolder, "*.json") + .Select(IoPath.GetFileName) + .OrderBy(name => name, StringComparer.Ordinal) + .Select(name => new object[] { name! }); + + static string AssetsFolder + { + get + { + // The tests run from the build output folder, so the repository root is + // found by walking up to the folder that contains the samples. + var directory = new DirectoryInfo(AppContext.BaseDirectory); + + while (directory is not null) + { + var candidate = IoPath.Combine(directory.FullName, "LottieSamples", "Assets"); + if (Directory.Exists(candidate)) + { + return candidate; + } + + directory = directory.Parent; + } + + throw new InvalidOperationException("Could not locate LottieSamples/Assets."); + } + } + + /// + /// Reads and translates one of the Lottie files. + /// + /// The name of the file within the samples folder. + /// The translated graph and the metadata that accompanies it. + public static TranslatedLottie Translate(string fileName) + { + using var stream = File.OpenRead(IoPath.Combine(AssetsFolder, fileName)); + + var lottie = LottieCompositionReader.ReadLottieCompositionFromJsonStream( + stream, + LottieCompositionReader.Options.IgnoreMatchNames, + out var readerIssues); + + if (lottie is null) + { + throw new InvalidOperationException( + $"Failed to read {fileName}: {string.Join("; ", readerIssues.Select(i => i.Description))}"); + } + + var result = LottieToWinCompTranslator.TryTranslateLottieComposition( + lottie, + new TranslatorConfiguration + { + AddCodegenDescriptions = true, + TranslatePropertyBindings = true, + + // The newest version is targeted so that the translation uses every + // feature it can, which gives the tests the widest coverage. + TargetUapVersion = uint.MaxValue, + }); + + if (result.RootVisual is null) + { + throw new InvalidOperationException($"Failed to translate {fileName}."); + } + + return new TranslatedLottie( + result.RootVisual, + checked((ushort)result.MinimumRequiredUapVersion), + result.SourceMetadata.TryGetValue(LottieMetadataKey, out var metadata) + ? (LottieCompositionMetadata)metadata + : null, + result.SourceMetadata.TryGetValue(PropertyBindingNamesKey, out var bindings) + ? (IReadOnlyList)bindings + : null, + (float)lottie.Width, + (float)lottie.Height); + } + + /// + /// A translated Lottie file, and everything needed to serialize it. + /// + /// The root of the translated graph. + /// The minimum UAP version needed to instantiate the graph. + /// Metadata about the source animation. + /// The property bindings that the graph exposes. + /// The width of the source animation. + /// The height of the source animation. + public sealed record TranslatedLottie( + Visual RootVisual, + ushort RequiredUapVersion, + LottieCompositionMetadata? Metadata, + IReadOnlyList? PropertyBindings, + float Width, + float Height) + { + /// + /// Serializes the graph. + /// + /// The serialized graph. + public byte[] Serialize() + => CompositionSerializer.Serialize( + RootVisual, RequiredUapVersion, Metadata, PropertyBindings, Width, Height); + } + } +} diff --git a/tests/CompDataFlatbuffer.Tests/CoverageTests.cs b/tests/CompDataFlatbuffer.Tests/CoverageTests.cs new file mode 100644 index 00000000..b06281cf --- /dev/null +++ b/tests/CompDataFlatbuffer.Tests/CoverageTests.cs @@ -0,0 +1,475 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable enable + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using CommunityToolkit.WinUI.Lottie.WinCompData; +using CommunityToolkit.WinUI.Lottie.WinCompData.Mgc; +using CommunityToolkit.WinUI.Lottie.WinCompData.Mgce; +using CommunityToolkit.WinUI.Lottie.WinCompData.Mgcg; +using CommunityToolkit.WinUI.Lottie.WinUIXamlMediaData; +using Xunit; +using Expr = CommunityToolkit.WinUI.Lottie.WinCompData.Expressions; +using Wui = CommunityToolkit.WinUI.Lottie.WinCompData.Wui; + +namespace CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Tests +{ + /// + /// Verifies that every kind of node that a graph can contain survives serialization. + /// + /// + /// The sample animations exercise the parts of the object model that the translator + /// happens to emit for them, which is not all of it. This builds a graph that + /// contains at least one of every , every + /// shape, every path command and every effect, and + /// round trips that. Together with + /// this means a node type cannot be added to WinCompData without either being + /// handled here or failing the build. + /// + public class CoverageTests + { + [Fact] + public void AllCompositionObjectTypesAreCovered() + { + var covered = Collect(BuildGraph()) + .Select(o => o.Type) + .ToHashSet(); + + var missing = Enum.GetValues() + .Where(t => !covered.Contains(t)) + .ToArray(); + + Assert.True( + missing.Length == 0, + $"The coverage graph does not contain: {string.Join(", ", missing)}."); + } + + [Fact] + public void EveryNodeTypeSurvivesARoundTrip() + { + var root = BuildGraph(); + + var expected = CompositionTreeDumper.Dump(root); + var actual = CompositionTreeDumper.Dump( + CompositionDeserializer.Deserialize(CompositionSerializer.Serialize(root, 14, null, null, 100, 100))); + + Assert.Equal(expected, actual); + } + + // Builds a graph containing one of everything. It is not a sensible animation; + // its only job is to reach every branch of the serializer and the deserializer. + static Visual BuildGraph() + { + var c = new Compositor(); + + var root = c.CreateContainerVisual(); + root.Comment = "Root"; + root.Offset = new Vector3(1, 2, 3); + root.CenterPoint = new Vector3(4, 5, 6); + root.RotationAngleInDegrees = 45; + root.RotationAxis = new Vector3(0, 0, 1); + root.Scale = new Vector3(2, 2, 2); + root.Size = new Vector2(100, 100); + root.Opacity = 0.5f; + root.IsVisible = true; + root.BorderMode = CompositionBorderMode.Soft; + root.TransformMatrix = Matrix4x4.Identity; + + // Clips. An inset clip on the root, a geometric clip further down. + var insetClip = c.CreateInsetClip(); + insetClip.LeftInset = 1; + insetClip.RightInset = 2; + insetClip.TopInset = 3; + insetClip.BottomInset = 4; + root.Clip = insetClip; + + // Easings. + var linear = c.CreateLinearEasingFunction(); + var cubic = c.CreateCubicBezierEasingFunction(new Vector2(0.1f, 0.2f), new Vector2(0.3f, 0.4f)); + var step = c.CreateStepEasingFunction(3); + step.IsInitialStepSingleFrame = true; + step.IsFinalStepSingleFrame = true; + step.InitialStep = 1; + step.FinalStep = 2; + + // Every kind of key frame animation, using every kind of easing and both + // kinds of key frame (a value and an expression). + var scalarAnimation = c.CreateScalarKeyFrameAnimation(); + scalarAnimation.Duration = TimeSpan.FromSeconds(1); + scalarAnimation.InsertKeyFrame(0, 0, linear); + scalarAnimation.InsertKeyFrame(0.5f, 1, cubic); + scalarAnimation.InsertExpressionKeyFrame(1, Expr.Expression.Scalar("0"), step); + + var booleanAnimation = c.CreateBooleanKeyFrameAnimation(); + booleanAnimation.Duration = TimeSpan.FromSeconds(1); + booleanAnimation.InsertKeyFrame(0, false); + booleanAnimation.InsertKeyFrame(1, true); + + var colorAnimation = c.CreateColorKeyFrameAnimation(); + colorAnimation.Duration = TimeSpan.FromSeconds(1); + colorAnimation.InterpolationColorSpace = CompositionColorSpace.Hsl; + colorAnimation.InsertKeyFrame(0, Wui.Color.FromArgb(255, 1, 2, 3), linear); + colorAnimation.InsertKeyFrame(1, Wui.Color.FromArgb(0, 4, 5, 6), linear); + + var vector2Animation = c.CreateVector2KeyFrameAnimation(); + vector2Animation.Duration = TimeSpan.FromSeconds(1); + vector2Animation.InsertKeyFrame(0, new Vector2(1, 2), linear); + + var vector3Animation = c.CreateVector3KeyFrameAnimation(); + vector3Animation.Duration = TimeSpan.FromSeconds(1); + vector3Animation.InsertKeyFrame(0, new Vector3(1, 2, 3), linear); + + var vector4Animation = c.CreateVector4KeyFrameAnimation(); + vector4Animation.Duration = TimeSpan.FromSeconds(1); + vector4Animation.InsertKeyFrame(0, new Vector4(1, 2, 3, 4), linear); + + var pathAnimation = c.CreatePathKeyFrameAnimation(); + pathAnimation.Duration = TimeSpan.FromSeconds(1); + pathAnimation.InsertKeyFrame(0, new CompositionPath(BuildPathGeometry()), linear); + + // A property set that other objects reference through expressions. This is + // how the translator exposes theming properties. + var theme = c.CreatePropertySet(); + theme.InsertScalar("Scalar", 1); + theme.InsertVector2("Vector2", new Vector2(1, 2)); + theme.InsertVector3("Vector3", new Vector3(1, 2, 3)); + theme.InsertVector4("Vector4", new Vector4(1, 2, 3, 4)); + theme.InsertColor("Color", Wui.Color.FromArgb(255, 7, 8, 9)); + + var expressionAnimation = c.CreateExpressionAnimation(Expr.Expression.Scalar("_.Scalar")); + expressionAnimation.SetReferenceParameter("_", theme); + + // A custom controller, which is the only kind the format has to carry, since + // a default one is recreated on the other side. + var controller = c.CreateAnimationController(); + controller.Pause(); + + // Shapes. + var shapeVisual = c.CreateShapeVisual(); + shapeVisual.Size = new Vector2(100, 100); + shapeVisual.ViewBox = c.CreateViewBox(); + shapeVisual.ViewBox.Size = new Vector2(50, 50); + + var containerShape = c.CreateContainerShape(); + containerShape.CenterPoint = new Vector2(1, 2); + containerShape.Offset = new Vector2(3, 4); + containerShape.RotationAngleInDegrees = 90; + containerShape.Scale = new Vector2(2, 2); + containerShape.TransformMatrix = Matrix3x2.Identity; + shapeVisual.Shapes.Add(containerShape); + + // Every geometry type, each on its own sprite shape so that the sprite shape + // properties are exercised as well. + var ellipse = c.CreateEllipseGeometry(); + ellipse.Center = new Vector2(1, 2); + ellipse.Radius = new Vector2(3, 4); + ellipse.TrimStart = 0.1f; + ellipse.TrimEnd = 0.9f; + ellipse.TrimOffset = 0.05f; + + var rectangle = c.CreateRectangleGeometry(); + rectangle.Offset = new Vector2(1, 2); + rectangle.Size = new Vector2(3, 4); + + var roundedRectangle = c.CreateRoundedRectangleGeometry(); + roundedRectangle.Offset = new Vector2(1, 2); + roundedRectangle.Size = new Vector2(3, 4); + roundedRectangle.CornerRadius = new Vector2(5, 6); + + var pathGeometry = c.CreatePathGeometry(new CompositionPath(BuildPathGeometry())); + + var colorBrush = c.CreateColorBrush(Wui.Color.FromArgb(255, 10, 20, 30)); + + var linearGradient = c.CreateLinearGradientBrush(); + linearGradient.StartPoint = new Vector2(0, 0); + linearGradient.EndPoint = new Vector2(1, 1); + linearGradient.AnchorPoint = new Vector2(0.5f, 0.5f); + linearGradient.CenterPoint = new Vector2(0.5f, 0.5f); + linearGradient.ExtendMode = CompositionGradientExtendMode.Mirror; + linearGradient.InterpolationSpace = CompositionColorSpace.HslLinear; + linearGradient.ColorStops.Add(c.CreateColorGradientStop(0, Wui.Color.FromArgb(255, 0, 0, 0))); + linearGradient.ColorStops.Add(c.CreateColorGradientStop(1, Wui.Color.FromArgb(255, 255, 255, 255))); + + var radialGradient = c.CreateRadialGradientBrush(); + radialGradient.EllipseCenter = new Vector2(0.5f, 0.5f); + radialGradient.EllipseRadius = new Vector2(0.5f, 0.5f); + radialGradient.GradientOriginOffset = new Vector2(0.1f, 0.1f); + radialGradient.ColorStops.Add(c.CreateColorGradientStop(0, Wui.Color.FromArgb(255, 1, 2, 3))); + + var strokedShape = AddSpriteShape(c, containerShape, ellipse, colorBrush, linearGradient); + strokedShape.StrokeDashArray.Add(1); + strokedShape.StrokeDashArray.Add(2); + strokedShape.StrokeDashOffset = 3; + strokedShape.StrokeDashCap = CompositionStrokeCap.Round; + strokedShape.StrokeStartCap = CompositionStrokeCap.Square; + strokedShape.StrokeEndCap = CompositionStrokeCap.Triangle; + strokedShape.StrokeLineJoin = CompositionStrokeLineJoin.Bevel; + strokedShape.StrokeMiterLimit = 4; + strokedShape.StrokeThickness = 2; + strokedShape.IsStrokeNonScaling = true; + + AddSpriteShape(c, containerShape, rectangle, colorBrush, radialGradient); + AddSpriteShape(c, containerShape, roundedRectangle, colorBrush, null); + AddSpriteShape(c, containerShape, pathGeometry, colorBrush, null); + + // A geometric clip, which is the other consumer of a geometry. + var geometricClip = c.CreateGeometricClip(); + geometricClip.Geometry = pathGeometry; + shapeVisual.Clip = geometricClip; + + // A layer visual with a drop shadow. + var layerVisual = c.CreateLayerVisual(); + layerVisual.Size = new Vector2(100, 100); + + var shadow = c.CreateDropShadow(); + shadow.BlurRadius = 5; + shadow.Color = Wui.Color.FromArgb(128, 0, 0, 0); + shadow.Offset = new Vector3(1, 2, 0); + shadow.Opacity = 0.5f; + shadow.Mask = colorBrush; + shadow.SourcePolicy = CompositionDropShadowSourcePolicy.InheritFromVisualContent; + layerVisual.Shadow = shadow; + layerVisual.Children.Add(shapeVisual); + + // A visual surface, a surface brush over it, and a mask brush combining two + // brushes. These are how the translator implements masking. + var visualSurface = c.CreateVisualSurface(); + visualSurface.SourceVisual = shapeVisual; + visualSurface.SourceSize = new Vector2(100, 100); + visualSurface.SourceOffset = new Vector2(1, 2); + + var surfaceBrush = c.CreateSurfaceBrush(visualSurface); + + // A surface brush over a loaded image, which is the other kind of surface. + var imageBrush = c.CreateSurfaceBrush( + LoadedImageSurface.StartLoadFromUri(new Uri("ms-appx:///image.png"))); + + var streamBrush = c.CreateSurfaceBrush( + LoadedImageSurface.StartLoadFromStream(new byte[] { 1, 2, 3, 4 })); + + var maskBrush = c.CreateMaskBrush(); + maskBrush.Source = surfaceBrush; + maskBrush.Mask = imageBrush; + + // Effects. Both effect types, reached through an effect factory and an + // effect brush. + var compositeEffect = new CompositeEffect( + CanvasComposite.DestinationIn, + new List + { + new CompositionEffectSourceParameter("source"), + new CompositionEffectSourceParameter("mask"), + }); + + var compositeBrush = c.CreateEffectFactory(compositeEffect).CreateBrush(); + compositeBrush.SetSourceParameter("source", surfaceBrush); + compositeBrush.SetSourceParameter("mask", streamBrush); + + var blurEffect = new GaussianBlurEffect(3, new CompositionEffectSourceParameter("source")); + var blurBrush = c.CreateEffectFactory(blurEffect).CreateBrush(); + blurBrush.SetSourceParameter("source", maskBrush); + + var effectVisual = c.CreateSpriteVisual(); + effectVisual.Size = new Vector2(100, 100); + effectVisual.Brush = blurBrush; + + var compositeVisual = c.CreateSpriteVisual(); + compositeVisual.Size = new Vector2(100, 100); + compositeVisual.Brush = compositeBrush; + + root.Children.Add(layerVisual); + root.Children.Add(effectVisual); + root.Children.Add(compositeVisual); + + // Bind an animation of every kind to something, so that the animators and + // their controllers are all reachable. + root.StartAnimation("Opacity", scalarAnimation, controller); + root.StartAnimation("IsVisible", booleanAnimation); + root.StartAnimation("Offset", vector3Animation); + root.StartAnimation("Size", vector2Animation); + root.StartAnimation("RotationAngleInDegrees", expressionAnimation); + colorBrush.StartAnimation("Color", colorAnimation); + pathGeometry.StartAnimation("Path", pathAnimation); + linearGradient.ColorStops[0].StartAnimation("Offset", scalarAnimation); + radialGradient.StartAnimation("EllipseCenter", vector2Animation); + strokedShape.StartAnimation("StrokeThickness", scalarAnimation); + theme.StartAnimation("Vector4", vector4Animation); + + return root; + } + + static CompositionSpriteShape AddSpriteShape( + Compositor compositor, + CompositionContainerShape parent, + CompositionGeometry geometry, + CompositionBrush fill, + CompositionBrush? stroke) + { + var shape = compositor.CreateSpriteShape(); + shape.Geometry = geometry; + shape.FillBrush = fill; + shape.StrokeBrush = stroke; + parent.Shapes.Add(shape); + return shape; + } + + // Builds a geometry that contains every CanvasGeometry shape and every path + // command, so that the flattened path encoding is fully exercised. + static CanvasGeometry BuildPathGeometry() + { + using var builder = new CanvasPathBuilder(null); + builder.SetFilledRegionDetermination(CanvasFilledRegionDetermination.Winding); + builder.BeginFigure(new Vector2(0, 0)); + builder.AddLine(new Vector2(1, 0)); + builder.AddCubicBezier(new Vector2(2, 0), new Vector2(3, 1), new Vector2(4, 1)); + builder.EndFigure(CanvasFigureLoop.Closed); + builder.BeginFigure(new Vector2(5, 5)); + builder.AddLine(new Vector2(6, 6)); + builder.EndFigure(CanvasFigureLoop.Open); + + var path = CanvasGeometry.CreatePath(builder); + var ellipse = CanvasGeometry.CreateEllipse(null, 1, 2, 3, 4); + var roundedRectangle = CanvasGeometry.CreateRoundedRectangle(null, 1, 2, 3, 4, 5, 6); + var transformed = ellipse.Transform(Matrix3x2.CreateScale(2)); + var combination = path.CombineWith( + roundedRectangle, + Matrix3x2.Identity, + CanvasGeometryCombine.Union); + + return CanvasGeometry.CreateGroup( + null, + new[] { combination, transformed }, + CanvasFilledRegionDetermination.Alternate); + } + + // Walks every CompositionObject reachable from a root. This deliberately does not + // reuse the serializer's walker, so that a node the serializer cannot see is + // still counted as uncovered. + static IEnumerable Collect(Visual root) + { + var seen = new HashSet(); + var result = new List(); + + void Add(CompositionObject? o) + { + if (o is null || !seen.Add(o)) + { + return; + } + + result.Add(o); + + Add(o.Properties); + + foreach (var animator in o.Animators) + { + Add(animator.Animation); + Add(animator.Controller); + } + + if (o is CompositionAnimation animation) + { + foreach (var parameter in animation.ReferenceParameters) + { + Add(parameter.Value); + } + + if (o is KeyFrameAnimation_ keyFrameAnimation) + { + foreach (var easing in keyFrameAnimation.KeyFrames.Select(f => f.Easing)) + { + Add(easing); + } + } + } + + switch (o) + { + case SpriteVisual sprite: + Add(sprite.Brush); + Add(sprite.Clip); + foreach (var child in sprite.Children) + { + Add(child); + } + + break; + case ContainerVisual container: + foreach (var child in container.Children) + { + Add(child); + } + + Add(container.Clip); + + if (container is LayerVisual layer) + { + Add(layer.Shadow); + } + else if (container is ShapeVisual shapeVisual) + { + Add(shapeVisual.ViewBox); + foreach (var shape in shapeVisual.Shapes) + { + Add(shape); + } + } + + break; + case CompositionContainerShape containerShape: + foreach (var shape in containerShape.Shapes) + { + Add(shape); + } + + break; + case CompositionSpriteShape spriteShape: + Add(spriteShape.Geometry); + Add(spriteShape.FillBrush); + Add(spriteShape.StrokeBrush); + break; + case CompositionGeometricClip geometricClip: + Add(geometricClip.Geometry); + break; + case CompositionGradientBrush gradient: + foreach (var stop in gradient.ColorStops) + { + Add(stop); + } + + break; + case CompositionMaskBrush mask: + Add(mask.Source); + Add(mask.Mask); + break; + case CompositionSurfaceBrush surfaceBrush: + Add(surfaceBrush.Surface as CompositionObject); + break; + case CompositionEffectBrush effectBrush: + var effectFactory = effectBrush.GetEffectFactory(); + Add(effectFactory); + foreach (var source in effectFactory.Effect.Sources) + { + Add(effectBrush.GetSourceParameter(source.Name)); + } + + break; + case CompositionVisualSurface visualSurface: + Add(visualSurface.SourceVisual); + break; + case DropShadow dropShadow: + Add(dropShadow.Mask); + break; + } + } + + Add(root); + return result; + } + } +} diff --git a/tests/CompDataFlatbuffer.Tests/RobustnessTests.cs b/tests/CompDataFlatbuffer.Tests/RobustnessTests.cs new file mode 100644 index 00000000..aa108d25 --- /dev/null +++ b/tests/CompDataFlatbuffer.Tests/RobustnessTests.cs @@ -0,0 +1,92 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable enable + +using System; +using Xunit; + +namespace CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Tests +{ + /// + /// Verifies that malformed input is rejected rather than being allowed to + /// corrupt the reader. + /// + /// + /// A serialized composition is likely to be loaded from a file or downloaded, so + /// it has to be treated as untrusted. Every one of these cases must fail with a + /// : no other exception type, no crash, and + /// no hang. The native interpreter performs the same checks, so this is also a + /// specification of what that interpreter has to reject. + /// + public class RobustnessTests + { + [Fact] + public void EmptyBufferIsRejected() + => Assert.Throws(() => CompositionDeserializer.Deserialize(Array.Empty())); + + [Fact] + public void GarbageIsRejected() + { + var garbage = new byte[512]; + new Random(0).NextBytes(garbage); + + Assert.Throws(() => CompositionDeserializer.Deserialize(garbage)); + } + + [Fact] + public void BufferWithTheWrongFileIdentifierIsRejected() + { + var buffer = Corpus.Translate("LightBulb.json").Serialize(); + + // The file identifier sits at offset 4, immediately after the root offset. + buffer[4] = (byte)'X'; + + Assert.Throws(() => CompositionDeserializer.Deserialize(buffer)); + } + + [Theory] + [MemberData(nameof(Corpus.FileNames), MemberType = typeof(Corpus))] + public void TruncatedBuffersAreRejected(string fileName) + { + var buffer = Corpus.Translate(fileName).Serialize(); + + // Truncation is checked at a spread of lengths rather than at every length, + // which would make the test run for minutes without finding anything more. + for (var length = 0; length < buffer.Length; length += Math.Max(1, buffer.Length / 64)) + { + var truncated = new byte[length]; + Array.Copy(buffer, truncated, length); + + Assert.Throws(() => CompositionDeserializer.Deserialize(truncated)); + } + } + + [Theory] + [MemberData(nameof(Corpus.FileNames), MemberType = typeof(Corpus))] + public void CorruptedBuffersDoNotCrash(string fileName) + { + var original = Corpus.Translate(fileName).Serialize(); + var random = new Random(fileName.GetHashCode(StringComparison.Ordinal)); + + // Unlike truncation, a flipped bit may leave a buffer that is still valid, + // just describing a different animation. So the requirement here is weaker: + // the reader either succeeds or reports a format error, but never throws + // something else and never reads outside the buffer. + for (var i = 0; i < 200; i++) + { + var corrupted = (byte[])original.Clone(); + corrupted[random.Next(corrupted.Length)] ^= (byte)(1 << random.Next(8)); + + try + { + CompositionDeserializer.Deserialize(corrupted); + } + catch (FlatBufferFormatException) + { + } + } + } + } +} diff --git a/tests/CompDataFlatbuffer.Tests/RoundTripTests.cs b/tests/CompDataFlatbuffer.Tests/RoundTripTests.cs new file mode 100644 index 00000000..24a3ac08 --- /dev/null +++ b/tests/CompDataFlatbuffer.Tests/RoundTripTests.cs @@ -0,0 +1,120 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable enable + +using System; +using System.Linq; +using CommunityToolkit.WinUI.Lottie.WinCompData; +using Xunit; + +namespace CommunityToolkit.WinUI.Lottie.CompDataFlatbuffer.Tests +{ + /// + /// Verifies that a graph survives a trip through the FlatBuffer format unchanged. + /// + /// + /// This is the test that the FlatBuffer based player produces the same visual tree + /// as the JSON based one. The JSON path is Lottie file to translator to + /// WinCompData graph. The FlatBuffer path is that same graph serialized and read + /// back. If the two graphs are identical then any interpreter that walks one + /// produces the same visuals as an interpreter that walks the other, so the + /// comparison is made once here rather than being repeated for every player. + /// + public class RoundTripTests + { + [Theory] + [MemberData(nameof(Corpus.FileNames), MemberType = typeof(Corpus))] + public void RoundTripPreservesTheGraph(string fileName) + { + var translated = Corpus.Translate(fileName); + + var expected = CompositionTreeDumper.Dump(translated.RootVisual); + var actual = CompositionTreeDumper.Dump(CompositionDeserializer.Deserialize(translated.Serialize())); + + Assert.Equal(expected, actual); + } + + [Theory] + [MemberData(nameof(Corpus.FileNames), MemberType = typeof(Corpus))] + public void SerializationIsDeterministic(string fileName) + { + var translated = Corpus.Translate(fileName); + + // The same graph must always produce the same bytes, otherwise builds are + // not reproducible and the output cannot be cached or diffed. + Assert.Equal(translated.Serialize(), translated.Serialize()); + } + + [Theory] + [MemberData(nameof(Corpus.FileNames), MemberType = typeof(Corpus))] + public void RoundTripIsStable(string fileName) + { + var translated = Corpus.Translate(fileName); + + // Serializing a deserialized graph must reproduce the original bytes. This + // catches any state that the deserializer drops but the dump does not cover. + var once = translated.Serialize(); + var twice = CompositionSerializer.Serialize( + CompositionDeserializer.Deserialize(once), + translated.RequiredUapVersion, + translated.Metadata, + translated.PropertyBindings, + translated.Width, + translated.Height); + + Assert.Equal(once, twice); + } + + [Theory] + [MemberData(nameof(Corpus.FileNames), MemberType = typeof(Corpus))] + public void DeserializedGraphSharesNodes(string fileName) + { + var translated = Corpus.Translate(fileName); + var root = CompositionDeserializer.Deserialize(translated.Serialize()); + + // A node that is reached by more than one path must be one object, not a + // copy per path, otherwise a large animation would expand enormously and + // animations bound to a shared object would stop being shared. + Assert.Equal(CountDistinct(translated.RootVisual), CountDistinct(root)); + } + + // Counts the distinct visuals reachable from a root. + static int CountDistinct(Visual root) + { + var seen = new System.Collections.Generic.HashSet( + ReferenceEqualityComparer.Instance); + + void Walk(Visual visual) + { + if (!seen.Add(visual)) + { + return; + } + + if (visual is ContainerVisual container) + { + foreach (var child in container.Children) + { + Walk(child); + } + } + } + + Walk(root); + return seen.Count; + } + + sealed class ReferenceEqualityComparer : System.Collections.Generic.IEqualityComparer + where T : class + { + internal static readonly ReferenceEqualityComparer Instance = new ReferenceEqualityComparer(); + + public bool Equals(T? x, T? y) => ReferenceEquals(x, y); + + public int GetHashCode(T obj) + => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj); + } + } +} diff --git a/tests/LottieRuntime.Tests/MetadataTests.cpp b/tests/LottieRuntime.Tests/MetadataTests.cpp new file mode 100644 index 00000000..e7bbb7a3 --- /dev/null +++ b/tests/LottieRuntime.Tests/MetadataTests.cpp @@ -0,0 +1,432 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include +#include +#include + +// Include the implementation to test realization-cache identity as well as the API. +#include "../../source/LottieRuntime/LottieRuntime.cpp" + +#include +#include +#include + +#include +#include +#include +#include + +namespace +{ + void Require(bool condition) + { + if (!condition) + { + throw std::runtime_error("Metadata assertion failed."); + } + } + + struct Options + { + bool Metadata = true; + bool Markers = true; + bool ReferenceTheme = true; + bool ReferenceOwnerProperties = false; + bool Image = false; + uint32_t Theme = 0; + uint32_t ThemeOwner = NullIndex; + uint32_t Name = 0; + uint32_t MarkerName = 1; + uint32_t BindingName = 2; + uint32_t BindingDisplayName = 2; + Fb::PropertyValueType BindingType = Fb::PropertyValueType::Scalar; + float Width = 64; + float Height = 32; + int64_t Ticks = 12345678; + float Fps = 60; + float Progress = 0.25f; + float DurationProgress = 0.5f; + float DefaultScalar = 0.75f; + uint16_t SchemaVersion = 1; + }; + + std::vector Buffer(Options const& options = {}) + { + flatbuffers::FlatBufferBuilder builder; + std::vector> strings; + for (auto text : { "Animation", "Marker", "Opacity", "Theme", "Theme.Opacity", "Progress", "Theme.Progress" }) + { + strings.push_back(builder.CreateString(text)); + } + auto const stringsVector = builder.CreateVector(strings); + + uint8_t const png[] = { + 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, + 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x08, 0x04, 0x00, 0x00, 0x00, 0xB5, 0x1C, 0x0C, + 0x02, 0x00, 0x00, 0x00, 0x0B, 0x49, 0x44, 0x41, + 0x54, 0x78, 0xDA, 0x63, 0xFC, 0xFF, 0x1F, 0x00, + 0x03, 0x03, 0x02, 0x00, 0xEF, 0x9A, 0x2F, 0x5B, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, + 0xAE, 0x42, 0x60, 0x82, + }; + auto const pngBytes = builder.CreateVector(png, std::size(png)); + auto const image = Fb::CreateSurface( + builder, 0, Fb::SurfaceKind::LoadedImageFromStream, NullIndex, nullptr, nullptr, NullIndex, pngBytes); + auto const visualSurface = Fb::CreateSurface(builder); + auto const surfaces = builder.CreateVector(std::vector{ visualSurface, image, image }); + Fb::BrushBuilder brushBuilder(builder); + brushBuilder.add_kind(Fb::BrushKind::Surface); + brushBuilder.add_surface(1); + auto const brush = brushBuilder.Finish(); + auto const brushes = builder.CreateVector(std::vector{ brush }); + + auto const value = Fb::CreatePropertyValue(builder, 2, Fb::PropertyValueType::Scalar, 0.75f); + auto const themeValues = builder.CreateVector(std::vector{ value }); + auto const theme = Fb::CreatePropertySet(builder, 0, options.ThemeOwner, themeValues); + auto const progressValue = Fb::CreatePropertyValue(builder, 5, Fb::PropertyValueType::Scalar, 0); + auto const progressValues = builder.CreateVector(std::vector{ progressValue }); + auto const progress = Fb::CreatePropertySet(builder, 0, 0, progressValues); + auto const sets = builder.CreateVector(std::vector{ theme, progress }); + + auto const reference = Fb::CreateReferenceParameter( + builder, 3, (static_cast(Fb::ObjectCategory::PropertySet) << CategoryShift) | + (options.ReferenceOwnerProperties ? 1u : 0u)); + auto const references = builder.CreateVector(std::vector{ reference }); + auto const animation = Fb::CreateAnimation( + builder, 0, Fb::AnimationKind::Expression, NullIndex, references, + options.ReferenceOwnerProperties ? 6 : 4); + auto const animations = builder.CreateVector(std::vector{ animation }); + auto const animator = Fb::CreateAnimator(builder, 2, 0); + auto const animators = builder.CreateVector(std::vector{ animator }); + auto const childBase = Fb::CreateCompObj(builder, NullIndex, animators); + auto const child = Fb::CreateVisual(builder, childBase); + auto const children = builder.CreateVector(std::vector{ 1 }); + auto const visualBase = Fb::CreateCompObj( + builder, NullIndex, options.ReferenceTheme && !options.ReferenceOwnerProperties ? animators : 0, 1); + Fb::VisualBuilder visualBuilder(builder); + visualBuilder.add_base(visualBase); + if (options.Image) + { + visualBuilder.add_kind(Fb::VisualKind::Sprite); + visualBuilder.add_brush(0); + } + if (options.ReferenceOwnerProperties) + { + visualBuilder.add_children(children); + } + auto const visual = visualBuilder.Finish(); + auto const visuals = builder.CreateVector(std::vector{ visual, child }); + + auto const marker = Fb::CreateMarker( + builder, options.MarkerName, options.Progress, options.DurationProgress); + auto const markers = builder.CreateVector(std::vector{ marker, marker }); + auto const binding = Fb::CreatePropertyBinding( + builder, options.BindingName, options.BindingDisplayName, + options.BindingType, options.BindingType, options.DefaultScalar); + auto const bindings = builder.CreateVector(std::vector{ binding }); + auto const metadata = Fb::CreateMetadata( + builder, options.Name, options.Width, options.Height, options.Ticks, + options.Fps, bindings, options.Markers ? markers : 0, options.Theme); + + Fb::LottieCompositionBuilder root(builder); + root.add_schema_version(options.SchemaVersion); + root.add_root_visual(0); + root.add_strings(stringsVector); + root.add_visuals(visuals); + root.add_property_sets(sets); + root.add_animations(animations); + root.add_surfaces(surfaces); + root.add_brushes(brushes); + if (options.Metadata) + { + root.add_metadata(metadata); + } + Fb::FinishLottieCompositionBuffer(builder, root.Finish()); + auto const* first = reinterpret_cast(builder.GetBufferPointer()); + return { first, first + builder.GetSize() }; + } + + void Invalid( + Compositor const& compositor, + std::vector const& bytes, + std::span images = {}) + { + try + { + Runtime::LoadCompositionWithMetadata(compositor, bytes, images); + } + catch (winrt::hresult_invalid_argument const&) + { + return; + } + throw std::runtime_error("Malformed input was not rejected with E_INVALIDARG."); + } + + // Every recorded animation is a keyframe animation, which always has a controller + // while it runs and none once it is stopped. + void RequireAnimationsRunning(Runtime::LoadedComposition const& loaded, bool running) + { + for (auto const& binding : loaded.Animations->Bindings) + { + Require(binding.Animation.try_as() == nullptr); + Require((binding.Target.TryGetAnimationController(binding.Property) != nullptr) == running); + } + } + + // Returns the number of recorded animations. + size_t TestRestart(Runtime::LoadedComposition const& loaded) + { + Require(Runtime::CanRestartAnimations(loaded)); + RequireAnimationsRunning(loaded, true); + for (int cycle = 0; cycle != 2; ++cycle) + { + Runtime::StopAnimations(loaded); + Runtime::StopAnimations(loaded); + RequireAnimationsRunning(loaded, false); + Runtime::StartAnimations(loaded); + Runtime::StartAnimations(loaded); + RequireAnimationsRunning(loaded, true); + } + + // Restarting must not disturb the expression that drives playback. + Runtime::ProgressPropertySet(loaded.Root).InsertScalar(L"Progress", 0.5f); + return loaded.Animations->Bindings.size(); + } + + void Test(Compositor const& compositor) + { + auto bytes = Buffer(); + auto loaded = Runtime::LoadCompositionWithMetadata(compositor, bytes); + Require(loaded.Root != nullptr); + Require(loaded.ImageSurfaces.empty()); + Require(loaded.Duration.count() == 12345678); + Require(loaded.Size.x == 64 && loaded.Size.y == 32); + Require(loaded.FramesPerSecond == 60); + Require(loaded.Markers.size() == 2); + Require(loaded.Markers[0].Name == L"Marker"); + Require(loaded.Markers[0].Progress == 0.25f); + Require(loaded.Markers[0].DurationProgress == 0.5f); + Require(loaded.Markers[1].Name == loaded.Markers[0].Name); + Require(loaded.ThemeProperties != nullptr); + Require(loaded.ThemeProperties != Runtime::ProgressPropertySet(loaded.Root)); + float value = -1; + Require(loaded.ThemeProperties.TryGetScalar(L"Opacity", value) == CompositionGetValueStatus::Succeeded); + Require(value == 0.75f); + Require(Runtime::ProgressPropertySet(loaded.Root).TryGetScalar(L"Progress", value) == + CompositionGetValueStatus::Succeeded && value == 0); + + // Expression bindings are not stopped, so this tree records no animations. + Require(TestRestart(loaded) == 0); + Runtime::LoadedComposition empty; + Require(!Runtime::CanRestartAnimations(empty)); + Runtime::StopAnimations(empty); + Runtime::StartAnimations(empty); + + // The expression realizes the theme while loading the root. Metadata must + // return that same cached object, including changes made after realization. + Interpreter interpreter(compositor, VerifyComposition(bytes)); + auto first = interpreter.RunWithMetadata(); + first.ThemeProperties.InsertScalar(L"Opacity", 0.125f); + auto second = interpreter.RunWithMetadata(); + Require(first.Root == second.Root && first.ThemeProperties == second.ThemeProperties); + Require(second.ThemeProperties.TryGetScalar(L"Opacity", value) == + CompositionGetValueStatus::Succeeded && value == 0.125f); + + bytes.clear(); + Require(loaded.Markers[0].Name == L"Marker" && loaded.Duration.count() == 12345678); + loaded.ThemeProperties.InsertScalar(L"Opacity", 0.25f); + + Options options; + options.Image = true; + bytes = Buffer(options); + loaded = Runtime::LoadCompositionWithMetadata(compositor, bytes); + Require(loaded.ImageSurfaces.size() == 1 && loaded.ImageSurfaces[0].Index == 1); + auto const image = loaded.ImageSurfaces[0].Surface; + Require(image.try_as() != nullptr); + Require(loaded.Root.as().Brush().as().Surface() == image); + auto reused = Runtime::LoadCompositionWithMetadata(compositor, bytes, loaded.ImageSurfaces); + Require(reused.Root != loaded.Root && reused.ImageSurfaces.size() == 1); + Require(reused.ImageSurfaces[0].Index == 1 && reused.ImageSurfaces[0].Surface == image); + Require(reused.Root.as().Brush().as().Surface() == image); + Interpreter imageInterpreter(compositor, VerifyComposition(bytes), loaded.ImageSurfaces); + auto cachedImages = imageInterpreter.RunWithMetadata(); + Require(cachedImages.ImageSurfaces[0].Surface == image); + Require(imageInterpreter.RunWithMetadata().ImageSurfaces[0].Surface == image); + + auto images = loaded.ImageSurfaces; + images.push_back(images[0]); + Invalid(compositor, bytes, images); + for (auto index : { 0u, 99u, NullIndex }) + { + images = loaded.ImageSurfaces; + images[0].Index = index; + Invalid(compositor, bytes, images); + } + images = loaded.ImageSurfaces; + images[0].Surface = nullptr; + Invalid(compositor, bytes, images); + images[0].Surface = compositor.CreateVisualSurface(); + Invalid(compositor, bytes, images); + + options = {}; + options.Theme = NullIndex; + options.Markers = false; + loaded = Runtime::LoadCompositionWithMetadata(compositor, Buffer(options)); + Require(loaded.ThemeProperties == nullptr && loaded.Markers.empty()); + + options = {}; + options.ReferenceTheme = false; + loaded = Runtime::LoadCompositionWithMetadata(compositor, Buffer(options)); + Require(loaded.ThemeProperties != nullptr); + Require(loaded.ThemeProperties.TryGetScalar(L"Opacity", value) == + CompositionGetValueStatus::Succeeded && value == 0.75f); + + options = {}; + options.ReferenceOwnerProperties = true; + loaded = Runtime::LoadCompositionWithMetadata(compositor, Buffer(options)); + Require(loaded.Root.as().Children().Count() == 1); + Require(Runtime::ProgressPropertySet(loaded.Root).TryGetScalar(L"Progress", value) == + CompositionGetValueStatus::Succeeded && value == 0); + + options = {}; + options.Progress = -0.5f; + options.DurationProgress = 2; + loaded = Runtime::LoadCompositionWithMetadata(compositor, Buffer(options)); + Require(loaded.Markers[0].Progress == -0.5f && loaded.Markers[0].DurationProgress == 2); + + options = {}; + options.Width = options.Height = options.Fps = 0; + options.Ticks = 0; + loaded = Runtime::LoadCompositionWithMetadata(compositor, Buffer(options)); + Require(loaded.Duration.count() == 0 && loaded.Size.x == 0 && loaded.FramesPerSecond == 0); + + options = {}; + options.Metadata = false; + bytes = Buffer(options); + Require(Runtime::LoadComposition(compositor, bytes) != nullptr); + Invalid(compositor, bytes); + + auto const nan = std::numeric_limits::quiet_NaN(); + auto const infinity = std::numeric_limits::infinity(); + for (auto bad : { -1.0f, nan, infinity }) + { + options = {}; options.Width = bad; Invalid(compositor, Buffer(options)); + options = {}; options.Height = bad; Invalid(compositor, Buffer(options)); + options = {}; options.Fps = bad; Invalid(compositor, Buffer(options)); + options = {}; options.DurationProgress = bad; Invalid(compositor, Buffer(options)); + } + for (auto bad : { nan, infinity }) + { + options = {}; options.Progress = bad; Invalid(compositor, Buffer(options)); + options = {}; options.DefaultScalar = bad; Invalid(compositor, Buffer(options)); + } + options = {}; options.Ticks = -1; Invalid(compositor, Buffer(options)); + options = {}; options.Theme = 99; Invalid(compositor, Buffer(options)); + options = {}; options.Theme = 1; Invalid(compositor, Buffer(options)); + options = {}; options.ThemeOwner = 0; Invalid(compositor, Buffer(options)); + options = {}; options.Name = 99; Invalid(compositor, Buffer(options)); + for (auto bad : { 99u, NullIndex }) + { + options = {}; options.MarkerName = bad; Invalid(compositor, Buffer(options)); + options = {}; options.BindingName = bad; Invalid(compositor, Buffer(options)); + options = {}; options.BindingDisplayName = bad; Invalid(compositor, Buffer(options)); + } + options = {}; + options.BindingType = static_cast(255); + Invalid(compositor, Buffer(options)); + + bytes = Buffer(); + for (size_t length = 0; length < bytes.size(); length += 8) + { + Invalid(compositor, { bytes.begin(), bytes.begin() + length }); + } + bytes[4] = std::byte{ 'X' }; + Invalid(compositor, bytes); + Invalid(compositor, {}); + + options = {}; options.SchemaVersion = 2; + try + { + Runtime::LoadCompositionWithMetadata(compositor, Buffer(options)); + throw std::runtime_error("Unsupported schema was not rejected."); + } + catch (winrt::hresult_not_implemented const&) + { + } + } +} + +int wmain(int argc, wchar_t** argv) +{ + try + { + winrt::init_apartment(winrt::apartment_type::single_threaded); + DispatcherQueueOptions const options{ sizeof(DispatcherQueueOptions), DQTYPE_THREAD_CURRENT, DQTAT_COM_NONE }; + winrt::Windows::System::DispatcherQueueController queue{ nullptr }; + winrt::check_hresult(CreateDispatcherQueueController( + options, reinterpret_cast(winrt::put_abi(queue)))); + auto xaml = winrt::Windows::UI::Xaml::Hosting::WindowsXamlManager::InitializeForCurrentThread(); + { + winrt::Windows::UI::Xaml::Controls::Grid host; + auto compositor = winrt::Windows::UI::Xaml::Hosting::ElementCompositionPreview::GetElementVisual(host).Compositor(); + bool const legacy = argc > 1 && std::wstring_view(argv[1]) == L"--legacy"; + if (!legacy) + { + Test(compositor); + } + for (int i = legacy ? 2 : 1; i < argc; ++i) + { + std::ifstream file(argv[i], std::ios::binary | std::ios::ate); + Require(file.good()); + std::vector bytes(static_cast(file.tellg())); + file.seekg(0); + file.read(reinterpret_cast(bytes.data()), static_cast(bytes.size())); + Require(file.good()); + if (legacy) + { + auto root = Runtime::LoadComposition(compositor, bytes); + Require(root != nullptr); + std::wcout << argv[i] << L": legacy composition loaded\n"; + continue; + } + auto loaded = Runtime::LoadCompositionWithMetadata(compositor, bytes); + Require(loaded.Root != nullptr); + auto const* metadata = VerifyComposition(bytes).metadata(); + Require((loaded.ThemeProperties != nullptr) == (metadata->theming_property_set() != NullIndex)); + if (!loaded.ImageSurfaces.empty()) + { + auto reused = Runtime::LoadCompositionWithMetadata(compositor, bytes, loaded.ImageSurfaces); + Require(reused.Root != loaded.Root && reused.ImageSurfaces.size() == loaded.ImageSurfaces.size()); + for (size_t image = 0; image < loaded.ImageSurfaces.size(); ++image) + { + Require(loaded.ImageSurfaces[image].Surface.try_as() != nullptr); + Require(reused.ImageSurfaces[image].Index == loaded.ImageSurfaces[image].Index); + Require(reused.ImageSurfaces[image].Surface == loaded.ImageSurfaces[image].Surface); + } + } + std::wcout << argv[i] << L": " << loaded.Size.x << L"x" << loaded.Size.y + << L", ticks=" << loaded.Duration.count() << L", fps=" << loaded.FramesPerSecond + << L", markers=" << loaded.Markers.size() + << L", theme=" << (loaded.ThemeProperties != nullptr ? L"present" : L"absent") + << L", images=" << loaded.ImageSurfaces.size() + << L", restartable animations=" << TestRestart(loaded) << L"\n"; + } + } + queue.ShutdownQueueAsync(); + std::cout << "Metadata tests passed.\n"; + return 0; + } + catch (winrt::hresult_error const& error) + { + std::wcerr << error.message().c_str() << L"\n"; + } + catch (std::exception const& error) + { + std::cerr << error.what() << "\n"; + } + return 1; +} diff --git a/tests/LottieRuntime.Tests/MetadataTests.manifest b/tests/LottieRuntime.Tests/MetadataTests.manifest new file mode 100644 index 00000000..e7fc0a80 --- /dev/null +++ b/tests/LottieRuntime.Tests/MetadataTests.manifest @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/tests/LottieRuntime.Tests/VisualSourceTests.cpp b/tests/LottieRuntime.Tests/VisualSourceTests.cpp new file mode 100644 index 00000000..6588ea9f --- /dev/null +++ b/tests/LottieRuntime.Tests/VisualSourceTests.cpp @@ -0,0 +1,267 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// Tests LottieVisualSource against serialized compositions passed on the command line. +// Builds with the runtime and a C++/WinRT projection of Microsoft.UI.Xaml 2.8, and hosts XAML so image assets +// load through LoadedImageSurface; see source\LottieRuntime\README.md. + +#include +#include +#include + +// Include the implementation to read back each visual's theme properties. +#include "../../source/LottieRuntime/LottieVisualSource.cpp" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace +{ + namespace Runtime = CommunityToolkit::WinUI2::Lottie; + namespace Fb = CommunityToolkit::WinUI::Lottie::CompDataFlatbuffer::Schema; + namespace Mux = winrt::Microsoft::UI::Xaml::Controls; + using namespace winrt::Windows::UI::Composition; + + void Require(bool condition, char const* message) + { + if (!condition) + { + throw std::runtime_error(message); + } + } + + std::vector Read(wchar_t const* path) + { + std::ifstream file(path, std::ios::binary | std::ios::ate); + Require(file.good(), "Cannot open file."); + std::vector bytes(static_cast(file.tellg())); + file.seekg(0); + file.read(reinterpret_cast(bytes.data()), static_cast(bytes.size())); + Require(file.good(), "Cannot read file."); + return bytes; + } + + bool HasImages(Fb::LottieComposition const& composition) + { + if (auto surfaces = composition.surfaces()) + { + for (auto surface : *surfaces) + { + if (surface->kind() == Fb::SurfaceKind::LoadedImageFromStream || + surface->kind() == Fb::SurfaceKind::LoadedImageFromUri) + { + return true; + } + } + } + return false; + } + + bool AnimationsRunning(Visual const& visual) + { + // Every serialized tree animates a property somewhere; find a keyframe controller. + auto found = false; + auto check = [&](CompositionObject const& object, wchar_t const* property) + { + found = found || object.TryGetAnimationController(property) != nullptr; + }; + std::function walk = [&](Visual const& node) + { + for (auto property : { L"Opacity", L"IsVisible", L"Offset", L"Scale", L"RotationAngleInDegrees", + L"TransformMatrix", L"Size" }) + { + check(node, property); + } + if (auto container = node.try_as()) + { + for (auto child : container.Children()) + { + walk(child); + } + } + }; + walk(visual); + return found; + } + + void Test(Compositor const& compositor, wchar_t const* path) + { + auto bytes = Read(path); + auto composition = Fb::GetLottieComposition(bytes.data()); + auto source = Runtime::CreateAnimatedVisualSource(bytes); + Require(source.try_as() != nullptr, "Not an IAnimatedVisualSource."); + + auto const images = HasImages(*composition); + Require((source.try_as() != nullptr) == images, "Wrong dynamic source."); + + winrt::Windows::Foundation::IInspectable diagnostics{ nullptr }; + auto visual = source.TryCreateAnimatedVisual(compositor, diagnostics); + Require(diagnostics == nullptr, "Unexpected diagnostics."); + Require(visual != nullptr, "No visual."); + Require(visual.RootVisual() != nullptr, "No root."); + Require(visual.Duration().count() == composition->metadata()->duration_ticks(), "Wrong duration."); + + auto visual2 = visual.try_as(); + Require(visual2 != nullptr, "Not an IAnimatedVisual2."); + auto const animated = AnimationsRunning(visual.RootVisual()); + for (int cycle = 0; cycle != 2; ++cycle) + { + visual2.DestroyAnimations(); + visual2.DestroyAnimations(); + Require(!AnimationsRunning(visual.RootVisual()), "Animations not destroyed."); + visual2.CreateAnimations(); + visual2.CreateAnimations(); + Require(AnimationsRunning(visual.RootVisual()) == animated, "Animations not recreated."); + } + + auto markers = source.Markers(); + for (auto const& marker : markers) + { + Require(marker.Value() >= 0 && marker.Value() <= 1, "Marker out of range."); + } + + // Bound colors and scalars reach live and later visuals; unbound names are ignored. + auto theme = winrt::get_self(visual)->ThemeProperties(); + source.SetColorProperty(L"NotABinding", winrt::Windows::UI::Color{ 255, 1, 2, 3 }); + Runtime::SetScalarProperty(source, L"NotABinding", 1); + winrt::Windows::Foundation::Numerics::float4 color{}; + float scalar{}; + if (theme) + { + Require(theme.TryGetVector4(L"NotABinding", color) != CompositionGetValueStatus::Succeeded, + "Unbound color applied."); + Require(theme.TryGetScalar(L"NotABinding", scalar) != CompositionGetValueStatus::Succeeded, + "Unbound scalar applied."); + } + std::vector> bound; + if (auto bindings = composition->metadata()->property_bindings()) + { + for (auto binding : *bindings) + { + auto name = winrt::to_hstring(composition->strings()->Get(binding->name())->str()); + if (binding->exposed_type() == Fb::PropertyValueType::Color) + { + source.SetColorProperty(name, winrt::Windows::UI::Color{ 40, 10, 20, 30 }); + bound.emplace_back(name, binding->exposed_type()); + } + else if (binding->exposed_type() == Fb::PropertyValueType::Scalar) + { + Runtime::SetScalarProperty(source, name, 0.25); + bound.emplace_back(name, binding->exposed_type()); + } + } + } + Require(bound.empty() || theme, "Bindings without theme properties."); + auto later = source.TryCreateAnimatedVisual(compositor, diagnostics); + Require(later != nullptr, "No second visual."); + for (auto const& set : { theme, winrt::get_self(later)->ThemeProperties() }) + { + for (auto const& [name, type] : bound) + { + if (type == Fb::PropertyValueType::Color) + { + Require(set.TryGetVector4(name, color) == CompositionGetValueStatus::Succeeded && + color == winrt::Windows::Foundation::Numerics::float4{ 10, 20, 30, 40 }, "Color not applied."); + } + else + { + Require(set.TryGetScalar(name, scalar) == CompositionGetValueStatus::Succeeded && scalar == 0.25f, + "Scalar not applied."); + } + } + } + later.as().Close(); + + visual.as().Close(); + Require(visual.RootVisual() == nullptr, "Root not released."); + visual2.DestroyAnimations(); + visual2.CreateAnimations(); + + // Image surfaces are tied to their compositor. Using another one throws by default + // and becomes diagnostics on request. + if (images) + { + Compositor other; + try + { + source.TryCreateAnimatedVisual(other, diagnostics); + throw std::runtime_error("Another compositor accepted."); + } + catch (winrt::hresult_invalid_argument const&) + { + } + + Runtime::AnimatedVisualSourceOptions options; + options.ReportLoadErrors = true; + source = Runtime::CreateAnimatedVisualSource(bytes, options); + Require(source.TryCreateAnimatedVisual(compositor, diagnostics) != nullptr && !diagnostics, + "No visual with diagnostics."); + Require(source.TryCreateAnimatedVisual(other, diagnostics) == nullptr, "Error not reported."); + Require(winrt::unbox_value_or(diagnostics, L"") != L"", "No diagnostics."); + } + + try + { + Runtime::SetScalarProperty(compositor.CreatePropertySet(), L"Name", 1); + throw std::runtime_error("Foreign source accepted."); + } + catch (winrt::hresult_invalid_argument const&) + { + } + std::wcout << path << L": markers=" << markers.Size() + << L", animated=" << (animated ? L"yes" : L"no") << (images ? L", images" : L"") << L"\n"; + } +} + +int wmain(int argc, wchar_t** argv) +{ + try + { + winrt::init_apartment(winrt::apartment_type::single_threaded); + DispatcherQueueOptions const options{ sizeof(DispatcherQueueOptions), DQTYPE_THREAD_CURRENT, DQTAT_COM_NONE }; + winrt::Windows::System::DispatcherQueueController queue{ nullptr }; + winrt::check_hresult(CreateDispatcherQueueController( + options, reinterpret_cast(winrt::put_abi(queue)))); + auto xaml = winrt::Windows::UI::Xaml::Hosting::WindowsXamlManager::InitializeForCurrentThread(); + { + winrt::Windows::UI::Xaml::Controls::Grid host; + auto compositor = winrt::Windows::UI::Xaml::Hosting::ElementCompositionPreview::GetElementVisual(host).Compositor(); + + try + { + Runtime::CreateAnimatedVisualSource({}); + throw std::runtime_error("Empty buffer accepted."); + } + catch (winrt::hresult_invalid_argument const&) + { + } + + for (int i = 1; i < argc; ++i) + { + Test(compositor, argv[i]); + } + } + queue.ShutdownQueueAsync(); + std::cout << "Visual source tests passed.\n"; + return 0; + } + catch (winrt::hresult_error const& error) + { + std::wcerr << error.message().c_str() << L"\n"; + } + catch (std::exception const& error) + { + std::cerr << error.what() << "\n"; + } + return 1; +} diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 00000000..3891e8ed --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,14 @@ +{ + "name": "lottie-runtime", + "version-string": "1.0.0", + "builtin-baseline": "a2f9862da6d88040a8537fb9b8cb24deaa9a196b", + "dependencies": [ + "flatbuffers" + ], + "overrides": [ + { + "name": "flatbuffers", + "version": "25.2.10" + } + ] +}