Update NuGets, optimize allocations.

Switch to newest JSON parser.
Optimize allocations by using ReadOnlySpan<T> in places where we previously use IEnumerable<T> as a way of protecting arrays for modification.
This commit is contained in:
Simeon Cran 2018-11-27 15:29:34 -08:00 коммит произвёл Simeon
Родитель 6eacb93a64
Коммит b014855ed7
29 изменённых файлов: 184 добавлений и 78 удалений

Просмотреть файл

@ -37,11 +37,13 @@
<SubType>Designer</SubType>
</PackageReference>
<PackageReference Include="Newtonsoft.Json">
<Version>11.0.2</Version>
<Version>12.0.1</Version>
</PackageReference>
<PackageReference Include="System.Memory" Version="4.5.1" />
<PackageReference Include="System.Numerics.Vectors">
<Version>4.5.0</Version>
</PackageReference>
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.2" />
<PackageReference Include="System.ValueTuple">
<Version>4.5.0</Version>
</PackageReference>

Просмотреть файл

@ -22,13 +22,14 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="StyleCop.Analyzers" Version="1.0.2">
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.1-beta.61">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Memory" Version="4.5.1" />
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.2" />
</ItemGroup>
<Import Project="..\source\LottieReader\LottieReader.projitems" Label="Shared" />

Просмотреть файл

@ -202,7 +202,13 @@
<Version>2.1.181025003-prerelease</Version>
</PackageReference>
<PackageReference Include="Newtonsoft.Json">
<Version>11.0.2</Version>
<Version>12.0.1</Version>
</PackageReference>
<PackageReference Include="System.Memory">
<Version>4.5.1</Version>
</PackageReference>
<PackageReference Include="System.Runtime.CompilerServices.Unsafe">
<Version>4.5.2</Version>
</PackageReference>
<PackageReference Include="Win2D.uwp">
<Version>1.23.0</Version>

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" IgnorableNamespaces="uap mp">
<Identity Name="8e772a41-9ca3-4339-a6a1-093cb9e19f2d" Publisher="CN=developer" Version="1.0.34.0" />
<Identity Name="8e772a41-9ca3-4339-a6a1-093cb9e19f2d" Publisher="CN=yongql" Version="1.0.35.0" />
<mp:PhoneIdentity PhoneProductId="8e772a41-9ca3-4339-a6a1-093cb9e19f2d" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
<Properties>
<DisplayName>Lottie Viewer</DisplayName>

Просмотреть файл

@ -8,4 +8,9 @@
<Import Project="..\..\source\LottieData\LottieData.projitems" Label="Shared" />
<ItemGroup>
<PackageReference Include="System.Memory" Version="4.5.1" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.2" />
</ItemGroup>
</Project>

Просмотреть файл

@ -9,7 +9,7 @@
<Import Project="..\..\source\LottieReader\LottieReader.projitems" Label="Shared" />
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
</ItemGroup>
<ItemGroup>

Просмотреть файл

@ -773,13 +773,13 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie
if (obj.Shapes.Count == 1)
{
var child = obj.Shapes[0];
if (!obj.Animators.Any())
if (obj.Animators.Count == 0)
{
// The container has no animations. It can be replaced with its child as
// long as the child doesn't animate any of the non-default properties and
// the container isn't referenced by an animation.
}
else if (!child.Animators.Any() && child.Type == Wd.CompositionObjectType.CompositionContainerShape)
else if (child.Animators.Count == 0 && child.Type == Wd.CompositionObjectType.CompositionContainerShape)
{
// The child has no animations. It can be replaced with its parent as long
// as the parent doesn't animate any of the child's non-default properties

Просмотреть файл

@ -53,7 +53,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
/// <summary>
/// Gets the keyframes that describe how the value should be animated.
/// </summary>
public IEnumerable<KeyFrame<T>> KeyFrames => _keyFrames;
public ReadOnlySpan<KeyFrame<T>> KeyFrames => _keyFrames;
/// <summary>
/// Gets the property index used for expressions.
@ -77,7 +77,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
/// <inheritdoc/>
public override string ToString() =>
IsAnimated
? string.Join(" -> ", KeyFrames.Select(kf => kf.Value.ToString()))
? string.Join(" -> ", _keyFrames.Select(kf => kf.Value.ToString()))
: InitialValue.ToString();
}
}

