Jelajahi Sumber

Added some docs.

And a few missing child scene properties.
Steven Kirk 8 tahun lalu
induk
melakukan
be20562426

+ 38 - 0
src/Avalonia.Visuals/Rendering/DeferredRenderer.cs

@@ -14,6 +14,10 @@ using System.Threading;
 
 namespace Avalonia.Rendering
 {
+    /// <summary>
+    /// A renderer which renders the state of the visual tree to an intermediate scene graph
+    /// representation which is then rendered on a rendering thread.
+    /// </summary>
     public class DeferredRenderer : RendererBase, IRenderer, IVisualBrushRenderer
     {
         private readonly IDispatcher _dispatcher;
@@ -33,6 +37,14 @@ namespace Avalonia.Rendering
         private DisplayDirtyRects _dirtyRectsDisplay = new DisplayDirtyRects();
         private IDrawOperation _currentDraw;
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DeferredRenderer"/> class.
+        /// </summary>
+        /// <param name="root">The control to render.</param>
+        /// <param name="renderLoop">The render loop.</param>
+        /// <param name="sceneBuilder">The scene builder to use. Optional.</param>
+        /// <param name="layerFactory">The layer factory to use. Optional.</param>
+        /// <param name="dispatcher">The dispatcher to use. Optional.</param>
         public DeferredRenderer(
             IRenderRoot root,
             IRenderLoop renderLoop,
@@ -56,6 +68,16 @@ namespace Avalonia.Rendering
             }
         }
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DeferredRenderer"/> class.
+        /// </summary>
+        /// <param name="root">The control to render.</param>
+        /// <param name="renderTarget">The render target.</param>
+        /// <param name="sceneBuilder">The scene builder to use. Optional.</param>
+        /// <param name="layerFactory">The layer factory to use. Optional.</param>
+        /// <remarks>
+        /// This constructor is intended to be used for unit testing.
+        /// </remarks>
         public DeferredRenderer(
             IVisual root,
             IRenderTarget renderTarget,
@@ -73,15 +95,26 @@ namespace Avalonia.Rendering
             _layers = new RenderLayers(_layerFactory);
         }
 
+        /// <inheritdoc/>
         public bool DrawFps { get; set; }
+
+        /// <inheritdoc/>
         public bool DrawDirtyRects { get; set; }
+
+        /// <summary>
+        /// Gets or sets a path to which rendered frame should be rendered for debugging.
+        /// </summary>
         public string DebugFramesPath { get; set; }
 
+        /// <inheritdoc/>
         public void AddDirty(IVisual visual)
         {
             _dirty?.Add(visual);
         }
 
+        /// <summary>
+        /// Disposes of the renderer and detaches from the render loop.
+        /// </summary>
         public void Dispose()
         {
             if (_renderLoop != null)
@@ -90,6 +123,7 @@ namespace Avalonia.Rendering
             }
         }
 
+        /// <inheritdoc/>
         public IEnumerable<IVisual> HitTest(Point p, Func<IVisual, bool> filter)
         {
             if (_renderLoop == null && (_dirty == null || _dirty.Count > 0))
@@ -101,19 +135,23 @@ namespace Avalonia.Rendering
             return _scene.HitTest(p, filter);
         }
 
+        /// <inheritdoc/>
         public void Paint(Rect rect)
         {
         }
 
+        /// <inheritdoc/>
         public void Resized(Size size)
         {
         }
 
+        /// <inheritdoc/>
         Size IVisualBrushRenderer.GetRenderTargetSize(IVisualBrush brush)
         {
             return (_currentDraw as BrushDrawOperation)?.ChildScenes?[brush.Visual]?.Size ?? Size.Empty;
         }
 
