diff --git a/source/UIData/Tools/Graph.cs b/source/UIData/Tools/Graph.cs
index 234752b..c8d7bde 100644
--- a/source/UIData/Tools/Graph.cs
+++ b/source/UIData/Tools/Graph.cs
@@ -51,6 +51,39 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.UIData.Tools
///
public int Position { get; private set; }
+ ///
+ /// Returns True iff this node is reachable from the given node.
+ ///
+ /// The node to test.
+ /// True if this node is reachable from the given node.
+ public bool IsReachableFrom(Node node) => node is null ? false : IsReachableFrom(node, new HashSet>());
+
+ bool IsReachableFrom(Node targetNode, HashSet> 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
{
///
diff --git a/source/UIDataCodeGen/CodeGen/InstantiatorGeneratorBase.cs b/source/UIDataCodeGen/CodeGen/InstantiatorGeneratorBase.cs
index 29d7d36..6b45bf2 100644
--- a/source/UIDataCodeGen/CodeGen/InstantiatorGeneratorBase.cs
+++ b/source/UIDataCodeGen/CodeGen/InstantiatorGeneratorBase.cs
@@ -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;
}