diff --git a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs index a30f02fc42..a93f730c0d 100644 --- a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs @@ -14,6 +14,10 @@ using System.Threading; namespace Avalonia.Rendering { + /// + /// A renderer which renders the state of the visual tree to an intermediate scene graph + /// representation which is then rendered on a rendering thread. + /// 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; + /// + /// Initializes a new instance of the class. + /// + /// The control to render. + /// The render loop. + /// The scene builder to use. Optional. + /// The layer factory to use. Optional. + /// The dispatcher to use. Optional. public DeferredRenderer( IRenderRoot root, IRenderLoop renderLoop, @@ -56,6 +68,16 @@ namespace Avalonia.Rendering } } + /// + /// Initializes a new instance of the class. + /// + /// The control to render. + /// The render target. + /// The scene builder to use. Optional. + /// The layer factory to use. Optional. + /// + /// This constructor is intended to be used for unit testing. + /// public DeferredRenderer( IVisual root, IRenderTarget renderTarget, @@ -73,15 +95,26 @@ namespace Avalonia.Rendering _layers = new RenderLayers(_layerFactory); } + /// public bool DrawFps { get; set; } + + /// public bool DrawDirtyRects { get; set; } + + /// + /// Gets or sets a path to which rendered frame should be rendered for debugging. + /// public string DebugFramesPath { get; set; } + /// public void AddDirty(IVisual visual) { _dirty?.Add(visual); } + /// + /// Disposes of the renderer and detaches from the render loop. + /// public void Dispose() { if (_renderLoop != null) @@ -90,6 +123,7 @@ namespace Avalonia.Rendering } } + /// public IEnumerable HitTest(Point p, Func filter) { if (_renderLoop == null && (_dirty == null || _dirty.Count > 0)) @@ -101,19 +135,23 @@ namespace Avalonia.Rendering return _scene.HitTest(p, filter); } + /// public void Paint(Rect rect) { } + /// public void Resized(Size size) { } + /// Size IVisualBrushRenderer.GetRenderTargetSize(IVisualBrush brush) { return (_currentDraw as BrushDrawOperation)?.ChildScenes?[brush.Visual]?.Size ?? Size.Empty; } + /// void IVisualBrushRenderer.RenderVisualBrush(IDrawingContextImpl context, IVisualBrush brush) { var childScene = (_currentDraw as BrushDrawOperation)?.ChildScenes?[brush.Visual]; diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/BrushDrawOperation.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/BrushDrawOperation.cs index 7c65cf5445..3b858f7b38 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/BrushDrawOperation.cs +++ b/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 { + /// + /// Base class for draw operations that can use a brush. + /// internal abstract class BrushDrawOperation : IDrawOperation { + /// public abstract Rect Bounds { get; } + + /// public abstract bool HitTest(Point p); + + /// + /// Gets a collection of child scenes that are needed to draw visual brushes. + /// public abstract IDictionary ChildScenes { get; } + /// public abstract void Render(IDrawingContextImpl context); + /// + /// Converts a possibly mutable brush to an immutable brush. + /// + /// The brush. + /// An immutable brush protected IBrush ToImmutable(IBrush brush) { return (brush as IMutableBrush)?.ToImmutable() ?? brush; } + /// + /// Converts pen with a possibly mutable brush to a pen with an immutable brush. + /// + /// The pen. + /// A pen with an immutable brush protected Pen ToImmutable(Pen pen) { var brush = pen?.Brush != null ? ToImmutable(pen.Brush) : null; diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs index 03a4929808..48bba84da7 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs @@ -9,6 +9,9 @@ using Avalonia.VisualTree; namespace Avalonia.Rendering.SceneGraph { + /// + /// A drawing context which builds a scene graph. + /// internal class DeferredDrawingContextImpl : IDrawingContextImpl { private readonly ISceneBuilder _sceneBuilder; @@ -16,16 +19,34 @@ namespace Avalonia.Rendering.SceneGraph private int _childIndex; private int _drawOperationindex; + /// + /// Initializes a new instance of the class. + /// + /// + /// A scene builder used for constructing child scenes for visual brushes. + /// + /// The scene layers. public DeferredDrawingContextImpl(ISceneBuilder sceneBuilder, SceneLayers layers) { _sceneBuilder = sceneBuilder; Layers = layers; } + /// public Matrix Transform { get; set; } = Matrix.Identity; + /// + /// Gets the layers in the scene being built. + /// public SceneLayers Layers { get; } + /// + /// Informs the drawing context of the visual node that is about to be rendered. + /// + /// The visual node. + /// + /// An object which when disposed will commit the changes to visual node. + /// public UpdateState BeginUpdate(VisualNode node) { Contract.Requires(node != null); @@ -50,21 +71,33 @@ namespace Avalonia.Rendering.SceneGraph return state; } + /// public void Clear(Color color) { // Cannot clear a deferred scene. } + /// public void Dispose() { // Nothing to do here as we allocate no unmanaged resources. } + /// + /// Removes any remaining drawing operations from the visual node. + /// + /// + /// 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. + /// public void TrimChildren() { _node.TrimChildren(_childIndex); } + /// public void DrawGeometry(IBrush brush, Pen pen, IGeometryImpl geometry) { var next = NextDrawAs(); @@ -79,6 +112,7 @@ namespace Avalonia.Rendering.SceneGraph } } + /// public void DrawImage(IBitmapImpl source, double opacity, Rect sourceRect, Rect destRect) { var next = NextDrawAs(); @@ -93,18 +127,20 @@ namespace Avalonia.Rendering.SceneGraph } } + /// public void DrawImage(IBitmapImpl source, IBrush opacityMask, Rect opacityMaskRect, Rect sourceRect) { throw new NotImplementedException(); } + /// public void DrawLine(Pen pen, Point p1, Point p2) { var next = NextDrawAs(); 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 } } + /// public void DrawRectangle(Pen pen, Rect rect, float cornerRadius = 0) { var next = NextDrawAs(); @@ -126,13 +163,14 @@ namespace Avalonia.Rendering.SceneGraph } } + /// public void DrawText(IBrush foreground, Point origin, IFormattedTextImpl text) { var next = NextDrawAs(); 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 } } + /// public void FillRectangle(IBrush brush, Rect rect, float cornerRadius = 0) { var next = NextDrawAs(); @@ -154,41 +193,49 @@ namespace Avalonia.Rendering.SceneGraph } } + /// public void PopClip() { // TODO: Implement } + /// public void PopGeometryClip() { // TODO: Implement } + /// public void PopOpacity() { // TODO: Implement } + /// public void PopOpacityMask() { // TODO: Implement } + /// public void PushClip(Rect clip) { // TODO: Implement } + /// public void PushGeometryClip(IGeometryImpl clip) { // TODO: Implement } + /// public void PushOpacity(double opacity) { // TODO: Implement } + /// public void PushOpacityMask(IBrush mask, Rect bounds) { // TODO: Implement diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/GeometryNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/GeometryNode.cs index 7cbc0ed28e..55c6a2b9b3 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/GeometryNode.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/GeometryNode.cs @@ -9,8 +9,19 @@ using Avalonia.VisualTree; namespace Avalonia.Rendering.SceneGraph { + /// + /// A node in the scene graph which represents a geometry draw. + /// internal class GeometryNode : BrushDrawOperation { + /// + /// Initializes a new instance of the class. + /// + /// The transform. + /// The fill brush. + /// The stroke pen. + /// The geometry. + /// Child scenes for drawing visual brushes. public GeometryNode( Matrix transform, IBrush brush, @@ -26,13 +37,44 @@ namespace Avalonia.Rendering.SceneGraph ChildScenes = childScenes; } + /// public override Rect Bounds { get; } + + /// + /// Gets the transform with which the node will be drawn. + /// public Matrix Transform { get; } + + /// + /// Gets the fill brush. + /// public IBrush Brush { get; } + + /// + /// Gets the stroke pen. + /// public Pen Pen { get; } + + /// + /// Gets the geometry to draw. + /// public IGeometryImpl Geometry { get; } + + /// public override IDictionary ChildScenes { get; } + /// + /// Determines if this draw operation equals another. + /// + /// The transform of the other draw operation. + /// The fill of the other draw operation. + /// The stroke of the other draw operation. + /// The geometry of the other draw operation. + /// True if the draw operations are the same, otherwise false. + /// + /// The properties of the other draw operation are passed in as arguments to prevent + /// allocation of a not-yet-constructed draw operation object. + /// 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); } + /// public override void Render(IDrawingContextImpl context) { context.Transform = Transform; context.DrawGeometry(Brush, Pen, Geometry); } + /// public override bool HitTest(Point p) { p *= Transform.Invert(); diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/ISceneBuilder.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/ISceneBuilder.cs index a62e9ade93..dd993fbb8c 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/ISceneBuilder.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/ISceneBuilder.cs @@ -2,9 +2,23 @@ namespace Avalonia.Rendering.SceneGraph { + /// + /// Builds a scene graph from a visual tree. + /// public interface ISceneBuilder { - bool Update(Scene scene, IVisual visual); + /// + /// Builds the initial scene graph for a visual tree. + /// + /// The scene to build. void UpdateAll(Scene scene); + + /// + /// Updates the visual (and potentially its children) in a scene. + /// + /// The scene. + /// The visual to update. + /// True if changes were made, otherwise false. + bool Update(Scene scene, IVisual visual); } } \ No newline at end of file diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs index ad9f7ff0a3..b34ce42dc2 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs +++ b/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 { + /// + /// A node in the scene graph which represents an image draw. + /// internal class ImageNode : IDrawOperation { + /// + /// Initializes a new instance of the class. + /// + /// The transform. + /// The image to draw. + /// The draw opacity. + /// The source rect. + /// The destination rect. 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; } + /// public Rect Bounds { get; } + + /// + /// Gets the transform with which the node will be drawn. + /// public Matrix Transform { get; } + + /// + /// Gets the image to draw. + /// public IBitmapImpl Source { get; } + + /// + /// Gets the draw opacity. + /// public double Opacity { get; } + + /// + /// Gets the source rect. + /// public Rect SourceRect { get; } + + /// + /// Gets the destination rect. + /// public Rect DestRect { get; } - public IDictionary ChildScenes => null; + /// + /// Determines if this draw operation equals another. + /// + /// The transform of the other draw operation. + /// The image of the other draw operation. + /// The opacity of the other draw operation. + /// The source rect of the other draw operation. + /// The dest rect of the other draw operation. + /// True if the draw operations are the same, otherwise false. + /// + /// The properties of the other draw operation are passed in as arguments to prevent + /// allocation of a not-yet-constructed draw operation object. + /// 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; } + /// public void Render(IDrawingContextImpl context) { context.Transform = Transform; context.DrawImage(Source, Opacity, SourceRect, DestRect); } + /// public bool HitTest(Point p) => Bounds.Contains(p); } } diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs index 05bb4872db..46da8c7900 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs @@ -9,24 +9,72 @@ using Avalonia.VisualTree; namespace Avalonia.Rendering.SceneGraph { + /// + /// A node in the scene graph which represents a line draw. + /// internal class LineNode : BrushDrawOperation { - public LineNode(Matrix transform, Pen pen, Point p1, Point p2) + /// + /// Initializes a new instance of the class. + /// + /// The transform. + /// The stroke pen. + /// The start point of the line. + /// The end point of the line. + /// Child scenes for drawing visual brushes. + public LineNode( + Matrix transform, + Pen pen, + Point p1, + Point p2, + IDictionary childScenes = null) { Bounds = new Rect(P1, P2); Transform = transform; Pen = ToImmutable(pen); P1 = p1; P2 = p2; + ChildScenes = childScenes; } + /// public override Rect Bounds { get; } + + /// + /// Gets the transform with which the node will be drawn. + /// public Matrix Transform { get; } + + /// + /// Gets the stroke pen. + /// public Pen Pen { get; } + + /// + /// Gets the start point of the line. + /// public Point P1 { get; } + + /// + /// Gets the end point of the line. + /// public Point P2 { get; } - public override IDictionary ChildScenes => null; + /// + public override IDictionary ChildScenes { get; } + + /// + /// Determines if this draw operation equals another. + /// + /// The transform of the other draw operation. + /// The stroke of the other draw operation. + /// The start point of the other draw operation. + /// The end point of the other draw operation. + /// True if the draw operations are the same, otherwise false. + /// + /// The properties of the other draw operation are passed in as arguments to prevent + /// allocation of a not-yet-constructed draw operation object. + /// public bool Equals(Matrix transform, Pen pen, Point p1, Point p2) { return transform == Transform && pen == Pen && p1 == P1 && p2 == P2; diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs index ab931ca623..33cccf5732 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs @@ -9,8 +9,20 @@ using Avalonia.VisualTree; namespace Avalonia.Rendering.SceneGraph { + /// + /// A node in the scene graph which represents a rectangle draw. + /// internal class RectangleNode : BrushDrawOperation { + /// + /// Initializes a new instance of the class. + /// + /// The transform. + /// The fill brush. + /// The stroke pen. + /// The rectanle to draw. + /// The rectangle corner radius. + /// Child scenes for drawing visual brushes. public RectangleNode( Matrix transform, IBrush brush, @@ -28,14 +40,50 @@ namespace Avalonia.Rendering.SceneGraph ChildScenes = childScenes; } + /// public override Rect Bounds { get; } + + /// + /// Gets the transform with which the node will be drawn. + /// public Matrix Transform { get; } + + /// + /// Gets the fill brush. + /// public IBrush Brush { get; } + + /// + /// Gets the stroke pen. + /// public Pen Pen { get; } + + /// + /// Gets the rectangle to draw. + /// public Rect Rect { get; } + + /// + /// Gets the rectangle corner radius. + /// public float CornerRadius { get; } + + /// public override IDictionary ChildScenes { get; } + /// + /// Determines if this draw operation equals another. + /// + /// The transform of the other draw operation. + /// The fill of the other draw operation. + /// The stroke of the other draw operation. + /// The rectangle of the other draw operation. + /// The rectangle corner radius of the other draw operation. + /// True if the draw operations are the same, otherwise false. + /// + /// The properties of the other draw operation are passed in as arguments to prevent + /// allocation of a not-yet-constructed draw operation object. + /// 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; } + /// public override void Render(IDrawingContextImpl context) { context.Transform = Transform; @@ -60,6 +109,7 @@ namespace Avalonia.Rendering.SceneGraph } } + /// public override bool HitTest(Point p) => Bounds.Contains(p); } } diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs index 3a15be144c..6db092c266 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs +++ b/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 { + /// + /// Represents a scene graph used by the . + /// public class Scene { private Dictionary _index; + /// + /// Initializes a new instance of the class. + /// + /// The root visual to draw. 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 index, SceneLayers layers, int id) + private Scene(VisualNode root, Dictionary index, SceneLayers layers, int id) { Contract.Requires(root != null); @@ -35,12 +41,35 @@ namespace Avalonia.Rendering.SceneGraph root.LayerRoot = root.Visual; } + /// + /// Gets an ID identifying the scene. This is incremented each time the scene is cloned. + /// public int Id { get; } + + /// + /// Gets the layers for the scene. + /// public SceneLayers Layers { get; } + + /// + /// Gets the root node of the scene graph. + /// public IVisualNode Root { get; } + + /// + /// Gets or sets the size of the scene in device independent pixels. + /// public Size Size { get; set; } + + /// + /// Gets or sets the scene scaling. + /// public double Scaling { get; set; } = 1; + /// + /// Adds a node to the scene index. + /// + /// The node. public void Add(IVisualNode node) { Contract.Requires(node != null); @@ -48,6 +77,10 @@ namespace Avalonia.Rendering.SceneGraph _index.Add(node.Visual, node); } + /// + /// Clones the scene. + /// + /// The cloned scene. public Scene Clone() { var index = new Dictionary(); @@ -62,6 +95,13 @@ namespace Avalonia.Rendering.SceneGraph return result; } + /// + /// Tries to find a node in the scene graph representing the specified visual. + /// + /// The visual. + /// + /// The node representing the visual or null if it could not be found. + /// public IVisualNode FindNode(IVisual visual) { IVisualNode node; @@ -69,11 +109,21 @@ namespace Avalonia.Rendering.SceneGraph return node; } + /// + /// Gets the visuals at a point in the scene. + /// + /// The point. + /// A filter. May be null. + /// The visuals at the specified point. public IEnumerable HitTest(Point p, Func filter) { return HitTest(Root, p, null, filter); } + /// + /// Removes a node from the scene index. + /// + /// The node. public void Remove(IVisualNode node) { Contract.Requires(node != null); diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs index 7adebcd1dc..e54648fe8d 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs @@ -10,8 +10,12 @@ using Avalonia.VisualTree; namespace Avalonia.Rendering.SceneGraph { + /// + /// Builds a scene graph from a visual tree. + /// public class SceneBuilder : ISceneBuilder { + /// public void UpdateAll(Scene scene) { Contract.Requires(scene != null); @@ -27,6 +31,7 @@ namespace Avalonia.Rendering.SceneGraph } } + /// public bool Update(Scene scene, IVisual visual) { Contract.Requires(scene != null); diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneLayer.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneLayer.cs index 253842ea3b..c17fbb08c9 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneLayer.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneLayer.cs @@ -5,8 +5,16 @@ using Avalonia.VisualTree; namespace Avalonia.Rendering.SceneGraph { + /// + /// Represents a layer in a . + /// public class SceneLayer { + /// + /// Initializes a new instance of the class. + /// + /// The visual at the root of the layer. + /// The distance from the scene root. public SceneLayer(IVisual layerRoot, int distanceFromRoot) { LayerRoot = layerRoot; @@ -14,6 +22,10 @@ namespace Avalonia.Rendering.SceneGraph DistanceFromRoot = distanceFromRoot; } + /// + /// Clones the layer. + /// + /// The cloned layer. public SceneLayer Clone() { return new SceneLayer(LayerRoot, DistanceFromRoot) @@ -25,12 +37,39 @@ namespace Avalonia.Rendering.SceneGraph }; } + /// + /// Gets the visual at the root of the layer. + /// public IVisual LayerRoot { get; } + + /// + /// Gets the dirty rectangles for the layer. + /// public DirtyRects Dirty { get; } + + /// + /// Gets the distance of the layer root from the root of the scene. + /// public int DistanceFromRoot { get; } + + /// + /// Gets or sets the opacity of the layer. + /// public double Opacity { get; set; } = 1; + + /// + /// Gets or sets the opacity mask for the layer. + /// public IBrush OpacityMask { get; set; } + + /// + /// Gets or sets the target rectangle for the layer opacity mask. + /// public Rect OpacityMaskRect { get; set; } + + /// + /// Gets the layer's geometry clip. + /// public IGeometryImpl GeometryClip { get; set; } } } diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneLayers.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneLayers.cs index 1d3c796da7..5960b4f560 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneLayers.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneLayers.cs @@ -5,19 +5,32 @@ using Avalonia.VisualTree; namespace Avalonia.Rendering.SceneGraph { + /// + /// Holds a collection of layers for a . + /// public class SceneLayers : IEnumerable { private readonly IVisual _root; private readonly List _inner = new List(); private readonly Dictionary _index = new Dictionary(); + /// + /// Initializes a new instance of the class. + /// + /// The scene's root visual. public SceneLayers(IVisual root) { _root = root; } + /// + /// Gets the number of layers in the scene. + /// public int Count => _inner.Count; + /// + /// Gets a value indicating whether any of the layers have a dirty region. + /// public bool HasDirty { get @@ -34,9 +47,25 @@ namespace Avalonia.Rendering.SceneGraph } } + /// + /// Gets a layer by index. + /// + /// The index of the layer. + /// The layer. public SceneLayer this[int index] => _inner[index]; + + /// + /// Gets a layer by its root visual. + /// + /// The layer's root visual. + /// The layer. public SceneLayer this[IVisual visual] => _index[visual]; + /// + /// Adds a layer to the scene. + /// + /// The root visual of the layer. + /// The created layer. public SceneLayer Add(IVisual layerRoot) { Contract.Requires(layerRoot != null); @@ -49,6 +78,10 @@ namespace Avalonia.Rendering.SceneGraph return layer; } + /// + /// Makes a deep clone of the layers. + /// + /// The cloned layers. public SceneLayers Clone() { var result = new SceneLayers(_root); @@ -63,6 +96,13 @@ namespace Avalonia.Rendering.SceneGraph return result; } + /// + /// Tests whether a layer exists with the specified root visual. + /// + /// The root visual. + /// + /// True if a layer exists with the specified root visual, otherwise false. + /// public bool Exists(IVisual layerRoot) { Contract.Requires(layerRoot != null); @@ -70,6 +110,11 @@ namespace Avalonia.Rendering.SceneGraph return _index.ContainsKey(layerRoot); } + /// + /// Tries to find a layer with the specified root visual. + /// + /// The root visual. + /// The layer if found, otherwise null. public SceneLayer Find(IVisual layerRoot) { SceneLayer result; @@ -77,6 +122,11 @@ namespace Avalonia.Rendering.SceneGraph return result; } + /// + /// Gets an existing layer or creates a new one if no existing layer is found. + /// + /// The root visual. + /// The layer. public SceneLayer GetOrAdd(IVisual layerRoot) { Contract.Requires(layerRoot != null); @@ -91,6 +141,11 @@ namespace Avalonia.Rendering.SceneGraph return result; } + /// + /// Removes a layer from the scene. + /// + /// The root visual. + /// True if a matching layer was removed, otherwise false. public bool Remove(IVisual layerRoot) { Contract.Requires(layerRoot != null); @@ -105,6 +160,11 @@ namespace Avalonia.Rendering.SceneGraph return layer != null; } + /// + /// Removes a layer from the scene. + /// + /// The layer. + /// True if the layer was part of the scene, otherwise false. public bool Remove(SceneLayer layer) { Contract.Requires(layer != null); @@ -113,7 +173,10 @@ namespace Avalonia.Rendering.SceneGraph return _inner.Remove(layer); } + /// public IEnumerator GetEnumerator() => _inner.GetEnumerator(); + + /// IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); private int FindInsertIndex(SceneLayer insert) diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/TextNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/TextNode.cs index df119365a6..3dc1500af0 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/TextNode.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/TextNode.cs @@ -9,30 +9,79 @@ using Avalonia.VisualTree; namespace Avalonia.Rendering.SceneGraph { + /// + /// A node in the scene graph which represents a text draw. + /// internal class TextNode : BrushDrawOperation { - public TextNode(Matrix transform, IBrush foreground, Point origin, IFormattedTextImpl text) + /// + /// Initializes a new instance of the class. + /// + /// The transform. + /// The foreground brush. + /// The draw origin. + /// The text to draw. + /// Child scenes for drawing visual brushes. + public TextNode( + Matrix transform, + IBrush foreground, + Point origin, + IFormattedTextImpl text, + IDictionary childScenes = null) { Bounds = new Rect(origin, text.Size).TransformToAABB(transform); Transform = transform; Foreground = ToImmutable(foreground); Origin = origin; Text = text; + ChildScenes = childScenes; } + /// public override Rect Bounds { get; } + + /// + /// Gets the transform with which the node will be drawn. + /// public Matrix Transform { get; } + + /// + /// Gets the foreground brush. + /// public IBrush Foreground { get; } + + /// + /// Gets the draw origin. + /// public Point Origin { get; } + + /// + /// Gets the text to draw. + /// public IFormattedTextImpl Text { get; } - public override IDictionary ChildScenes => null; + /// + public override IDictionary ChildScenes { get; } + + /// public override void Render(IDrawingContextImpl context) { context.Transform = Transform; context.DrawText(Foreground, Origin, Text); } + /// + /// Determines if this draw operation equals another. + /// + /// The transform of the other draw operation. + /// The foregroundof the other draw operation. + /// The draw origin of the other draw operation. + /// The text of the other draw operation. + /// True if the draw operations are the same, otherwise false. + /// + /// The properties of the other draw operation are passed in as arguments to prevent + /// allocation of a not-yet-constructed draw operation object. + /// 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); } + /// public override bool HitTest(Point p) => Bounds.Contains(p); } }