+        /// <inheritdoc/>
         void IVisualBrushRenderer.RenderVisualBrush(IDrawingContextImpl context, IVisualBrush brush)
         {
             var childScene = (_currentDraw as BrushDrawOperation)?.ChildScenes?[brush.Visual];

+ 25 - 1
src/Avalonia.Visuals/Rendering/SceneGraph/BrushDrawOperation.cs

@@ -1,4 +1,7 @@
-using System;
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
 using System.Collections.Generic;
 using Avalonia.Media;
 using Avalonia.Platform;
@@ -6,19 +9,40 @@ using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.SceneGraph
 {
+    /// <summary>
+    /// Base class for draw operations that can use a brush.
+    /// </summary>
     internal abstract class BrushDrawOperation : IDrawOperation
     {
+        /// <inheritdoc/>
         public abstract Rect Bounds { get; }
+
+        /// <inheritdoc/>
         public abstract bool HitTest(Point p);
+
+        /// <summary>
+        /// Gets a collection of child scenes that are needed to draw visual brushes.
+        /// </summary>
         public abstract IDictionary<IVisual, Scene> ChildScenes { get; }
 
+        /// <inheritdoc/>
         public abstract void Render(IDrawingContextImpl context);
 
+        /// <summary>
+        /// Converts a possibly mutable brush to an immutable brush.
+        /// </summary>
+        /// <param name="brush">The brush.</param>
+        /// <returns>An immutable brush</returns>
         protected IBrush ToImmutable(IBrush brush)
         {
             return (brush as IMutableBrush)?.ToImmutable() ?? brush;
         }
 
+        /// <summary>
+        /// Converts pen with a possibly mutable brush to a pen with an immutable brush.
+        /// </summary>
+        /// <param name="pen">The pen.</param>
+        /// <returns>A pen with an immutable brush</returns>
         protected Pen ToImmutable(Pen pen)
         {
             var brush = pen?.Brush != null ? ToImmutable(pen.Brush) : null;

+ 49 - 2
src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs

@@ -9,6 +9,9 @@ using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.SceneGraph
 {
+    /// <summary>
+    /// A drawing context which builds a scene graph.
+    /// </summary>
     internal class DeferredDrawingContextImpl : IDrawingContextImpl
     {
         private readonly ISceneBuilder _sceneBuilder;
@@ -16,16 +19,34 @@ namespace Avalonia.Rendering.SceneGraph
         private int _childIndex;
         private int _drawOperationindex;
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DeferredDrawingContextImpl"/> class.
+        /// </summary>
+        /// <param name="sceneBuilder">
+        /// A scene builder used for constructing child scenes for visual brushes.
+        /// </param>
+        /// <param name="layers">The scene layers.</param>
         public DeferredDrawingContextImpl(ISceneBuilder sceneBuilder, SceneLayers layers)
         {
             _sceneBuilder = sceneBuilder;
             Layers = layers;
         }
 
+        /// <inheritdoc/>
         public Matrix Transform { get; set; } = Matrix.Identity;
 
+        /// <summary>
+        /// Gets the layers in the scene being built.
+        /// </summary>
         public SceneLayers Layers { get; }
 
+        /// <summary>
+        /// Informs the drawing context of the visual node that is about to be rendered.
+        /// </summary>
+        /// <param name="node">The visual node.</param>
+        /// <returns>
+        /// An object which when disposed will commit the changes to visual node.
+        /// </returns>
         public UpdateState BeginUpdate(VisualNode node)
         {
             Contract.Requires<ArgumentNullException>(node != null);
@@ -50,21 +71,33 @@ namespace Avalonia.Rendering.SceneGraph
             return state;
         }
 
+        /// <inheritdoc/>
         public void Clear(Color color)
         {
             // Cannot clear a deferred scene.
         }
 
+        /// <inheritdoc/>
         public void Dispose()
         {
             // Nothing to do here as we allocate no unmanaged resources.
         }
 
+        /// <summary>
+        /// Removes any remaining drawing operations from the visual node.
+        /// </summary>
+        /// <remarks>
+        /// Drawing operations are updated in place, overwriting existing drawing operations if
+        /// they are different. Once drawing has completed for the current visual node, it is
+        /// possible that there are stale drawing operations at the end of the list. This method
+        /// trims these stale drawing operations.
+        /// </remarks>
         public void TrimChildren()
         {
             _node.TrimChildren(_childIndex);
         }
 
+        /// <inheritdoc/>
         public void DrawGeometry(IBrush brush, Pen pen, IGeometryImpl geometry)
         {
             var next = NextDrawAs<GeometryNode>();
@@ -79,6 +112,7 @@ namespace Avalonia.Rendering.SceneGraph
             }
         }
 
+        /// <inheritdoc/>
         public void DrawImage(IBitmapImpl source, double opacity, Rect sourceRect, Rect destRect)
         {
             var next = NextDrawAs<ImageNode>();
@@ -93,18 +127,20 @@ namespace Avalonia.Rendering.SceneGraph
             }
         }
 
+        /// <inheritdoc/>
         public void DrawImage(IBitmapImpl source, IBrush opacityMask, Rect opacityMaskRect, Rect sourceRect)
         {
             throw new NotImplementedException();
         }
 
+        /// <inheritdoc/>
         public void DrawLine(Pen pen, Point p1, Point p2)
         {
             var next = NextDrawAs<LineNode>();
 
             if (next == null || !next.Equals(Transform, pen, p1, p2))
             {
-                Add(new LineNode(Transform, pen, p1, p2));
+                Add(new LineNode(Transform, pen, p1, p2, CreateChildScene(pen.Brush)));
             }
             else
             {
@@ -112,6 +148,7 @@ namespace Avalonia.Rendering.SceneGraph
             }
         }
 
+        /// <inheritdoc/>
         public void DrawRectangle(Pen pen, Rect rect, float cornerRadius = 0)
         {
             var next = NextDrawAs<RectangleNode>();
@@ -126,13 +163,14 @@ namespace Avalonia.Rendering.SceneGraph
             }
         }
 
+        /// <inheritdoc/>
         public void DrawText(IBrush foreground, Point origin, IFormattedTextImpl text)
         {
             var next = NextDrawAs<TextNode>();
 
             if (next == null || !next.Equals(Transform, foreground, origin, text))
             {
-                Add(new TextNode(Transform, foreground, origin, text));
+                Add(new TextNode(Transform, foreground, origin, text, CreateChildScene(foreground)));
             }
             else
             {
@@ -140,6 +178,7 @@ namespace Avalonia.Rendering.SceneGraph
             }
         }
 
+        /// <inheritdoc/>
         public void FillRectangle(IBrush brush, Rect rect, float cornerRadius = 0)
         {
             var next = NextDrawAs<RectangleNode>();
@@ -154,41 +193,49 @@ namespace Avalonia.Rendering.SceneGraph
             }
         }
 
+        /// <inheritdoc/>
         public void PopClip()
         {
             // TODO: Implement
         }
 
+        /// <inheritdoc/>
         public void PopGeometryClip()
         {
             // TODO: Implement
         }
 
+        /// <inheritdoc/>
         public void PopOpacity()
         {
             // TODO: Implement
         }
 
+        /// <inheritdoc/>
         public void PopOpacityMask()
         {
             // TODO: Implement
         }
 
+        /// <inheritdoc/>
         public void PushClip(Rect clip)
         {
             // TODO: Implement
         }
 
+        /// <inheritdoc/>
         public void PushGeometryClip(IGeometryImpl clip)
         {
             // TODO: Implement
         }
 
+        /// <inheritdoc/>
         public void PushOpacity(double opacity)
         {
             // TODO: Implement
         }
 
+        /// <inheritdoc/>
         public void PushOpacityMask(IBrush mask, Rect bounds)
         {
             // TODO: Implement

+ 44 - 0
src/Avalonia.Visuals/Rendering/SceneGraph/GeometryNode.cs

@@ -9,8 +9,19 @@ using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.SceneGraph
 {
+    /// <summary>
+    /// A node in the scene graph which represents a geometry draw.
+    /// </summary>
     internal class GeometryNode : BrushDrawOperation
     {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="GeometryNode"/> class.
+        /// </summary>
+        /// <param name="transform">The transform.</param>
+        /// <param name="brush">The fill brush.</param>
+        /// <param name="pen">The stroke pen.</param>
+        /// <param name="geometry">The geometry.</param>
+        /// <param name="childScenes">Child scenes for drawing visual brushes.</param>
         public GeometryNode(
             Matrix transform,
             IBrush brush,
@@ -26,13 +37,44 @@ namespace Avalonia.Rendering.SceneGraph
             ChildScenes = childScenes;
         }
 
+        /// <inheritdoc/>
         public override Rect Bounds { get; }
+
+        /// <summary>
+        /// Gets the transform with which the node will be drawn.
+        /// </summary>
         public Matrix Transform { get; }
+
+        /// <summary>
+        /// Gets the fill brush.
+        /// </summary>
         public IBrush Brush { get; }
+
+        /// <summary>
+        /// Gets the stroke pen.
+        /// </summary>
         public Pen Pen { get; }
+
+        /// <summary>
+        /// Gets the geometry to draw.
+        /// </summary>
         public IGeometryImpl Geometry { get; }
+
+        /// <inheritdoc/>
         public override IDictionary<IVisual, Scene> ChildScenes { get; }
 
+        /// <summary>
+        /// Determines if this draw operation equals another.
+        /// </summary>
+        /// <param name="transform">The transform of the other draw operation.</param>
+        /// <param name="brush">The fill of the other draw operation.</param>
+        /// <param name="pen">The stroke of the other draw operation.</param>
+        /// <param name="geometry">The geometry of the other draw operation.</param>
+        /// <returns>True if the draw operations are the same, otherwise false.</returns>
+        /// <remarks>
+        /// The properties of the other draw operation are passed in as arguments to prevent
+        /// allocation of a not-yet-constructed draw operation object.
+        /// </remarks>
         public bool Equals(Matrix transform, IBrush brush, Pen pen, IGeometryImpl geometry)
         {
             return transform == Transform &&
@@ -41,12 +83,14 @@ namespace Avalonia.Rendering.SceneGraph
                 Equals(geometry, Geometry);
         }
 
+        /// <inheritdoc/>
         public override void Render(IDrawingContextImpl context)
         {
             context.Transform = Transform;
             context.DrawGeometry(Brush, Pen, Geometry);
         }
 
+        /// <inheritdoc/>
         public override bool HitTest(Point p)
         {
             p *= Transform.Invert();

+ 15 - 1
src/Avalonia.Visuals/Rendering/SceneGraph/ISceneBuilder.cs

@@ -2,9 +2,23 @@
 
 namespace Avalonia.Rendering.SceneGraph
 {
+    /// <summary>
+    /// Builds a scene graph from a visual tree.
+    /// </summary>
     public interface ISceneBuilder
     {
-        bool Update(Scene scene, IVisual visual);
+        /// <summary>
+        /// Builds the initial scene graph for a visual tree.
+        /// </summary>
+        /// <param name="scene">The scene to build.</param>
         void UpdateAll(Scene scene);
+
+        /// <summary>
+        /// Updates the visual (and potentially its children) in a scene.
+        /// </summary>
+        /// <param name="scene">The scene.</param>
+        /// <param name="visual">The visual to update.</param>
+        /// <returns>True if changes were made, otherwise false.</returns>
+        bool Update(Scene scene, IVisual visual);
     }
 }

+ 47 - 3
src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs

@@ -2,14 +2,23 @@
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 using System;
-using System.Collections.Generic;
-using Avalonia.Media;
 using Avalonia.Platform;
 
 namespace Avalonia.Rendering.SceneGraph
 {
+    /// <summary>
+    /// A node in the scene graph which represents an image draw.
+    /// </summary>
     internal class ImageNode : IDrawOperation
     {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ImageNode"/> class.
+        /// </summary>
+        /// <param name="transform">The transform.</param>
+        /// <param name="source">The image to draw.</param>
+        /// <param name="opacity">The draw opacity.</param>
+        /// <param name="sourceRect">The source rect.</param>
+        /// <param name="destRect">The destination rect.</param>
         public ImageNode(Matrix transform, IBitmapImpl source, double opacity, Rect sourceRect, Rect destRect)
         {
             Bounds = destRect.TransformToAABB(transform);
@@ -20,14 +29,47 @@ namespace Avalonia.Rendering.SceneGraph
             DestRect = destRect;
         }
 
+        /// <inheritdoc/>
         public Rect Bounds { get; }
+
+        /// <summary>
+        /// Gets the transform with which the node will be drawn.
+        /// </summary>
         public Matrix Transform { get; }
+
+        /// <summary>
+        /// Gets the image to draw.
+        /// </summary>
         public IBitmapImpl Source { get; }
+
+        /// <summary>
+        /// Gets the draw opacity.
+        /// </summary>
         public double Opacity { get; }
+
+        /// <summary>
+        /// Gets the source rect.
+        /// </summary>
         public Rect SourceRect { get; }
+
+        /// <summary>
+        /// Gets the destination rect.
+        /// </summary>
         public Rect DestRect { get; }
-        public IDictionary<VisualBrush, Scene> ChildScenes => null;
 
+        /// <summary>
+        /// Determines if this draw operation equals another.
+        /// </summary>
+        /// <param name="transform">The transform of the other draw operation.</param>
+        /// <param name="source">The image of the other draw operation.</param>
+        /// <param name="opacity">The opacity of the other draw operation.</param>
+        /// <param name="sourceRect">The source rect of the other draw operation.</param>
+        /// <param name="destRect">The dest rect of the other draw operation.</param>
+        /// <returns>True if the draw operations are the same, otherwise false.</returns>
+        /// <remarks>
+        /// The properties of the other draw operation are passed in as arguments to prevent
+        /// allocation of a not-yet-constructed draw operation object.
+        /// </remarks>
         public bool Equals(Matrix transform, IBitmapImpl source, double opacity, Rect sourceRect, Rect destRect)
         {
             return transform == Transform &&
@@ -37,12 +79,14 @@ namespace Avalonia.Rendering.SceneGraph
                 destRect == DestRect;
         }
 
+        /// <inheritdoc/>
         public void Render(IDrawingContextImpl context)
         {
             context.Transform = Transform;
             context.DrawImage(Source, Opacity, SourceRect, DestRect);
         }
 
+        /// <inheritdoc/>
         public bool HitTest(Point p) => Bounds.Contains(p);
     }
 }

+ 50 - 2
src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs

@@ -9,24 +9,72 @@ using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.SceneGraph
 {
+    /// <summary>
+    /// A node in the scene graph which represents a line draw.
+    /// </summary>
     internal class LineNode : BrushDrawOperation
     {
-        public LineNode(Matrix transform, Pen pen, Point p1, Point p2)
+        /// <summary>
+        /// Initializes a new instance of the <see cref="GeometryNode"/> class.
+        /// </summary>
+        /// <param name="transform">The transform.</param>
+        /// <param name="pen">The stroke pen.</param>
+        /// <param name="p1">The start point of the line.</param>
+        /// <param name="p2">The end point of the line.</param>
+        /// <param name="childScenes">Child scenes for drawing visual brushes.</param>
+        public LineNode(
+            Matrix transform,
+            Pen pen,
+            Point p1,
+            Point p2,
+            IDictionary<IVisual, Scene> childScenes = null)
         {
             Bounds = new Rect(P1, P2);
             Transform = transform;
             Pen = ToImmutable(pen);
             P1 = p1;
             P2 = p2;
+            ChildScenes = childScenes;
         }
 
+        /// <inheritdoc/>
         public override Rect Bounds { get; }
+
+        /// <summary>
+        /// Gets the transform with which the node will be drawn.
+        /// </summary>
         public Matrix Transform { get; }
+
+        /// <summary>
+        /// Gets the stroke pen.
+        /// </summary>
         public Pen Pen { get; }
+
+        /// <summary>
+        /// Gets the start point of the line.
+        /// </summary>
         public Point P1 { get; }
+
+        /// <summary>
+        /// Gets the end point of the line.
+        /// </summary>
         public Point P2 { get; }
-        public override IDictionary<IVisual, Scene> ChildScenes => null;
 
+        /// <inheritdoc/>
+        public override IDictionary<IVisual, Scene> ChildScenes { get; }
+
+        /// <summary>
+        /// Determines if this draw operation equals another.
+        /// </summary>
+        /// <param name="transform">The transform of the other draw operation.</param>
+        /// <param name="pen">The stroke of the other draw operation.</param>
+        /// <param name="p1">The start point of the other draw operation.</param>
+        /// <param name="p2">The end point of the other draw operation.</param>
+        /// <returns>True if the draw operations are the same, otherwise false.</returns>
+        /// <remarks>
+        /// The properties of the other draw operation are passed in as arguments to prevent
+        /// allocation of a not-yet-constructed draw operation object.
+        /// </remarks>
         public bool Equals(Matrix transform, Pen pen, Point p1, Point p2)
         {
             return transform == Transform && pen == Pen && p1 == P1 && p2 == P2;

+ 50 - 0
src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs

@@ -9,8 +9,20 @@ using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.SceneGraph
 {
+    /// <summary>
+    /// A node in the scene graph which represents a rectangle draw.
+    /// </summary>
     internal class RectangleNode : BrushDrawOperation
     {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="RectangleNode"/> class.
+        /// </summary>
+        /// <param name="transform">The transform.</param>
+        /// <param name="brush">The fill brush.</param>
+        /// <param name="pen">The stroke pen.</param>
+        /// <param name="rect">The rectanle to draw.</param>
+        /// <param name="cornerRadius">The rectangle corner radius.</param>
+        /// <param name="childScenes">Child scenes for drawing visual brushes.</param>
         public RectangleNode(
             Matrix transform,
             IBrush brush,
@@ -28,14 +40,50 @@ namespace Avalonia.Rendering.SceneGraph
             ChildScenes = childScenes;
         }
 
+        /// <inheritdoc/>
         public override Rect Bounds { get; }
+
+        /// <summary>
+        /// Gets the transform with which the node will be drawn.
+        /// </summary>
         public Matrix Transform { get; }
+
+        /// <summary>
+        /// Gets the fill brush.
+        /// </summary>
         public IBrush Brush { get; }
+
+        /// <summary>
+        /// Gets the stroke pen.
+        /// </summary>
         public Pen Pen { get; }
+
+        /// <summary>
+        /// Gets the rectangle to draw.
+        /// </summary>
         public Rect Rect { get; }
+
+        /// <summary>
+        /// Gets the rectangle corner radius.
+        /// </summary>
         public float CornerRadius { get; }
+
+        /// <inheritdoc/>
         public override IDictionary<IVisual, Scene> ChildScenes { get; }
 
+        /// <summary>
+        /// Determines if this draw operation equals another.
+        /// </summary>
+        /// <param name="transform">The transform of the other draw operation.</param>
+        /// <param name="brush">The fill of the other draw operation.</param>
+        /// <param name="pen">The stroke of the other draw operation.</param>
+        /// <param name="rect">The rectangle of the other draw operation.</param>
+        /// <param name="cornerRadius">The rectangle corner radius of the other draw operation.</param>
+        /// <returns>True if the draw operations are the same, otherwise false.</returns>
+        /// <remarks>
+        /// The properties of the other draw operation are passed in as arguments to prevent
+        /// allocation of a not-yet-constructed draw operation object.
+        /// </remarks>
         public bool Equals(Matrix transform, IBrush brush, Pen pen, Rect rect, float cornerRadius)
         {
             return transform == Transform &&
@@ -45,6 +93,7 @@ namespace Avalonia.Rendering.SceneGraph
                 cornerRadius == CornerRadius;
         }
 
+        /// <inheritdoc/>
         public override void Render(IDrawingContextImpl context)
         {
             context.Transform = Transform;
@@ -60,6 +109,7 @@ namespace Avalonia.Rendering.SceneGraph
             }
         }
 
+        /// <inheritdoc/>
         public override bool HitTest(Point p) => Bounds.Contains(p);
     }
 }

+ 52 - 2
src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs

@@ -3,15 +3,21 @@
 
 using System;
 using System.Collections.Generic;
-using Avalonia;
 using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.SceneGraph
 {
+    /// <summary>
+    /// Represents a scene graph used by the <see cref="DeferredRenderer"/>.
+    /// </summary>
     public class Scene
     {
         private Dictionary<IVisual, IVisualNode> _index;
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Scene"/> class.
+        /// </summary>
+        /// <param name="rootVisual">The root visual to draw.</param>
         public Scene(IVisual rootVisual)
             : this(
                 new VisualNode(rootVisual, null),
@@ -22,7 +28,7 @@ namespace Avalonia.Rendering.SceneGraph
             _index.Add(rootVisual, Root);
         }
 
-        internal Scene(VisualNode root, Dictionary<IVisual, IVisualNode> index, SceneLayers layers, int id)
+        private Scene(VisualNode root, Dictionary<IVisual, IVisualNode> index, SceneLayers layers, int id)
         {
             Contract.Requires<ArgumentNullException>(root != null);
 
@@ -35,12 +41,35 @@ namespace Avalonia.Rendering.SceneGraph
             root.LayerRoot = root.Visual;
         }
 
+        /// <summary>
+        /// Gets an ID identifying the scene. This is incremented each time the scene is cloned.
+        /// </summary>
         public int Id { get; }
+
+        /// <summary>
+        /// Gets the layers for the scene.
+        /// </summary>
         public SceneLayers Layers { get; }
+
+        /// <summary>
+        /// Gets the root node of the scene graph.
+        /// </summary>
         public IVisualNode Root { get; }
+
+        /// <summary>
+        /// Gets or sets the size of the scene in device independent pixels.
+        /// </summary>
         public Size Size { get; set; }
+
+        /// <summary>
+        /// Gets or sets the scene scaling.
+        /// </summary>
         public double Scaling { get; set; } = 1;
 
+        /// <summary>
+        /// Adds a node to the scene index.
+        /// </summary>
+        /// <param name="node">The node.</param>
         public void Add(IVisualNode node)
         {
             Contract.Requires<ArgumentNullException>(node != null);
@@ -48,6 +77,10 @@ namespace Avalonia.Rendering.SceneGraph
             _index.Add(node.Visual, node);
         }
 
+        /// <summary>
+        /// Clones the scene.
+        /// </summary>
+        /// <returns>The cloned scene.</returns>
         public Scene Clone()
         {
             var index = new Dictionary<IVisual, IVisualNode>();
@@ -62,6 +95,13 @@ namespace Avalonia.Rendering.SceneGraph
             return result;
         }
 
+        /// <summary>
+        /// Tries to find a node in the scene graph representing the specified visual.
+        /// </summary>
+        /// <param name="visual">The visual.</param>
+        /// <returns>
+        /// The node representing the visual or null if it could not be found.
+        /// </returns>
         public IVisualNode FindNode(IVisual visual)
         {
             IVisualNode node;
@@ -69,11 +109,21 @@ namespace Avalonia.Rendering.SceneGraph
             return node;
         }
 
+        /// <summary>
+        /// Gets the visuals at a point in the scene.
+        /// </summary>
+        /// <param name="p">The point.</param>
+        /// <param name="filter">A filter. May be null.</param>
+        /// <returns>The visuals at the specified point.</returns>
         public IEnumerable<IVisual> HitTest(Point p, Func<IVisual, bool> filter)
         {
             return HitTest(Root, p, null, filter);
         }
 
+        /// <summary>
+        /// Removes a node from the scene index.
+        /// </summary>
+        /// <param name="node">The node.</param>
         public void Remove(IVisualNode node)
         {
             Contract.Requires<ArgumentNullException>(node != null);

+ 5 - 0
src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs

@@ -10,8 +10,12 @@ using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.SceneGraph
 {
+    /// <summary>
+    /// Builds a scene graph from a visual tree.
+    /// </summary>
     public class SceneBuilder : ISceneBuilder
     {
+        /// <inheritdoc/>
         public void UpdateAll(Scene scene)
         {
             Contract.Requires<ArgumentNullException>(scene != null);
@@ -27,6 +31,7 @@ namespace Avalonia.Rendering.SceneGraph
             }
         }
 
+        /// <inheritdoc/>
         public bool Update(Scene scene, IVisual visual)
         {
             Contract.Requires<ArgumentNullException>(scene != null);

+ 39 - 0
src/Avalonia.Visuals/Rendering/SceneGraph/SceneLayer.cs

@@ -5,8 +5,16 @@ using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.SceneGraph
 {
+    /// <summary>
+    /// Represents a layer in a <see cref="Scene"/>.
+    /// </summary>
     public class SceneLayer
     {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="SceneLayer"/> class.
+        /// </summary>
+        /// <param name="layerRoot">The visual at the root of the layer.</param>
+        /// <param name="distanceFromRoot">The distance from the scene root.</param>
         public SceneLayer(IVisual layerRoot, int distanceFromRoot)
         {
             LayerRoot = layerRoot;
@@ -14,6 +22,10 @@ namespace Avalonia.Rendering.SceneGraph
             DistanceFromRoot = distanceFromRoot;
         }
 
+        /// <summary>
+        /// Clones the layer.
+        /// </summary>
+        /// <returns>The cloned layer.</returns>
         public SceneLayer Clone()
         {
             return new SceneLayer(LayerRoot, DistanceFromRoot)
@@ -25,12 +37,39 @@ namespace Avalonia.Rendering.SceneGraph
             };
         }
 
+        /// <summary>
+        /// Gets the visual at the root of the layer.
+        /// </summary>
         public IVisual LayerRoot { get; }
+
+        /// <summary>
+        /// Gets the dirty rectangles for the layer.
+        /// </summary>
         public DirtyRects Dirty { get; }
+
+        /// <summary>
+        /// Gets the distance of the layer root from the root of the scene.
+        /// </summary>
         public int DistanceFromRoot { get; }
+
+        /// <summary>
+        /// Gets or sets the opacity of the layer.
+        /// </summary>
         public double Opacity { get; set; } = 1;
+
+        /// <summary>
+        /// Gets or sets the opacity mask for the layer.
+        /// </summary>
         public IBrush OpacityMask { get; set; }
+
+        /// <summary>
+        /// Gets or sets the target rectangle for the layer opacity mask.
+        /// </summary>
         public Rect OpacityMaskRect { get; set; }
+
+        /// <summary>
+        /// Gets the layer's geometry clip.
+        /// </summary>
         public IGeometryImpl GeometryClip { get; set; }
     }
 }

+ 63 - 0
src/Avalonia.Visuals/Rendering/SceneGraph/SceneLayers.cs

@@ -5,19 +5,32 @@ using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.SceneGraph
 {
+    /// <summary>
+    /// Holds a collection of layers for a <see cref="Scene"/>.
+    /// </summary>
     public class SceneLayers : IEnumerable<SceneLayer>
     {
         private readonly IVisual _root;
         private readonly List<SceneLayer> _inner = new List<SceneLayer>();
         private readonly Dictionary<IVisual, SceneLayer> _index = new Dictionary<IVisual, SceneLayer>();
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="SceneLayers"/> class.
+        /// </summary>
+        /// <param name="root">The scene's root visual.</param>
         public SceneLayers(IVisual root)
         {
             _root = root;
         }
 
+        /// <summary>
+        /// Gets the number of layers in the scene.
+        /// </summary>
         public int Count => _inner.Count;
 
+        /// <summary>
+        /// Gets a value indicating whether any of the layers have a dirty region.
+        /// </summary>
         public bool HasDirty
         {
             get
@@ -34,9 +47,25 @@ namespace Avalonia.Rendering.SceneGraph
             }
         }
 
+        /// <summary>
+        /// Gets a layer by index.
+        /// </summary>
+        /// <param name="index">The index of the layer.</param>
+        /// <returns>The layer.</returns>
         public SceneLayer this[int index] => _inner[index];
+
+        /// <summary>
+        /// Gets a layer by its root visual.
+        /// </summary>
+        /// <param name="visual">The layer's root visual.</param>
+        /// <returns>The layer.</returns>
         public SceneLayer this[IVisual visual] => _index[visual];
 
+        /// <summary>
+        /// Adds a layer to the scene.
+        /// </summary>
+        /// <param name="layerRoot">The root visual of the layer.</param>
+        /// <returns>The created layer.</returns>
         public SceneLayer Add(IVisual layerRoot)
         {
             Contract.Requires<ArgumentNullException>(layerRoot != null);
@@ -49,6 +78,10 @@ namespace Avalonia.Rendering.SceneGraph
             return layer;
         }
 
+        /// <summary>
+        /// Makes a deep clone of the layers.
+        /// </summary>
+        /// <returns>The cloned layers.</returns>
         public SceneLayers Clone()
         {
             var result = new SceneLayers(_root);
@@ -63,6 +96,13 @@ namespace Avalonia.Rendering.SceneGraph
             return result;
         }
 
+        /// <summary>
+        /// Tests whether a layer exists with the specified root visual.
+        /// </summary>
+        /// <param name="layerRoot">The root visual.</param>
+        /// <returns>
+        /// True if a layer exists with the specified root visual, otherwise false.
+        /// </returns>
         public bool Exists(IVisual layerRoot)
         {
             Contract.Requires<ArgumentNullException>(layerRoot != null);
@@ -70,6 +110,11 @@ namespace Avalonia.Rendering.SceneGraph
             return _index.ContainsKey(layerRoot);
         }
 
+        /// <summary>
+        /// Tries to find a layer with the specified root visual.
+        /// </summary>
+        /// <param name="layerRoot">The root visual.</param>
+        /// <returns>The layer if found, otherwise null.</returns>
         public SceneLayer Find(IVisual layerRoot)
         {
             SceneLayer result;
@@ -77,6 +122,11 @@ namespace Avalonia.Rendering.SceneGraph
             return result;
         }
 
+        /// <summary>
+        /// Gets an existing layer or creates a new one if no existing layer is found.
+        /// </summary>
+        /// <param name="layerRoot">The root visual.</param>
+        /// <returns>The layer.</returns>
         public SceneLayer GetOrAdd(IVisual layerRoot)
         {
             Contract.Requires<ArgumentNullException>(layerRoot != null);
@@ -91,6 +141,11 @@ namespace Avalonia.Rendering.SceneGraph
             return result;
         }
 
+        /// <summary>
+        /// Removes a layer from the scene.
+        /// </summary>
+        /// <param name="layerRoot">The root visual.</param>
+        /// <returns>True if a matching layer was removed, otherwise false.</returns>
         public bool Remove(IVisual layerRoot)
         {
             Contract.Requires<ArgumentNullException>(layerRoot != null);
@@ -105,6 +160,11 @@ namespace Avalonia.Rendering.SceneGraph
             return layer != null;
         }
 
+        /// <summary>
+        /// Removes a layer from the scene.
+        /// </summary>
+        /// <param name="layer">The layer.</param>
+        /// <returns>True if the layer was part of the scene, otherwise false.</returns>
         public bool Remove(SceneLayer layer)
         {
             Contract.Requires<ArgumentNullException>(layer != null);
@@ -113,7 +173,10 @@ namespace Avalonia.Rendering.SceneGraph
             return _inner.Remove(layer);
         }
 
+        /// <inheritdoc/>
         public IEnumerator<SceneLayer> GetEnumerator() => _inner.GetEnumerator();
+
+        /// <inheritdoc/>
         IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 
         private int FindInsertIndex(SceneLayer insert)

+ 52 - 2
src/Avalonia.Visuals/Rendering/SceneGraph/TextNode.cs

@@ -9,30 +9,79 @@ using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.SceneGraph
 {
+    /// <summary>
+    /// A node in the scene graph which represents a text draw.
+    /// </summary>
     internal class TextNode : BrushDrawOperation
     {
-        public TextNode(Matrix transform, IBrush foreground, Point origin, IFormattedTextImpl text)
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TextNode"/> class.
+        /// </summary>
+        /// <param name="transform">The transform.</param>
+        /// <param name="foreground">The foreground brush.</param>
+        /// <param name="origin">The draw origin.</param>
+        /// <param name="text">The text to draw.</param>
+        /// <param name="childScenes">Child scenes for drawing visual brushes.</param>
+        public TextNode(
+            Matrix transform,
+            IBrush foreground,
+            Point origin,
+            IFormattedTextImpl text,
+            IDictionary<IVisual, Scene> childScenes = null)
         {
             Bounds = new Rect(origin, text.Size).TransformToAABB(transform);
             Transform = transform;
             Foreground = ToImmutable(foreground);
             Origin = origin;
             Text = text;
+            ChildScenes = childScenes;
         }
 
+        /// <inheritdoc/>
         public override Rect Bounds { get; }
+
+        /// <summary>
+        /// Gets the transform with which the node will be drawn.
+        /// </summary>
         public Matrix Transform { get; }
+
+        /// <summary>
+        /// Gets the foreground brush.
+        /// </summary>
         public IBrush Foreground { get; }
+
+        /// <summary>
+        /// Gets the draw origin.
+        /// </summary>
         public Point Origin { get; }
+
+        /// <summary>
+        /// Gets the text to draw.
+        /// </summary>
         public IFormattedTextImpl Text { get; }
-        public override IDictionary<IVisual, Scene> ChildScenes => null;
 
+        /// <inheritdoc/>
+        public override IDictionary<IVisual, Scene> ChildScenes { get; }
+
+        /// <inheritdoc/>
         public override void Render(IDrawingContextImpl context)
         {
             context.Transform = Transform;
             context.DrawText(Foreground, Origin, Text);
         }
 
+        /// <summary>
+        /// Determines if this draw operation equals another.
+        /// </summary>
+        /// <param name="transform">The transform of the other draw operation.</param>
+        /// <param name="foreground">The foregroundof the other draw operation.</param>
+        /// <param name="origin">The draw origin of the other draw operation.</param>
+        /// <param name="text">The text of the other draw operation.</param>
+        /// <returns>True if the draw operations are the same, otherwise false.</returns>
+        /// <remarks>
+        /// The properties of the other draw operation are passed in as arguments to prevent
+        /// allocation of a not-yet-constructed draw operation object.
+        /// </remarks>
         internal bool Equals(Matrix transform, IBrush foreground, Point origin, IFormattedTextImpl text)
         {
             return transform == Transform &&
@@ -41,6 +90,7 @@ namespace Avalonia.Rendering.SceneGraph
                 Equals(text, Text);
         }
 
+        /// <inheritdoc/>
         public override bool HitTest(Point p) => Bounds.Contains(p);
     }
 }