Просмотреть файл

@ -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.
using System;
namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
{
/// <summary>
/// Extension methods for <see cref="ReadOnlySpan{T}"/> to make it easier to treat them
/// like IEnumerables.
/// </summary>
#if !WINDOWS_UWP
public
#endif
static class ExtensionMethods
{
public static bool Any<TSource>(this ReadOnlySpan<TSource> source)
{
return source.Length > 0;
}
public static bool Any<TSource>(this ReadOnlySpan<TSource> source, Func<TSource, bool> predicate)
{
for (var i = 0; i < source.Length; i++)
{
if (predicate(source[i]))
{
return true;
}
}
return false;
}
public static TResult[] SelectToArray<TSource, TResult>(this ReadOnlySpan<TSource> source, Func<TSource, TResult> selector)
{
var result = new TResult[source.Length];
for (var i = 0; i < source.Length; i++)
{
result[i] = selector(source[i]);
}
return result;
}
public static double Max<TSource>(this ReadOnlySpan<TSource> source, Func<TSource, double> selector)
{
var result = double.NegativeInfinity;
foreach (var item in source)
{
var candidate = selector(item);
if (candidate > result)
{
result = candidate;
}
}
return result;
}
public static double Min<TSource>(this ReadOnlySpan<TSource> source, Func<TSource, double> selector)
{
var result = double.PositiveInfinity;
foreach (var item in source)
{
var candidate = selector(item);
if (candidate < result)
{
result = candidate;
}
}
return result;
}
}
}

Просмотреть файл

@ -44,9 +44,17 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
/// Returns the first gradient stop in a sequence that is a color. Opacity will always be
/// set to 1.
/// </summary>
public static Color GetFirstColor(IEnumerable<GradientStop> gradientStops)
public static Color GetFirstColor(ReadOnlySpan<GradientStop> gradientStops)
{
return gradientStops.Select(stop => stop.Color).FirstOrDefault(color => color != null);
foreach (var stop in gradientStops)
{
if (stop.Color != null)
{
return stop.Color;
}
}
return null;
}
/// <inheritdoc/>

Просмотреть файл

@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
@ -19,7 +20,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
#endif
abstract class Layer : LottieObject
{
static Mask[] _emptyMasks = new Mask[0];
static readonly Mask[] _emptyMasks = new Mask[0];
readonly Mask[] _masks;
protected private Layer(
@ -96,7 +97,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
/// <summary>
/// Gets the list of masks appplied to the layer.
/// </summary>
public IEnumerable<Mask> Masks => _masks == null ? _emptyMasks : _masks;
public ReadOnlySpan<Mask> Masks => _masks;
public enum LayerType
{

Просмотреть файл

@ -7,6 +7,7 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)\Animatable.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ExtensionMethods.cs" />
<Compile Include="$(MSBuildThisFileDirectory)\AnimatableVector3.cs" />
<Compile Include="$(MSBuildThisFileDirectory)\AnimatableXYZ.cs" />
<Compile Include="$(MSBuildThisFileDirectory)\Asset.cs" />

Просмотреть файл

@ -7,7 +7,6 @@
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<PropertyGroup />
<Import Project="LottieData.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>

Просмотреть файл

@ -41,7 +41,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Optimization
// If the geometries have different numbers of segments they can't be animated. However
// in one specific case we can fix that.
var geometries = value.KeyFrames.Select(kf => kf.Value.Items.ToArray()).ToArray();
var geometries = value.KeyFrames.SelectToArray(kf => kf.Value.Items.ToArray());
var distinctSegmentCounts = geometries.Select(g => g.Length).Distinct().Count();
if (distinctSegmentCounts != 2)
@ -106,13 +106,13 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Optimization
}
// Create a new Animatable<PathGeometry> which has only one segment in each keyframe.
var hacked = optimized.KeyFrames.Select(pg => HackPathGeometry(pg));
var hacked = optimized.KeyFrames.SelectToArray(pg => HackPathGeometry(pg));
return new Animatable<Sequence<BezierSegment>>(hacked.First().Value, hacked, optimized.PropertyIndex);
}
static KeyFrame<Sequence<BezierSegment>> HackPathGeometry(KeyFrame<Sequence<BezierSegment>> value)
{
return new KeyFrame<Sequence<BezierSegment>>(value.Frame, new Sequence<BezierSegment>(new[] { value.Value.Items.First() }), Vector3.Zero, Vector3.Zero, value.Easing);
return new KeyFrame<Sequence<BezierSegment>>(value.Frame, new Sequence<BezierSegment>(new[] { value.Value.Items[0] }), Vector3.Zero, Vector3.Zero, value.Easing);
}
// True iff b is between and c.
@ -154,8 +154,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Optimization
}
else
{
var keyFrames = OptimizeKeyFrames(value.InitialValue, value.KeyFrames).ToArray();
if (comparer.Equals(keyFrames, value.KeyFrames))
var keyFrames = OptimizeKeyFrames(value.InitialValue, value.KeyFrames.ToArray()).ToArray();
if (comparer.Equals(keyFrames, value.KeyFrames.ToArray()))
{
// Optimization didn't achieve anything.
result = value;
@ -379,7 +379,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Optimization
return false;
}
return x.InitialValue.Equals(y.InitialValue) && Equals(x.KeyFrames, y.KeyFrames);
return x.InitialValue.Equals(y.InitialValue) && x.KeyFrames.SequenceEqual(y.KeyFrames);
}
public int GetHashCode(KeyFrame<T> obj) => obj.GetHashCode();

