Add support for gradient strokes. (#181)

* Add support for gradient strokes.

* Make IRadialGradient compatible with pre-8.0 C# compiler.

WinRT can't use C# 8.0 yet, and the "public" on interface members is a C# 8.0 feature. It was a mistake to have "public" on there anyway.

* CR feedback.
This commit is contained in:
Simeon 2019-11-06 11:52:47 -08:00 коммит произвёл GitHub
Родитель 9928d5ec25
Коммит d0df8a8187
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
16 изменённых файлов: 354 добавлений и 191 удалений

Двоичные данные
source/Issues/LT0007.md

Двоичный файл не отображается.

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

@ -0,0 +1,20 @@
// 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.
namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
{
#if PUBLIC_LottieData
public
#endif
interface IGradient
{
IAnimatableVector3 StartPoint { get; }
IAnimatableVector3 EndPoint { get; }
Animatable<Sequence<ColorGradientStop>> ColorStops { get; }
Animatable<Sequence<OpacityGradientStop>> OpacityPercentStops { get; }
}
}

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

@ -0,0 +1,16 @@
// 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.
namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
{
#if PUBLIC_LottieData
public
#endif
interface IRadialGradient : IGradient
{
Animatable<double> HighlightLength { get; }
Animatable<double> HighlightDegrees { get; }
}
}

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

@ -7,7 +7,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
#if PUBLIC_LottieData
public
#endif
sealed class LinearGradientFill : ShapeFill
sealed class LinearGradientFill : ShapeFill, IGradient
{
public LinearGradientFill(
in ShapeLayerContentArgs args,

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

@ -2,14 +2,12 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using static Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.SolidColorStroke;
namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
{
#if PUBLIC_LottieData
public
#endif
sealed class LinearGradientStroke : ShapeStroke
sealed class LinearGradientStroke : ShapeStroke, IGradient
{
public LinearGradientStroke(
in ShapeLayerContentArgs args,
@ -22,26 +20,14 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
IAnimatableVector3 endPoint,
Animatable<Sequence<ColorGradientStop>> colorStops,
Animatable<Sequence<OpacityGradientStop>> opacityPercentStops)
: base(in args, opacityPercent)
: base(in args, opacityPercent, strokeWidth, capType, joinType, miterLimit)
{
StrokeWidth = strokeWidth;
CapType = capType;
JoinType = joinType;
MiterLimit = miterLimit;
StartPoint = startPoint;
EndPoint = endPoint;
ColorStops = colorStops;
OpacityPercentStops = opacityPercentStops;
}
public Animatable<double> StrokeWidth { get; }
public LineCapType CapType { get; }
public LineJoinType JoinType { get; }
public double MiterLimit { get; }
public IAnimatableVector3 StartPoint { get; }
public IAnimatableVector3 EndPoint { get; }

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

@ -17,11 +17,11 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
/// Initializes a new instance of the <see cref="LottieComposition"/> class.
/// </summary>
/// <param name="name">The name of the composition.</param>
/// <param name="width">Width of animation canvas as specified in AfterEffects.</param>
/// <param name="height">Height of animation canvas as specified in AfterEffects.</param>
/// <param name="inPoint">Frame at which animation begins as specified in AfterEffects.</param>
/// <param name="outPoint">Frame at which animation ends as specified in AfterEffects.</param>
/// <param name="framesPerSecond">FrameRate (frames per second) at which animation data was generated in AfterEffects.</param>
/// <param name="width">Width of animation canvas as specified in After Effects.</param>
/// <param name="height">Height of animation canvas as specified in After Effects.</param>
/// <param name="inPoint">Frame at which animation begins as specified in After Effects.</param>
/// <param name="outPoint">Frame at which animation ends as specified in After Effects.</param>
/// <param name="framesPerSecond">FrameRate (frames per second) at which animation data was generated in After Effects.</param>
/// <param name="is3d">True if the composition is 3d.</param>
/// <param name="version">The version of the schema of the composition.</param>
/// <param name="assets">Assets that are part of the composition.</param>

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

@ -6,6 +6,8 @@
<SharedGUID>b3db16ee-a821-4474-a188-e64926529bbd</SharedGUID>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)IGradient.cs" />
<Compile Include="$(MSBuildThisFileDirectory)IRadialGradient.cs" />
<Compile Include="$(MSBuildThisFileDirectory)\Animatable.cs" />
<Compile Include="$(MSBuildThisFileDirectory)\ExtensionMethods.cs" />
<Compile Include="$(MSBuildThisFileDirectory)\AnimatableVector3.cs" />

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

@ -7,7 +7,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
#if PUBLIC_LottieData
public
#endif
sealed class RadialGradientFill : ShapeFill
sealed class RadialGradientFill : ShapeFill, IRadialGradient
{
public RadialGradientFill(
in ShapeLayerContentArgs args,

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

@ -2,14 +2,12 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using static Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.SolidColorStroke;
namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
{
#if PUBLIC_LottieData
public
#endif
sealed class RadialGradientStroke : ShapeStroke
sealed class RadialGradientStroke : ShapeStroke, IRadialGradient
{
public RadialGradientStroke(
in ShapeLayerContentArgs args,
@ -24,12 +22,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
Animatable<Sequence<OpacityGradientStop>> opacityPercentStops,
Animatable<double> highlightLength,
Animatable<double> highlightDegrees)
: base(in args, opacityPercent)
: base(in args, opacityPercent, strokeWidth, capType, joinType, miterLimit)
{
StrokeWidth = strokeWidth;
CapType = capType;
JoinType = joinType;
MiterLimit = miterLimit;
StartPoint = startPoint;
EndPoint = endPoint;
ColorStops = colorStops;
@ -38,14 +32,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
HighlightDegrees = highlightDegrees;
}
public Animatable<double> StrokeWidth { get; }
public LineCapType CapType { get; }
public LineJoinType JoinType { get; }
public double MiterLimit { get; }
public IAnimatableVector3 StartPoint { get; }
public IAnimatableVector3 EndPoint { get; }

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

@ -424,7 +424,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
yield return FromAnimatable(nameof(content.Color), content.Color);
yield return FromAnimatable(nameof(content.OpacityPercent), content.OpacityPercent);
yield return FromAnimatable(nameof(content.Thickness), content.Thickness);
yield return FromAnimatable(nameof(content.StrokeWidth), content.StrokeWidth);
}
}

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

@ -346,7 +346,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
var result = superclassContent;
result.Add("Color", FromAnimatable(content.Color, FromColor));
result.Add("OpacityPercent", FromAnimatable(content.OpacityPercent));
result.Add("Thickness", FromAnimatable(content.Thickness));
result.Add("Thickness", FromAnimatable(content.StrokeWidth));
return result;
}

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

@ -11,16 +11,46 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
{
public ShapeStroke(
in ShapeLayerContentArgs args,
Animatable<double> opacityPercent)
Animatable<double> opacityPercent,
Animatable<double> strokeWidth,
LineCapType capType,
LineJoinType joinType,
double miterLimit)
: base(in args)
{
OpacityPercent = opacityPercent;
StrokeWidth = strokeWidth;
CapType = capType;
JoinType = joinType;
MiterLimit = miterLimit;
}
public Animatable<double> OpacityPercent { get; }
public Animatable<double> StrokeWidth { get; }
public LineCapType CapType { get; }
public LineJoinType JoinType { get; }
public double MiterLimit { get; }
public abstract ShapeStrokeKind StrokeKind { get; }
public enum LineCapType
{
Butt,
Round,
Projected,
}
public enum LineJoinType
{
Miter,
Round,
Bevel,
}
public enum ShapeStrokeKind
{
SolidColor,

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

@ -21,35 +21,23 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
IEnumerable<double> dashPattern,
Animatable<Color> color,
Animatable<double> opacityPercent,
Animatable<double> thickness,
Animatable<double> strokeWidth,
LineCapType capType,
LineJoinType joinType,
double miterLimit)
: base(in args, opacityPercent)
: base(in args, opacityPercent, strokeWidth, capType, joinType, miterLimit)
{
DashOffset = dashOffset;
_dashPattern = dashPattern.ToArray();
Color = color;
Thickness = thickness;
CapType = capType;
JoinType = joinType;
MiterLimit = miterLimit;
}
public Animatable<Color> Color { get; }
public Animatable<double> Thickness { get; }
public ReadOnlySpan<double> DashPattern => _dashPattern;
public Animatable<double> DashOffset { get; }
public LineCapType CapType { get; }
public LineJoinType JoinType { get; }
public double MiterLimit { get; }
/// <inheritdoc/>
public override ShapeContentType ContentType => ShapeContentType.SolidColorStroke;
@ -57,19 +45,5 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
public override LottieObjectType ObjectType => LottieObjectType.SolidColorStroke;
public override ShapeStrokeKind StrokeKind => ShapeStrokeKind.SolidColor;
public enum LineCapType
{
Butt,
Round,
Projected,
}
public enum LineJoinType
{
Miter,
Round,
Bevel,
}
}
}

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

@ -964,7 +964,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
var strokeWidth = ReadAnimatableFloat(obj.GetNamedObject("w"));
var capType = LcToLineCapType(obj.GetNamedNumber("lc"));
var joinType = LjToLineJoinType(obj.GetNamedNumber("lj"));
var miterLimit = obj.GetNamedNumber("ml", 4); // Default miter limit in AfterEffects is 4
var miterLimit = obj.GetNamedNumber("ml", 4); // Default miter limit in After Effects is 4
// Get dash pattern to be set as StrokeDashArray
Animatable<double> offset = null;
@ -1018,8 +1018,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
LinearGradientStroke ReadLinearGradientStroke(JObject obj, in ShapeLayerContent.ShapeLayerContentArgs shapeLayerContentArgs)
{
_issues.GradientStrokes();
// Not clear whether we need to read these fields.
IgnoreFieldThatIsNotYetSupported(obj, "hd");
IgnoreFieldThatIsNotYetSupported(obj, "t");
@ -1029,7 +1027,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
var strokeWidth = ReadAnimatableFloat(obj.GetNamedObject("w"));
var capType = LcToLineCapType(obj.GetNamedNumber("lc"));
var joinType = LjToLineJoinType(obj.GetNamedNumber("lj"));
var miterLimit = obj.GetNamedNumber("ml", 4); // Default miter limit in AfterEffects is 4
var miterLimit = obj.GetNamedNumber("ml", 4); // Default miter limit in After Effects is 4
var startPoint = ReadAnimatableVector3(obj.GetNamedObject("s"));
var endPoint = ReadAnimatableVector3(obj.GetNamedObject("e"));
ReadAnimatableGradientStops(obj.GetNamedObject("g"), out var colorStops, out var opacityPercentStops);
@ -1050,8 +1048,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
RadialGradientStroke ReadRadialGradientStroke(JObject obj, in ShapeLayerContent.ShapeLayerContentArgs shapeLayerContentArgs)
{
_issues.GradientStrokes();
// Not clear whether we need to read these fields.
IgnoreFieldThatIsNotYetSupported(obj, "t");
@ -1077,7 +1073,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
var strokeWidth = ReadAnimatableFloat(obj.GetNamedObject("w"));
var capType = LcToLineCapType(obj.GetNamedNumber("lc"));
var joinType = LjToLineJoinType(obj.GetNamedNumber("lj"));
var miterLimit = obj.GetNamedNumber("ml", 4); // Default miter limit in AfterEffects is 4
var miterLimit = obj.GetNamedNumber("ml", 4); // Default miter limit in After Effects is 4
var startPoint = ReadAnimatableVector3(obj.GetNamedObject("s"));
var endPoint = ReadAnimatableVector3(obj.GetNamedObject("e"));
ReadAnimatableGradientStops(obj.GetNamedObject("g"), out var colorStops, out var opacityPercentStops);

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

@ -1146,7 +1146,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
readonly LottieToWinCompTranslator _owner;
internal SolidColorStroke Stroke { get; private set; }
internal ShapeStroke Stroke { get; private set; }
internal ShapeFill Fill { get; private set; }
@ -1176,19 +1176,16 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
var popped = stack.Peek();
switch (popped.ContentType)
{
case ShapeContentType.LinearGradientStroke:
case ShapeContentType.RadialGradientStroke:
_owner._issues.GradientStrokeIsNotSupported();
break;
case ShapeContentType.LinearGradientFill:
case ShapeContentType.RadialGradientFill:
case ShapeContentType.SolidColorFill:
Fill = ComposeFills(Fill, (ShapeFill)popped);
break;
case ShapeContentType.LinearGradientStroke:
case ShapeContentType.RadialGradientStroke:
case ShapeContentType.SolidColorStroke:
Stroke = ComposeStrokes(Stroke, (SolidColorStroke)popped);
Stroke = ComposeStrokes(Stroke, (ShapeStroke)popped);
break;
case ShapeContentType.RoundedCorner:
@ -1389,7 +1386,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
return b;
}
SolidColorStroke ComposeStrokes(SolidColorStroke a, SolidColorStroke b)
ShapeStroke ComposeStrokes(ShapeStroke a, ShapeStroke b)
{
if (a == null)
{
@ -1400,11 +1397,69 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
return a;
}
if (!a.Thickness.IsAnimated && !b.Thickness.IsAnimated &&
if (a.StrokeKind != b.StrokeKind)
{
_owner._issues.MultipleStrokesIsNotSupported();
}
switch (a.StrokeKind)
{
case ShapeStroke.ShapeStrokeKind.SolidColor:
return ComposeSolidColorStrokes((SolidColorStroke)a, (SolidColorStroke)b);
case ShapeStroke.ShapeStrokeKind.LinearGradient:
return ComposeLinearGradientStrokes((LinearGradientStroke)a, (LinearGradientStroke)b);
case ShapeStroke.ShapeStrokeKind.RadialGradient:
return ComposeRadialGradientStrokes((RadialGradientStroke)a, (RadialGradientStroke)b);
default:
throw new InvalidOperationException();
}
}
LinearGradientStroke ComposeLinearGradientStrokes(LinearGradientStroke a, LinearGradientStroke b)
{
Debug.Assert(a != null && b != null, "Precondition");
if (!a.StrokeWidth.IsAnimated && !b.StrokeWidth.IsAnimated &&
a.OpacityPercent.AlwaysEquals(100) && b.OpacityPercent.AlwaysEquals(100))
{
if (a.StrokeWidth.InitialValue >= b.StrokeWidth.InitialValue)
{
// a occludes b, so b can be ignored.
return a;
}
}
_owner._issues.MultipleStrokesIsNotSupported();
return a;
}
RadialGradientStroke ComposeRadialGradientStrokes(RadialGradientStroke a, RadialGradientStroke b)
{
Debug.Assert(a != null && b != null, "Precondition");
if (!a.StrokeWidth.IsAnimated && !b.StrokeWidth.IsAnimated &&
a.OpacityPercent.AlwaysEquals(100) && b.OpacityPercent.AlwaysEquals(100))
{
if (a.StrokeWidth.InitialValue >= b.StrokeWidth.InitialValue)
{
// a occludes b, so b can be ignored.
return a;
}
}
_owner._issues.MultipleStrokesIsNotSupported();
return a;
}
SolidColorStroke ComposeSolidColorStrokes(SolidColorStroke a, SolidColorStroke b)
{
Debug.Assert(a != null && b != null, "Precondition");
if (!a.StrokeWidth.IsAnimated && !b.StrokeWidth.IsAnimated &&
!a.DashPattern.Any() && !b.DashPattern.Any() &&
a.OpacityPercent.AlwaysEquals(100) && b.OpacityPercent.AlwaysEquals(100))
{
if (a.Thickness.InitialValue >= b.Thickness.InitialValue)
if (a.StrokeWidth.InitialValue >= b.StrokeWidth.InitialValue)
{
// a occludes b, so b can be ignored.
return a;
@ -2581,39 +2636,73 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
void TranslateAndApplyStroke(
TranslationContext context,
SolidColorStroke shapeStroke,
ShapeStroke shapeStroke,
CompositionSpriteShape sprite,
TrimmedAnimatable<double> contextOpacityPercent)
{
if (shapeStroke == null || shapeStroke.Thickness.AlwaysEquals(0))
if (shapeStroke == null)
{
return;
}
// A ShapeStroke is represented as a CompositionColorBrush and Stroke properties on the relevant SpriteShape.
// Map ShapeStroke's color to SpriteShape.StrokeBrush
sprite.StrokeBrush = CreateAnimatedColorBrush(
if (shapeStroke.StrokeWidth.AlwaysEquals(0))
{
return;
}
switch (shapeStroke.StrokeKind)
{
case ShapeStroke.ShapeStrokeKind.SolidColor:
TranslateAndApplySolidColorStroke(context, (SolidColorStroke)shapeStroke, sprite, contextOpacityPercent);
break;
case ShapeStroke.ShapeStrokeKind.LinearGradient:
TranslateAndApplyLinearGradientStroke(context, (LinearGradientStroke)shapeStroke, sprite, contextOpacityPercent);
break;
case ShapeStroke.ShapeStrokeKind.RadialGradient:
TranslateAndApplyRadialGradientStroke(context, (RadialGradientStroke)shapeStroke, sprite, contextOpacityPercent);
break;
default:
throw new InvalidOperationException();
}
}
void TranslateAndApplyLinearGradientStroke(
TranslationContext context,
LinearGradientStroke shapeStroke,
CompositionSpriteShape sprite,
TrimmedAnimatable<double> contextOpacityPercent)
{
ApplyCommonStrokeProperties(
context,
MultiplyAnimatableColorByAnimatableOpacityPercent(
context.TrimAnimatable(shapeStroke.Color),
context.TrimAnimatable(shapeStroke.OpacityPercent)),
contextOpacityPercent);
shapeStroke,
TranslateLinearGradientStroke(context, shapeStroke, contextOpacityPercent),
sprite);
}
var strokeThickness = context.TrimAnimatable(shapeStroke.Thickness);
if (strokeThickness.IsAnimated)
{
ApplyScalarKeyFrameAnimation(context, strokeThickness, sprite, nameof(sprite.StrokeThickness));
}
else
{
sprite.StrokeThickness = (float)strokeThickness.InitialValue;
}
void TranslateAndApplyRadialGradientStroke(
TranslationContext context,
RadialGradientStroke shapeStroke,
CompositionSpriteShape sprite,
TrimmedAnimatable<double> contextOpacityPercent)
{
ApplyCommonStrokeProperties(
context,
shapeStroke,
TranslateRadialGradientStroke(context, shapeStroke, contextOpacityPercent),
sprite);
}
sprite.StrokeStartCap = sprite.StrokeEndCap = sprite.StrokeDashCap = StrokeCap(shapeStroke.CapType);
sprite.StrokeLineJoin = StrokeLineJoin(shapeStroke.JoinType);
sprite.StrokeMiterLimit = (float)shapeStroke.MiterLimit;
void TranslateAndApplySolidColorStroke(
TranslationContext context,
SolidColorStroke shapeStroke,
CompositionSpriteShape sprite,
TrimmedAnimatable<double> contextOpacityPercent)
{
ApplyCommonStrokeProperties(
context,
shapeStroke,
TranslateSolidColor(context, shapeStroke.Color, shapeStroke.OpacityPercent, contextOpacityPercent),
sprite);
// NOTE: DashPattern animation (animating dash sizes) are not supported on CompositionSpriteShape.
foreach (var dash in shapeStroke.DashPattern)
@ -2633,6 +2722,32 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
}
}
// Applies the properties that are common to all Lottie ShapeStrokes to a CompositionSpriteShape.
void ApplyCommonStrokeProperties(
TranslationContext context,
ShapeStroke shapeStroke,
CompositionBrush brush,
CompositionSpriteShape sprite)
{
var strokeThickness = context.TrimAnimatable(shapeStroke.StrokeWidth);
if (strokeThickness.IsAnimated)
{
ApplyScalarKeyFrameAnimation(context, strokeThickness, sprite, nameof(sprite.StrokeThickness));
}
else
{
sprite.StrokeThickness = (float)strokeThickness.InitialValue;
}
sprite.StrokeStartCap = sprite.StrokeEndCap = sprite.StrokeDashCap = StrokeCap(shapeStroke.CapType);
sprite.StrokeLineJoin = StrokeLineJoin(shapeStroke.JoinType);
sprite.StrokeMiterLimit = (float)shapeStroke.MiterLimit;
sprite.StrokeBrush = brush;
}
CompositionBrush TranslateShapeFill(TranslationContext context, ShapeFill shapeFill, TrimmedAnimatable<double> opacityPercent)
{
if (shapeFill == null)
@ -2653,30 +2768,26 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
}
}
CompositionColorBrush TranslateSolidColorFill(TranslationContext context, SolidColorFill shapeFill, TrimmedAnimatable<double> opacityPercent)
CompositionColorBrush TranslateSolidColor(TranslationContext context, Animatable<Color> color, Animatable<double> opacityPercentA, TrimmedAnimatable<double> opacityPercentB)
{
return CreateAnimatedColorBrush(
context,
MultiplyAnimatableColorByAnimatableOpacityPercent(
context.TrimAnimatable(shapeFill.Color),
context.TrimAnimatable(shapeFill.OpacityPercent)),
opacityPercent);
context.TrimAnimatable(color),
context.TrimAnimatable(opacityPercentA)),
opacityPercentB);
}
CompositionColorBrush TranslateSolidColorFill(TranslationContext context, SolidColorFill shapeFill, TrimmedAnimatable<double> opacityPercent)
=> TranslateSolidColor(context, shapeFill.Color, shapeFill.OpacityPercent, opacityPercent);
CompositionLinearGradientBrush TranslateLinearGradientFill(
TranslationContext context,
LinearGradientFill shapeFill,
TrimmedAnimatable<double> opacityPercent)
{
var colorStops = context.TrimAnimatable(shapeFill.ColorStops);
var opacityPercentStops = context.TrimAnimatable(shapeFill.OpacityPercentStops);
if (colorStops.InitialValue.Items.IsEmpty)
{
// If there are no color stops then we can't create a brush.
return null;
}
if (opacityPercent.IsAnimated)
{
// We don't yet support animated opacity with LinearGradientFill.
@ -2689,15 +2800,90 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
_issues.GradientFillIsNotSupported("Linear", "opacity stops");
}
var opacityPercentValue = opacityPercent.InitialValue;
return TranslateLinearGradientFill(context, shapeFill, colorStops, opacityPercentValue);
return TranslateLinearGradient(
context,
shapeFill,
opacityPercent.InitialValue);
}
CompositionLinearGradientBrush TranslateLinearGradientFill(
CompositionGradientBrush TranslateLinearGradientStroke(
TranslationContext context,
LinearGradientFill shapeFill,
TrimmedAnimatable<Sequence<ColorGradientStop>> colorStops,
LinearGradientStroke shapeStroke,
TrimmedAnimatable<double> contextOpacityPercent)
{
var opacityPercentStops = context.TrimAnimatable(shapeStroke.OpacityPercentStops);
if (contextOpacityPercent.IsAnimated)
{
// We don't yet support animated opacity with LinearGradientFill.
_issues.GradientStrokeIsNotSupported("Linear", "animated opacity");
}
if (!opacityPercentStops.InitialValue.Items.IsEmpty)
{
// We don't yet support opacity stops.
_issues.GradientStrokeIsNotSupported("Linear", "opacity stops");
}
return TranslateLinearGradient(
context,
shapeStroke,
contextOpacityPercent.InitialValue);
}
CompositionBrush TranslateRadialGradientFill(
TranslationContext context,
RadialGradientFill shapeFill,
TrimmedAnimatable<double> opacityPercent)
{
var opacityPercentStops = context.TrimAnimatable(shapeFill.OpacityPercentStops);
if (opacityPercent.IsAnimated)
{
// We don't yet support animated opacity with RadialGradientFill.
_issues.GradientFillIsNotSupported("Radial", "animated opacity");
}
if (!opacityPercentStops.InitialValue.Items.IsEmpty)
{
// We don't yet support opacity stops.
_issues.GradientFillIsNotSupported("Radial", "opacity stops");
}
return TranslateRadialGradient(
context,
shapeFill,
opacityPercent.InitialValue);
}
CompositionGradientBrush TranslateRadialGradientStroke(
TranslationContext context,
RadialGradientStroke shapeStroke,
TrimmedAnimatable<double> contextOpacityPercent)
{
var opacityPercentStops = context.TrimAnimatable(shapeStroke.OpacityPercentStops);
if (contextOpacityPercent.IsAnimated)
{
// We don't yet support animated opacity with RadialGradientStroke.
_issues.GradientStrokeIsNotSupported("Radial", "animated opacity");
}
if (!opacityPercentStops.InitialValue.Items.IsEmpty)
{
// We don't yet support opacity stops.
_issues.GradientStrokeIsNotSupported("Radial", "opacity stops");
}
return TranslateRadialGradient(
context,
shapeStroke,
contextOpacityPercent.InitialValue);
}
CompositionLinearGradientBrush TranslateLinearGradient(
TranslationContext context,
IGradient linearGradient,
double opacityPercentValue)
{
var result = _c.CreateLinearGradientBrush();
@ -2705,8 +2891,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
// BodyMovin specifies start and end points in absolute values.
result.MappingMode = CompositionMappingMode.Absolute;
var startPoint = context.TrimAnimatable(shapeFill.StartPoint);
var endPoint = context.TrimAnimatable(shapeFill.EndPoint);
var startPoint = context.TrimAnimatable(linearGradient.StartPoint);
var endPoint = context.TrimAnimatable(linearGradient.EndPoint);
if (startPoint.IsAnimated)
{
@ -2728,6 +2914,14 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
var brushStops = result.ColorStops;
var colorStops = context.TrimAnimatable(linearGradient.ColorStops);
if (colorStops.InitialValue.Items.IsEmpty)
{
// If there are no color stops then we can't create a brush.
return null;
}
if (colorStops.IsAnimated)
{
// Lottie represents animation of stops as a sequence of lists of stops.
@ -2776,73 +2970,25 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
return result;
}
CompositionBrush TranslateRadialGradientFill(
CompositionGradientBrush TranslateRadialGradient(
TranslationContext context,
RadialGradientFill shapeFill,
TrimmedAnimatable<double> opacityPercent)
{
var colorStops = context.TrimAnimatable(shapeFill.ColorStops);
var opacityPercentStops = context.TrimAnimatable(shapeFill.OpacityPercentStops);
if (colorStops.InitialValue.Items.IsEmpty)
{
// If there are no color stops then we can't create a brush.
return null;
}
if (opacityPercent.IsAnimated)
{
// We don't yet support animated opacity with RadialGradientFill.
_issues.GradientFillIsNotSupported("Radial", "animated opacity");
}
if (!opacityPercentStops.InitialValue.Items.IsEmpty)
{
// We don't yet support opacity stops.
_issues.GradientFillIsNotSupported("Radial", "opacity stops");
}
var opacityPercentValue = opacityPercent.InitialValue;
if (IsUapApiAvailable(nameof(CompositionRadialGradientBrush), versionDependentFeatureDescription: "Radial gradient fill"))
{
return TranslateRadialGradientFillToCompositionRadialGradientBrush(context, shapeFill, colorStops, opacityPercentValue);
}
else
{
// Radial gradient is not available. Convert the RadialGradientFill to a LinearGradientFill as a compromise.
var fillArgs = new ShapeLayerContent.ShapeLayerContentArgs()
{
BlendMode = shapeFill.BlendMode,
MatchName = shapeFill.MatchName,
Name = shapeFill.Name,
};
var linearFill = new LinearGradientFill(
in fillArgs,
shapeFill.FillType,
shapeFill.OpacityPercent,
shapeFill.StartPoint,
shapeFill.EndPoint,
shapeFill.ColorStops,
shapeFill.OpacityPercentStops);
return TranslateLinearGradientFill(context, linearFill, opacityPercent);
}
}
CompositionRadialGradientBrush TranslateRadialGradientFillToCompositionRadialGradientBrush(
TranslationContext context,
RadialGradientFill shapeFill,
TrimmedAnimatable<Sequence<ColorGradientStop>> colorStops,
IRadialGradient gradient,
double opacityPercentValue)
{
if (!IsUapApiAvailable(nameof(CompositionRadialGradientBrush), versionDependentFeatureDescription: "Radial gradient fill"))
{
// CompositionRadialGradientBrush didn't exist until UAP v8. If the target OS doesn't support
// UAP v8 then fall back to linear gradients as a compromise.
return TranslateLinearGradient(context, gradient, opacityPercentValue);
}
var result = _c.CreateRadialGradientBrush();
// BodyMovin specifies start and end points in absolute values.
result.MappingMode = CompositionMappingMode.Absolute;
var startPoint = context.TrimAnimatable(shapeFill.StartPoint);
var endPoint = context.TrimAnimatable(shapeFill.EndPoint);
var startPoint = context.TrimAnimatable(gradient.StartPoint);
var endPoint = context.TrimAnimatable(gradient.EndPoint);
if (startPoint.IsAnimated)
{
@ -2861,14 +3007,21 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
result.EllipseRadius = new Sn.Vector2(Sn.Vector2.Distance(Vector2(startPoint.InitialValue), Vector2(endPoint.InitialValue)));
if (shapeFill.HighlightLength != null &&
(shapeFill.HighlightLength.InitialValue != 0 || shapeFill.HighlightLength.IsAnimated))
if (gradient.HighlightLength != null &&
(gradient.HighlightLength.InitialValue != 0 || gradient.HighlightLength.IsAnimated))
{
// We don't yet support animated HighlightLength.
_issues.GradientFillIsNotSupported("Radial", "animated highlight length");
}
var brushStops = result.ColorStops;
var colorStops = context.TrimAnimatable(gradient.ColorStops);
if (colorStops.InitialValue.Items.IsEmpty)
{
// If there are no color stops then we can't create a brush.
return null;
}
if (colorStops.IsAnimated)
{

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

@ -44,7 +44,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
internal void GradientFillIsNotSupported(string linearOrRadial, string combination) => Report("LT0006", $"{linearOrRadial} gradient fill with {combination} is not supported.");
internal void GradientStrokeIsNotSupported() => Report("LT0007", "Gradient stroke is not supported.");
internal void GradientStrokeIsNotSupported(string linearOrRadial, string combination) => Report("LT0007", $"{linearOrRadial} gradient stroke with {combination} is not supported.");
internal void ImageLayerIsNotSupported() => Report("LT0009", "Image layers are not supported.");