Просмотр исходного кода

Got VisualBrushes working again.

Steven Kirk 8 лет назад
Родитель
Сommit
69bca2cf89

+ 32 - 25
src/Avalonia.Visuals/Rendering/DeferredRenderer.cs

@@ -30,6 +30,7 @@ namespace Avalonia.Rendering
         private bool _rendering;
         private int _lastSceneId = -1;
         private DisplayDirtyRects _dirtyRectsDisplay = new DisplayDirtyRects();
+        private IDrawOperation _currentDraw;
 
         public DeferredRenderer(
             IRenderRoot root,
@@ -107,20 +108,16 @@ namespace Avalonia.Rendering
 
         Size IVisualBrushRenderer.GetRenderTargetSize(IVisualBrush brush)
         {
-            if (brush.Visual != null)
-            {
-                return _scene.FindNode(brush.Visual)?.ClipBounds.Size ?? Size.Empty;
-            }
-
-            return Size.Empty;
+            return (_currentDraw as BrushDrawOperation)?.ChildScenes?[brush.Visual]?.Size ?? Size.Empty;
         }
 
         void IVisualBrushRenderer.RenderVisualBrush(IDrawingContextImpl context, IVisualBrush brush)
         {
-            if (brush.Visual != null)
+            var childScene = (_currentDraw as BrushDrawOperation)?.ChildScenes?[brush.Visual];
+
+            if (childScene != null)
             {
-                var node = (VisualNode)_scene.FindNode(brush.Visual);
-                Render(context, node, null, node.ClipBounds);
+                Render(context, (VisualNode)childScene.Root, null, new Rect(childScene.Size));
             }
         }
 
@@ -130,29 +127,37 @@ namespace Avalonia.Rendering
 
         private void Render(Scene scene)
         {
-            _rendering = true;
-            _dirtyRectsDisplay.Tick();
-
-            if (scene.Size != Size.Empty)
+            if (!_rendering)
             {
-                if (scene.Id != _lastSceneId)
+                try
                 {
-                    _layers.Update(scene);
-                    RenderToLayers(scene);
+                    _rendering = true;
+                    _dirtyRectsDisplay.Tick();
 
-                    if (DebugFramesPath != null)
+                    if (scene.Size != Size.Empty)
                     {
-                        SaveDebugFrames(scene.Id);
-                    }
+                        if (scene.Id != _lastSceneId)
+                        {
+                            _layers.Update(scene);
+                            RenderToLayers(scene);
 
-                    _lastSceneId = scene.Id;
-                }
+                            if (DebugFramesPath != null)
+                            {
+                                SaveDebugFrames(scene.Id);
+                            }
 
-                RenderOverlay(scene);
-                RenderComposite(scene);
-            }
+                            _lastSceneId = scene.Id;
+                        }
 
-            _rendering = false;
+                        RenderOverlay(scene);
+                        RenderComposite(scene);
+                    }
+                }
+                finally
+                {
+                    _rendering = false;
+                }
+            }
         }
 
         private void Render(IDrawingContextImpl context, VisualNode node, IVisual layer, Rect clipBounds)
@@ -167,7 +172,9 @@ namespace Avalonia.Rendering
 
                     foreach (var operation in node.DrawOperations)
                     {
+                        _currentDraw = operation;
                         operation.Render(context);
+                        _currentDraw = null;
                     }
 
                     foreach (var child in node.Children)

+ 4 - 0
src/Avalonia.Visuals/Rendering/SceneGraph/BrushDrawOperation.cs

@@ -1,6 +1,8 @@
 using System;
+using System.Collections.Generic;
 using Avalonia.Media;
 using Avalonia.Rendering.SceneGraph.Media;
