Simplified factories for some common cases. (#278)

* Simplified factories for some common cases.

This simplifies the codegen for the creation of some objects. This results in smaller
outputs and a slight perf improvement.
This commit is contained in:
Simeon 2020-06-04 09:56:30 -07:00 коммит произвёл GitHub
Родитель c544e564c6
Коммит 34367ced9b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
2 изменённых файлов: 89 добавлений и 24 удалений

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

@ -51,6 +51,39 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.Tools
/// </summary>
public int Position { get; private set; }
/// <summary>
/// Returns <c>True</c> iff this node is reachable from the given node.
/// </summary>
/// <param name="node">The node to test.</param>
/// <returns><c>True</c> if this node is reachable from the given node.</returns>
public bool IsReachableFrom(Node<T> node) => node is null ? false : IsReachableFrom(node, new HashSet<Node<T>>());
bool IsReachableFrom(Node<T> targetNode, HashSet<Node<T>> alreadyVisited)
{
// Walk the tree of references to this node, ignoring any that have already
// been visited.
foreach (var vertex in targetNode.InReferences)
{
// inRef is a node that directly references this node.
var inRef = vertex.Node;
if (alreadyVisited.Add(inRef))
{
// We haven't examined the inRef node yet.
if (inRef == targetNode || inRef.IsReachableFrom(targetNode, alreadyVisited))
{
// inRef is the targetNode, or it's reachable from targetNode.
return true;
}
// This node is not reachable from the targetNode.
}
}
// Not reachable from targetNode.
return false;
}
public struct Vertex
{
/// <summary>

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

@ -2797,20 +2797,28 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen
bool GenerateCompositionPathGeometryFactory(CodeBuilder builder, CompositionPathGeometry obj, ObjectData node)
{
WriteObjectFactoryStart(builder, node);
if (obj.Path is null)
var path = obj.Path is null ? null : _objectGraph[obj.Path];
var createPathText = path is null ? string.Empty : CallFactoryFromFor(node, path);
var createPathGeometryText = $"_c{Deref}CreatePathGeometry({createPathText})";
if (obj.Animators.Count == 0 &&
obj.Properties.Names.Count == 0 &&
!obj.TrimEnd.HasValue &&
!obj.TrimOffset.HasValue &&
!obj.TrimStart.HasValue &&
!node.IsReachableFrom(path))
{
WriteCreateAssignment(builder, node, $"_c{Deref}CreatePathGeometry()");
WriteSimpleObjectFactory(builder, node, createPathGeometryText);
}
else
{
var path = _objectGraph[obj.Path];
WriteCreateAssignment(builder, node, $"_c{Deref}CreatePathGeometry({CallFactoryFromFor(node, path)})");
WriteObjectFactoryStart(builder, node);
WriteCreateAssignment(builder, node, createPathGeometryText);
InitializeCompositionGeometry(builder, obj, node);
StartAnimationsOnResult(builder, obj, node);
WriteObjectFactoryEnd(builder);
}
InitializeCompositionGeometry(builder, obj, node);
StartAnimationsOnResult(builder, obj, node);
WriteObjectFactoryEnd(builder);
return true;
}
@ -3009,27 +3017,51 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.CodeGen
bool GenerateCompositionSurfaceBrushFactory(CodeBuilder builder, CompositionSurfaceBrush obj, ObjectData node)
{
WriteObjectFactoryStart(builder, node);
WriteCreateAssignment(builder, node, $"_c{Deref}CreateSurfaceBrush()");
InitializeCompositionBrush(builder, obj, node);
if (obj.Surface != null)
var surfaceNode = obj.Surface switch
{
switch (obj.Surface)
CompositionObject compositionObject => NodeFor(compositionObject),
Wmd.LoadedImageSurface loadedImageSurface => NodeFor(loadedImageSurface),
_ => null,
};
// Create the code that initializes the Surface.
var surfaceInitializationText = obj.Surface switch
{
CompositionObject compositionObject => CallFactoryFromFor(node, compositionObject),
Wmd.LoadedImageSurface _ => surfaceNode.FieldName,
null => string.Empty,
_ => throw new InvalidOperationException(),
};
var isReachableFromSurfaceNode = node.IsReachableFrom(surfaceNode);
if (obj.Animators.Count == 0 &&
obj.Properties.Names.Count == 0 &&
!isReachableFromSurfaceNode)
{
WriteSimpleObjectFactory(builder, node, $"_c{Deref}CreateSurfaceBrush({surfaceInitializationText})");
}
else
{
WriteObjectFactoryStart(builder, node);
if (isReachableFromSurfaceNode)
{
case CompositionObject compositionObject:
WriteSetPropertyStatement(builder, "Surface", CallFactoryFromFor(node, compositionObject));
break;
case Wmd.LoadedImageSurface loadedImageSurface:
WriteSetPropertyStatement(builder, "Surface", NodeFor(loadedImageSurface).FieldName);
break;
default:
throw new InvalidOperationException();
// The Surface depends on the brush, so the brush needs to be created and assigned
// before the Surface.
WriteCreateAssignment(builder, node, $"_c{Deref}CreateSurfaceBrush()");
WriteSetPropertyStatement(builder, "Surface", surfaceInitializationText);
}
else
{
WriteCreateAssignment(builder, node, $"_c{Deref}CreateSurfaceBrush({surfaceInitializationText})");
}
InitializeCompositionBrush(builder, obj, node);
StartAnimationsOnResult(builder, obj, node);
WriteObjectFactoryEnd(builder);
}
StartAnimationsOnResult(builder, obj, node);
WriteObjectFactoryEnd(builder);
return true;
}