Просмотреть файл

@ -29,12 +29,12 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
/// <summary>
/// Gets the items in the sequence.
/// </summary>
public IEnumerable<T> Items => _items;
public ReadOnlySpan<T> Items => _items;
/// <inheritdoc/>
public bool Equals(Sequence<T> other) =>
other != null &&
Enumerable.SequenceEqual(_items, other.Items);
Enumerable.SequenceEqual(_items, other._items);
/// <inheritdoc/>
public override bool Equals(object obj)
@ -62,6 +62,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
}
/// <inheritdoc/>
public override string ToString() => $"{ItemTypeName}s: {string.Join(", ", Items)}";
public override string ToString() => $"{ItemTypeName}s: {string.Join(", ", _items)}";
}
}

Просмотреть файл

@ -215,9 +215,9 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Tools
yield return FromTransform(layer.Transform);
if (layer.Masks != null)
{
foreach (var mask in layer.Masks)
for (var i = 0; i < layer.Masks.Length; i++)
{
yield return FromMask(mask);
yield return FromMask(layer.Masks[i]);
}
}
}
@ -296,9 +296,9 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Tools
yield return item;
}
foreach (var shapeContent in layer.Contents)
for (var i = 0; i < layer.Contents.Length; i++)
{
yield return FromShapeLayerContent(shapeContent);
yield return FromShapeLayerContent(layer.Contents[i]);
}
}
}
@ -379,9 +379,9 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Tools
yield return item;
}
foreach (var item in content.Items)
for (var i = 0; i < content.Items.Length; i++)
{
yield return FromShapeLayerContent(item);
yield return FromShapeLayerContent(content.Items[i]);
}
}
}
@ -515,7 +515,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Tools
}
else
{
var keyframesString = string.Join(", ", animatable.KeyFrames.Select(kf => $"{FromKeyFrame(kf)}"));
var keyframesString = string.Join(", ", animatable.KeyFrames.SelectToArray(kf => $"{FromKeyFrame(kf)}"));
return new XElement(name, keyframesString);
}

Просмотреть файл