+using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.SceneGraph
 {
@@ -8,6 +10,8 @@ namespace Avalonia.Rendering.SceneGraph
     {
         public abstract Rect Bounds { get; }
         public abstract bool HitTest(Point p);
+        public abstract IDictionary<IVisual, Scene> ChildScenes { get; }
+
         public abstract void Render(IDrawingContextImpl context);
 
         protected IBrush Convert(IBrush brush)

+ 28 - 4
src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs

@@ -2,19 +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;
+using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.SceneGraph
 {
     internal class DeferredDrawingContextImpl : IDrawingContextImpl
     {
+        private readonly ISceneBuilder _sceneBuilder;
         private VisualNode _node;
         private int _childIndex;
         private int _drawOperationindex;
 
-        public DeferredDrawingContextImpl(SceneLayers layers)
+        public DeferredDrawingContextImpl(ISceneBuilder sceneBuilder, SceneLayers layers)
         {
+            _sceneBuilder = sceneBuilder;
             Layers = layers;
         }
 
@@ -67,7 +71,7 @@ namespace Avalonia.Rendering.SceneGraph
 
             if (next == null || !next.Equals(Transform, brush, pen, geometry))
             {
-                Add(new GeometryNode(Transform, brush, pen, geometry));
+                Add(new GeometryNode(Transform, brush, pen, geometry, CreateChildScene(brush)));
             }
             else
             {
@@ -109,7 +113,7 @@ namespace Avalonia.Rendering.SceneGraph
 
             if (next == null || !next.Equals(Transform, null, pen, rect, cornerRadius))
             {
-                Add(new RectangleNode(Transform, null, pen, rect, cornerRadius));
+                Add(new RectangleNode(Transform, null, pen, rect, cornerRadius, CreateChildScene(pen.Brush)));
             }
             else
             {
@@ -137,7 +141,7 @@ namespace Avalonia.Rendering.SceneGraph
 
             if (next == null || !next.Equals(Transform, brush, null, rect, cornerRadius))
             {
-                Add(new RectangleNode(Transform, brush, null, rect, cornerRadius));
+                Add(new RectangleNode(Transform, brush, null, rect, cornerRadius, CreateChildScene(brush)));
             }
             else
             {
@@ -239,5 +243,25 @@ namespace Avalonia.Rendering.SceneGraph
         {
             return _drawOperationindex < _node.DrawOperations.Count ? _node.DrawOperations[_drawOperationindex] as T : null;
         }
+
+        private IDictionary<IVisual, Scene> CreateChildScene(IBrush brush)
+        {
+            var visualBrush = brush as VisualBrush;
+
+            if (visualBrush != null)
+            {
+                var visual = visualBrush.Visual;
+
+                if (visual != null)
+                {
+                    (visual as IVisualBrushInitialize)?.EnsureInitialized();
+                    var scene = new Scene(visual);
+                    _sceneBuilder.UpdateAll(scene);
+                    return new Dictionary<IVisual, Scene> { { visualBrush.Visual, scene } };
+                }
+            }
+
+            return null;
+        }
     }
 }

+ 10 - 1
src/Avalonia.Visuals/Rendering/SceneGraph/GeometryNode.cs

@@ -2,20 +2,28 @@
 // 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;
+using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.SceneGraph
 {
     public class GeometryNode : BrushDrawOperation
     {
-        public GeometryNode(Matrix transform, IBrush brush, Pen pen, IGeometryImpl geometry)
+        public GeometryNode(
+            Matrix transform,
+            IBrush brush,
+            Pen pen,
+            IGeometryImpl geometry,
+            IDictionary<IVisual, Scene> childScenes = null)
         {
             Bounds = geometry.GetRenderBounds(pen.Thickness).TransformToAABB(transform);
             Transform = transform;
             Brush = Convert(brush);
             Pen = Convert(pen);
             Geometry = geometry;
+            ChildScenes = childScenes;
         }
 
         public override Rect Bounds { get; }
@@ -23,6 +31,7 @@ namespace Avalonia.Rendering.SceneGraph
         public IBrush Brush { get; }
         public Pen Pen { get; }
         public IGeometryImpl Geometry { get; }
+        public override IDictionary<IVisual, Scene> ChildScenes { get; }
 
         public bool Equals(Matrix transform, IBrush brush, Pen pen, IGeometryImpl geometry)
         {

+ 2 - 0
src/Avalonia.Visuals/Rendering/SceneGraph/IDrawOperation.cs

@@ -2,7 +2,9 @@
 // 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.VisualTree;
 
 namespace Avalonia.Rendering.SceneGraph
 {

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

@@ -2,8 +2,10 @@
 // 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;
+using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.SceneGraph
 {
@@ -25,6 +27,7 @@ namespace Avalonia.Rendering.SceneGraph
         public double Opacity { get; }
         public Rect SourceRect { get; }
         public Rect DestRect { get; }
+        public IDictionary<VisualBrush, Scene> ChildScenes => null;
 
         public bool Equals(Matrix transform, IBitmapImpl source, double opacity, Rect sourceRect, Rect destRect)
         {

+ 3 - 0
src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs

@@ -2,7 +2,9 @@
 // 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.VisualTree;
 
 namespace Avalonia.Rendering.SceneGraph
 {
@@ -22,6 +24,7 @@ namespace Avalonia.Rendering.SceneGraph
         public Pen Pen { get; }
         public Point P1 { get; }
         public Point P2 { get; }
+        public override IDictionary<IVisual, Scene> ChildScenes => null;
 
         public bool Equals(Matrix transform, Pen pen, Point p1, Point p2)
         {

+ 11 - 1
src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs

@@ -2,13 +2,21 @@
 // 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.VisualTree;
 
 namespace Avalonia.Rendering.SceneGraph
 {
     public class RectangleNode : BrushDrawOperation
     {
-        public RectangleNode(Matrix transform, IBrush brush, Pen pen, Rect rect, float cornerRadius)
+        public RectangleNode(
+            Matrix transform,
+            IBrush brush,
+            Pen pen,
+            Rect rect,
+            float cornerRadius,
+            IDictionary<IVisual, Scene> childScenes = null)
         {
             Bounds = rect.TransformToAABB(transform).Inflate(pen?.Thickness ?? 0);
             Transform = transform;
@@ -16,6 +24,7 @@ namespace Avalonia.Rendering.SceneGraph
             Pen = Convert(pen);
             Rect = rect;
             CornerRadius = cornerRadius;
+            ChildScenes = childScenes;
         }
 
         public override Rect Bounds { get; }
@@ -24,6 +33,7 @@ namespace Avalonia.Rendering.SceneGraph
         public Pen Pen { get; }
         public Rect Rect { get; }
         public float CornerRadius { get; }
+        public override IDictionary<IVisual, Scene> ChildScenes { get; }
 
         public bool Equals(Matrix transform, IBrush brush, Pen pen, Rect rect, float cornerRadius)
         {

+ 2 - 2
src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs

@@ -19,7 +19,7 @@ namespace Avalonia.Rendering.SceneGraph
             UpdateSize(scene);
             scene.Layers.GetOrAdd(scene.Root.Visual);
 
-            using (var impl = new DeferredDrawingContextImpl(scene.Layers))
+            using (var impl = new DeferredDrawingContextImpl(this, scene.Layers))
             using (var context = new DrawingContext(impl))
             {
                 Update(context, scene, (VisualNode)scene.Root, scene.Root.Visual.Bounds, true);
@@ -55,7 +55,7 @@ namespace Avalonia.Rendering.SceneGraph
                         // descendents too.
                         var recurse = node.Visual != visual;
 
-                        using (var impl = new DeferredDrawingContextImpl(scene.Layers))
+                        using (var impl = new DeferredDrawingContextImpl(this, scene.Layers))
                         using (var context = new DrawingContext(impl))
                         {
                             var clip = scene.Root.Visual.Bounds;

+ 3 - 0
src/Avalonia.Visuals/Rendering/SceneGraph/TextNode.cs

@@ -2,8 +2,10 @@
 // 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;
+using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.SceneGraph
 {
@@ -23,6 +25,7 @@ namespace Avalonia.Rendering.SceneGraph
         public IBrush Foreground { get; }
         public Point Origin { get; }
         public IFormattedTextImpl Text { get; }
+        public IDictionary<VisualBrush, Scene> ChildScenes => null;
 
         public void Render(IDrawingContextImpl context)
         {

+ 0 - 6
src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs

@@ -31,12 +31,6 @@ namespace Avalonia.Rendering.SceneGraph
         {
             Contract.Requires<ArgumentNullException>(visual != null);
 
-            if (parent == null && visual.VisualParent != null)
-            {
-                throw new AvaloniaInternalException(
-                    "Attempted to create root VisualNode for parented visual.");
-            }
-
             Visual = visual;
             Parent = parent;
         }

+ 9 - 9
tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DeferredDrawingContextImplTests.cs

@@ -17,7 +17,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
             var parent = new VisualNode(new TestRoot(), null);
             var child = new VisualNode(Mock.Of<IVisual>(), null);
             var layers = new SceneLayers(parent.Visual);
-            var target = new DeferredDrawingContextImpl(layers);
+            var target = new DeferredDrawingContextImpl(null, layers);
 
             target.BeginUpdate(parent);
             target.BeginUpdate(child);
@@ -35,7 +35,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
 
             parent.AddChild(child);
 
-            var target = new DeferredDrawingContextImpl(layers);
+            var target = new DeferredDrawingContextImpl(null, layers);
 
             target.BeginUpdate(parent);
             target.BeginUpdate(child);
@@ -54,7 +54,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
 
             parent.AddChild(child1);
 
-            var target = new DeferredDrawingContextImpl(layers);
+            var target = new DeferredDrawingContextImpl(null, layers);
 
             target.BeginUpdate(parent);
             target.BeginUpdate(child2);
@@ -75,7 +75,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
             node.AddChild(new VisualNode(Mock.Of<IVisual>(), node) { LayerRoot = root });
 
             var layers = new SceneLayers(root);
-            var target = new DeferredDrawingContextImpl(layers);
+            var target = new DeferredDrawingContextImpl(null, layers);
             var child1 = new VisualNode(Mock.Of<IVisual>(), null) { LayerRoot = root };
             var child2 = new VisualNode(Mock.Of<IVisual>(), null) { LayerRoot = root };
 
@@ -92,7 +92,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
         {
             var node = new VisualNode(new TestRoot(), null);
             var layers = new SceneLayers(node.Visual);
-            var target = new DeferredDrawingContextImpl(layers);
+            var target = new DeferredDrawingContextImpl(null, layers);
 
             node.LayerRoot = node.Visual;
 
@@ -113,7 +113,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
             var node = new VisualNode(new TestRoot(), null);
             var operation = new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 100, 100), 0);
             var layers = new SceneLayers(node.Visual);
-            var target = new DeferredDrawingContextImpl(layers);
+            var target = new DeferredDrawingContextImpl(null, layers);
 
             node.LayerRoot = node.Visual;
             node.AddDrawOperation(operation);
@@ -135,7 +135,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
             var node = new VisualNode(new TestRoot(), null);
             var operation = new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 100, 100), 0);
             var layers = new SceneLayers(node.Visual);
-            var target = new DeferredDrawingContextImpl(layers);
+            var target = new DeferredDrawingContextImpl(null, layers);
 
             node.LayerRoot = node.Visual;
             node.AddDrawOperation(operation);
@@ -157,7 +157,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
             var node = new VisualNode(new TestRoot(), null);
             var operation = new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 100, 100), 0);
             var layers = new SceneLayers(node.Visual);
-            var target = new DeferredDrawingContextImpl(layers);
+            var target = new DeferredDrawingContextImpl(null, layers);
 
             node.LayerRoot = node.Visual;
 
@@ -181,7 +181,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
             node.AddDrawOperation(new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 40, 100), 0));
 
             var layers = new SceneLayers(node.Visual);
-            var target = new DeferredDrawingContextImpl(layers);
+            var target = new DeferredDrawingContextImpl(null, layers);
 
             using (target.BeginUpdate(node))
             {