@ -2,7 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
{
@ -11,16 +13,18 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
#endif
sealed class ShapeGroup : ShapeLayerContent
{
readonly ShapeLayerContent[] _items;
public ShapeGroup(
string name,
string matchName,
IEnumerable<ShapeLayerContent> items)
: base(name, matchName)
{
Items = items;
_items = items.ToArray();
}
public IEnumerable<ShapeLayerContent> Items { get; }
public ReadOnlySpan<ShapeLayerContent> Items => _items;
/// <inheritdoc/>
public override ShapeContentType ContentType => ShapeContentType.Group;

Просмотреть файл

@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
@ -12,7 +13,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
#endif
sealed class ShapeLayer : Layer
{
readonly IEnumerable<ShapeLayerContent> _shapes;
readonly ShapeLayerContent[] _shapes;
public ShapeLayer(
string name,
@ -44,10 +45,10 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
autoOrient,
masks)
{
_shapes = shapes;
_shapes = shapes.ToArray();
}
public IEnumerable<ShapeLayerContent> Contents => _shapes.AsEnumerable();
public ReadOnlySpan<ShapeLayerContent> Contents => _shapes;
/// <inheritdoc/>
public override LayerType Type => LayerType.Shape;

Просмотреть файл

@ -2,7 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
{
@ -11,6 +13,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
#endif
sealed class SolidColorStroke : ShapeLayerContent
{
readonly double[] _dashPattern;
public SolidColorStroke(
string name,
string matchName,
@ -25,7 +29,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
: base(name, matchName)
{
DashOffset = dashOffset;
DashPattern = dashPattern;
_dashPattern = dashPattern.ToArray();
Color = color;
OpacityPercent = opacityPercent;
Thickness = thickness;
@ -40,7 +44,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
public Animatable<double> Thickness { get; }
public IEnumerable<double> DashPattern { get; }
public ReadOnlySpan<double> DashPattern => _dashPattern;
public Animatable<double> DashOffset { get; }

Просмотреть файл

@ -105,7 +105,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Tools
}
}
_maskCount += layer.Masks.Count();
_maskCount += layer.Masks.Length;
}
}

Просмотреть файл

@ -262,7 +262,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
if (layer.Masks != null &&
layer.Masks.Any())
{
Mask mask = layer.Masks.First();
var mask = layer.Masks[0];
if (mask.Inverted)
{
@ -282,7 +282,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
// Translation currently does not support having multiple paths for masks.
// If possible users should combine masks when exporting to json.
if (layer.Masks.Skip(1).Any())
if (layer.Masks.Length > 1)
{
_unsupported.MultipleShapeMasks();
}
@ -292,7 +292,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
mask.Opacity.InitialValue == 100 &&
!mask.Opacity.IsAnimated &&
mask.Mode == Mask.MaskMode.Additive &&
layer.Masks.Count() == 1)
layer.Masks.Length == 1)
{
var geometry = mask.Points;
@ -847,7 +847,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
var bScale = b.InitialValue;
return new Animatable<double>(
initialValue: a.InitialValue * bScale,
keyFrames: a.KeyFrames.Select(kf => new KeyFrame<double>(
keyFrames: a.KeyFrames.SelectToArray(kf => new KeyFrame<double>(
kf.Frame,
kf.Value * (bScale / 100),
kf.SpatialControlPoint1,
@ -1050,7 +1050,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
CompositionShape TranslateShapeLayerContents(
TranslationContext context,
ShapeContentContext shapeContext,
IEnumerable<ShapeLayerContent> contents)
ReadOnlySpan<ShapeLayerContent> contents)
{
// The Contents of a ShapeLayer is a list of instructions for a stack machine.
@ -1066,7 +1066,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
var result = container;
// If the contents contains a repeater, generate repeated contents
if (contents.Where(slc => slc.ContentType == ShapeContentType.Repeater).Any())
if (contents.Any(slc => slc.ContentType == ShapeContentType.Repeater))
{
// The contents contains a repeater. Treat it as if there are n sets of items (where n
// equals the Count of the repeater). In each set, replace the repeater with
@ -1105,7 +1105,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
// by n transforms.
// TODO - currently ignoring the StartOpacityPercent and EndOpacityPercent - should generate a new transform
// that interpolates that.
var generatedItems = itemsBeforeRepeater.Concat(Enumerable.Repeat(repeater.Transform, i + 1)).Concat(itemsAfterRepeater);
var generatedItems = itemsBeforeRepeater.Concat(Enumerable.Repeat(repeater.Transform, i + 1)).Concat(itemsAfterRepeater).ToArray();
// Recurse to translate the synthesized items.
container.Shapes.Add(TranslateShapeLayerContents(context, shapeContext, generatedItems));
@ -1115,7 +1115,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
}
}
var stack = new Stack<ShapeLayerContent>(contents);
var stack = new Stack<ShapeLayerContent>(contents.ToArray());
while (true)
{
@ -1315,7 +1315,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
{
// Convert all the shapes in the group to a list of geometries
var group = (ShapeGroup)shapeContent;
var groupedGeometries = CreateCanvasGeometries(context.Clone(), new Stack<ShapeLayerContent>(group.Items), pathFillType).ToArray();
var groupedGeometries = CreateCanvasGeometries(context.Clone(), new Stack<ShapeLayerContent>(group.Items.ToArray()), pathFillType).ToArray();
foreach (var geometry in groupedGeometries)
{
yield return geometry;
@ -1369,7 +1369,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
Sn.Matrix3x2 transformMatrix,
bool optimizeLines)
{
var beziers = figure.Items.ToArray();
var beziers = figure.Items;
using (var builder = new CanvasPathBuilder(null))
{
if (beziers.Length == 0)
@ -2551,7 +2551,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
compositionAnimation.Duration = _lc.Duration;
// Get only the key frames that exist from at or just before the animation starts, and end at or just after the animation ends.
var trimmedKeyFrames = Optimizer.GetOptimized(Optimizer.GetTrimmed(value.KeyFrames, context.StartTime, context.EndTime)).ToArray();
var trimmedKeyFrames = Optimizer.GetOptimized(Optimizer.GetTrimmed(value.KeyFrames.ToArray(), context.StartTime, context.EndTime)).ToArray();
if (trimmedKeyFrames.Length == 0)
{
@ -2890,7 +2890,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
// Multiply the color animation by the single opacity value.
return new Animatable<Color>(
initialValue: MultiplyColorByOpacityPercent(color.InitialValue, opacityPercent.InitialValue),
keyFrames: color.KeyFrames.Select(kf =>
keyFrames: color.KeyFrames.SelectToArray(kf =>
new KeyFrame<Color>(
kf.Frame,
MultiplyColorByOpacityPercent(kf.Value, opacityPercent.InitialValue),
@ -2926,7 +2926,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
// Multiply the single color value by the opacity animation.
return new Animatable<Color>(
initialValue: MultiplyColorByOpacityPercent(color, opacityPercent.InitialValue),
keyFrames: opacityPercent.KeyFrames.Select(kf =>
keyFrames: opacityPercent.KeyFrames.SelectToArray(kf =>
new KeyFrame<Color>(
kf.Frame,
MultiplyColorByOpacityPercent(color, kf.Value),

Просмотреть файл

@ -95,8 +95,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.WinCompData.CodeGen
from item in items
let obj = item.Object
where (_ignoreCommentProperties || obj.Comment == null)
&& !obj.Properties.PropertyNames.Any()
&& !obj.Animators.Any()
&& obj.Properties.IsEmpty
&& obj.Animators.Count == 0
select (item.Node, obj);
}
@ -259,7 +259,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.WinCompData.CodeGen
from item in nodes
let obj = item.Object
where (_ignoreCommentProperties || obj.Comment == null)
&& !obj.Properties.PropertyNames.Any()
&& obj.Properties.IsEmpty
select (item.Node, obj);
var grouping =

Просмотреть файл

@ -819,7 +819,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.WinCompData.CodeGen
}
var propertySet = obj.Properties;
if (propertySet.PropertyNames.Any())
if (!propertySet.IsEmpty)
{
builder.WriteLine($"{Var} propertySet = {localName}{Deref}Properties;");
foreach (var prop in propertySet.ScalarProperties)
@ -1194,7 +1194,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.WinCompData.CodeGen
{
var createCallText = $"_c{Deref}CreateColorBrush({Color(obj.Color)})";
if (obj.Animators.Any())
if (obj.Animators.Count > 0)
{
WriteObjectFactoryStart(builder, node);
WriteCreateAssignment(builder, node, createCallText);

Просмотреть файл

@ -150,7 +150,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.WinCompData.CodeGen
// Color brushes that are not animated get names describing their color.
// Optimization ensures there will only be one brush for any one non-animated color.
var brush = (CompositionColorBrush)obj;
if (brush.Animators.Any())
if (brush.Animators.Count > 0)
{
// Brush is animated. Give it a name based on the colors in the animation.
var colorAnimation = (ColorKeyFrameAnimation)brush.Animators.Where(a => a.Animation is ColorKeyFrameAnimation).First().Animation;

Просмотреть файл

@ -89,7 +89,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.WinCompData.CodeGen
obj.RotationAngleInDegrees.HasValue && obj.RotationAngleInDegrees.Value != 0 &&
obj.RotationAxis.HasValue && obj.RotationAxis != Vector3.UnitZ;
if (!obj.Animators.Any() && !hasNonStandardRotation)
if (obj.Animators.Count == 0 && !hasNonStandardRotation)
{
// Get the values of the properties, and the defaults for properties that are not set.
var centerPoint = obj.CenterPoint ?? Vector3.Zero;
@ -136,7 +136,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.WinCompData.CodeGen
// Convert the properties to a transform matrix. This can reduce the
// number of calls needed to initialize the object, and makes finding
// and removing redundant containers easier.
if (!obj.Animators.Any())
if (obj.Animators.Count == 0)
{
// Get the values for the properties, and the defaults for the properties that are not set.
var centerPoint = obj.CenterPoint ?? Vector2.Zero;
@ -211,8 +211,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.WinCompData.CodeGen
var elidableContainers = containerShapes.Where(n =>
{
var container = (CompositionContainerShape)n.Object;
if (container.Properties.PropertyNames.Any() ||
container.Animators.Any() ||
if (!container.Properties.IsEmpty ||
container.Animators.Count > 0 ||
container.CenterPoint != null ||
container.Offset != null ||
container.RotationAngleInDegrees != null ||
@ -223,8 +223,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.WinCompData.CodeGen
foreach (var child in container.Shapes)
{
if (child.Properties.PropertyNames.Any() ||
child.Animators.Any() ||
if (!child.Properties.IsEmpty ||
child.Animators.Count > 0 ||
child.CenterPoint != null ||
child.Offset != null ||
child.RotationAngleInDegrees != null ||
@ -264,8 +264,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.WinCompData.CodeGen
container.RotationAngleInDegrees != null ||
container.Scale != null ||
container.TransformMatrix != null ||
container.Animators.Any() ||
container.Properties.PropertyNames.Any())
container.Animators.Count > 0 ||
!container.Properties.IsEmpty)
{
return false;
}
@ -336,8 +336,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.WinCompData.CodeGen
container.Scale == null &&
container.Size == null &&
container.TransformMatrix == null &&
!container.Animators.Any() &&
!container.Properties.PropertyNames.Any();
container.Animators.Count == 0 &&
container.Properties.IsEmpty;
}).ToArray();
// Pull the children of the container into the parent of the container. Remove the unnecessary containers.

Просмотреть файл

@ -80,7 +80,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.WinCompData
/// <summary>
/// Gets the animators that are bound to this object.
/// </summary>
public IEnumerable<Animator> Animators => _animators;
public IReadOnlyList<Animator> Animators => _animators;
public AnimationController TryGetAnimationController(string target) =>
_animators.Where(a => a.AnimatedProperty == target).Single().Controller;

Просмотреть файл

@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
@ -34,7 +33,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.WinCompData
internal IEnumerable<string> PropertyNames => _scalarProperties.Keys.Concat(_vector2Properties.Keys);
internal bool IsEmpty => !PropertyNames.Any();
internal bool IsEmpty => _scalarProperties.Count + _vector2Properties.Count == 0;
/// <inheritdoc/>
public override CompositionObjectType Type => CompositionObjectType.CompositionPropertySet;

Просмотреть файл

@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.Toolkit.Uwp.UI.Lottie.WinCompData
{
@ -13,7 +12,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.WinCompData
#endif
abstract class KeyFrameAnimation<T> : KeyFrameAnimation_
{
readonly Dictionary<float, KeyFrame> _keyFrames = new Dictionary<float, KeyFrame>();
readonly SortedList<float, KeyFrame> _keyFrames = new SortedList<float, KeyFrame>();
protected private KeyFrameAnimation(KeyFrameAnimation<T> other)
: base(other)
@ -44,7 +43,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.WinCompData
_keyFrames.Add(progress, new ValueKeyFrame { Progress = progress, Value = value, Easing = easing });
}
public IEnumerable<KeyFrame> KeyFrames => _keyFrames.Values.OrderBy(kf => kf.Progress);
public IEnumerable<KeyFrame> KeyFrames => _keyFrames.Values;
/// <inheritdoc/>
public override int KeyFrameCount => _keyFrames.Count;

Просмотреть файл

@ -8,10 +8,7 @@ using System.Collections.Generic;
namespace Microsoft.Toolkit.Uwp.UI.Lottie.WinCompData.Tools
{
#if !WINDOWS_UWP
public
#endif
sealed class ListOfNeverNull<T> : IList<T>
sealed class ListOfNeverNull<T> : IList<T>, IReadOnlyList<T>
{
readonly List<T> _wrapped = new List<T>();