浏览代码

Removed RendererMixin.

Moved immediate rendering logic into `Renderer`.
Steven Kirk 9 年之前
父节点
当前提交
14805322ca

+ 0 - 1
src/Avalonia.Visuals/Avalonia.Visuals.csproj

@@ -116,7 +116,6 @@
     <Compile Include="Rendering\IRenderLoop.cs" />
     <Compile Include="Rendering\IRenderLoop.cs" />
     <Compile Include="Rendering\DirtyRects.cs" />
     <Compile Include="Rendering\DirtyRects.cs" />
     <Compile Include="Rendering\Renderer.cs" />
     <Compile Include="Rendering\Renderer.cs" />
-    <Compile Include="Rendering\RendererMixin.cs" />
     <Compile Include="Rendering\DefaultRenderLoop.cs" />
     <Compile Include="Rendering\DefaultRenderLoop.cs" />
     <Compile Include="Rendering\IRenderLayerFactory.cs" />
     <Compile Include="Rendering\IRenderLayerFactory.cs" />
     <Compile Include="Rendering\RenderLayer.cs" />
     <Compile Include="Rendering\RenderLayer.cs" />

+ 7 - 0
src/Avalonia.Visuals/Media/Imaging/RenderTargetBitmap.cs

@@ -3,6 +3,7 @@
 
 
 using System;
 using System;
 using Avalonia.Platform;
 using Avalonia.Platform;
+using Avalonia.Rendering;
 using Avalonia.VisualTree;
 using Avalonia.VisualTree;
 
 
 namespace Avalonia.Media.Imaging
 namespace Avalonia.Media.Imaging
@@ -37,6 +38,12 @@ namespace Avalonia.Media.Imaging
             PlatformImpl.Dispose();
             PlatformImpl.Dispose();
         }
         }
 
 
+        /// <summary>
+        /// Renders a visual to the <see cref="RenderTargetBitmap"/>.
+        /// </summary>
+        /// <param name="visual">The visual to render.</param>
+        public void Render(IVisual visual) => Renderer.Render(visual, this);
+
         /// <summary>
         /// <summary>
         /// Creates a platform-specific imlementation for a <see cref="RenderTargetBitmap"/>.
         /// Creates a platform-specific imlementation for a <see cref="RenderTargetBitmap"/>.
         /// </summary>
         /// </summary>

+ 134 - 6
src/Avalonia.Visuals/Rendering/Renderer.cs

@@ -6,13 +6,15 @@ using Avalonia.Platform;
 using Avalonia.VisualTree;
 using Avalonia.VisualTree;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using Avalonia.Threading;
 using Avalonia.Threading;
+using Avalonia.Media;
+using System.Linq;
 
 
 namespace Avalonia.Rendering
 namespace Avalonia.Rendering
 {
 {
     public class Renderer : IDisposable, IRenderer
     public class Renderer : IDisposable, IRenderer
     {
     {
         private readonly IRenderLoop _renderLoop;
         private readonly IRenderLoop _renderLoop;
-        private readonly IRenderRoot _root;
+        private readonly IVisual _root;
         private IRenderTarget _renderTarget;
         private IRenderTarget _renderTarget;
         private bool _dirty;
         private bool _dirty;
         private bool _renderQueued;
         private bool _renderQueued;
@@ -20,15 +22,40 @@ namespace Avalonia.Rendering
         public Renderer(IRenderRoot root, IRenderLoop renderLoop)
         public Renderer(IRenderRoot root, IRenderLoop renderLoop)
         {
         {
             Contract.Requires<ArgumentNullException>(root != null);
             Contract.Requires<ArgumentNullException>(root != null);
+            Contract.Requires<ArgumentNullException>(renderLoop != null);
 
 
             _root = root;
             _root = root;
             _renderLoop = renderLoop;
             _renderLoop = renderLoop;
             _renderLoop.Tick += OnRenderLoopTick;
             _renderLoop.Tick += OnRenderLoopTick;
         }
         }
 
 
+        private Renderer(IVisual root)
+        {
+            Contract.Requires<ArgumentNullException>(root != null);
+
+            _root = root;
+        }
+
         public bool DrawFps { get; set; }
         public bool DrawFps { get; set; }
         public bool DrawDirtyRects { get; set; }
         public bool DrawDirtyRects { get; set; }
 
 
+        public static void Render(IVisual visual, IRenderTarget target)
+        {
+            using (var renderer = new Renderer(visual))
+            using (var context = new DrawingContext(target.CreateDrawingContext()))
+            {
+                renderer.Render(context, visual, visual.Bounds);
+            }
+        }
+
+        public static void Render(IVisual visual, DrawingContext context)
+        {
+            using (var renderer = new Renderer(visual))
+            {
+                renderer.Render(context, visual, visual.Bounds);
+            }
+        }
+
         public void AddDirty(IVisual visual)
         public void AddDirty(IVisual visual)
         {
         {
             _dirty = true;
             _dirty = true;
@@ -36,7 +63,10 @@ namespace Avalonia.Rendering
 
 
         public void Dispose()
         public void Dispose()
         {
         {
-            _renderLoop.Tick -= OnRenderLoopTick;
+            if (_renderLoop != null)
+            {
+                _renderLoop.Tick -= OnRenderLoopTick;
+            }
         }
         }
 
 
         public IEnumerable<IVisual> HitTest(Point p, Func<IVisual, bool> filter)
         public IEnumerable<IVisual> HitTest(Point p, Func<IVisual, bool> filter)
@@ -48,13 +78,12 @@ namespace Avalonia.Rendering
         {
         {
             if (_renderTarget == null)
             if (_renderTarget == null)
             {
             {
-                _renderTarget = _root.CreateRenderTarget();
+                _renderTarget = ((IRenderRoot)_root).CreateRenderTarget();
             }
             }
 
 
             try
             try
             {
             {
-                RendererMixin.DrawFpsCounter = DrawFps;
-                _renderTarget.Render(_root);
+                Render(_root);
             }
             }
             catch (RenderTargetCorruptedException ex)
             catch (RenderTargetCorruptedException ex)
             {
             {
@@ -69,6 +98,29 @@ namespace Avalonia.Rendering
             }
             }
         }
         }
 
 
+        private static void ClearTransformedBounds(IVisual visual)
+        {
+            foreach (var e in visual.GetSelfAndVisualDescendents())
+            {
+                BoundsTracker.SetTransformedBounds((Visual)visual, null);
+            }
+        }
+
+        private static Rect GetTransformedBounds(IVisual visual)
+        {
+            if (visual.RenderTransform == null)
+            {
+                return visual.Bounds;
+            }
+            else
+            {
+                var origin = visual.RenderTransformOrigin.ToPixels(new Size(visual.Bounds.Width, visual.Bounds.Height));
+                var offset = Matrix.CreateTranslation(visual.Bounds.Position + origin);
+                var m = (-offset) * visual.RenderTransform.Value * (offset);
+                return visual.Bounds.TransformToAABB(m);
+            }
+        }
+
         static IEnumerable<IVisual> HitTest(
         static IEnumerable<IVisual> HitTest(
            IVisual visual,
            IVisual visual,
            Point p,
            Point p,
@@ -98,12 +150,88 @@ namespace Avalonia.Rendering
             }
             }
         }
         }
 
 
+        private void Render(IVisual visual)
+        {
+            using (var context = new DrawingContext(_renderTarget.CreateDrawingContext()))
+            {
+                Render(context, visual, visual.Bounds);
+            }
+        }
+
+        private void Render(DrawingContext context, IVisual visual, Rect clipRect)
+        {
+            var opacity = visual.Opacity;
+            var clipToBounds = visual.ClipToBounds;
+            var bounds = new Rect(visual.Bounds.Size);
+
+            if (visual.IsVisible && opacity > 0)
+            {
+                var m = Matrix.CreateTranslation(visual.Bounds.Position);
+
+                var renderTransform = Matrix.Identity;
+
+                if (visual.RenderTransform != null)
+                {
+                    var origin = visual.RenderTransformOrigin.ToPixels(new Size(visual.Bounds.Width, visual.Bounds.Height));
+                    var offset = Matrix.CreateTranslation(origin);
+                    renderTransform = (-offset) * visual.RenderTransform.Value * (offset);
+                }
+
+                m = renderTransform * m;
+
+                if (clipToBounds)
+                {
+                    clipRect = clipRect.Intersect(new Rect(visual.Bounds.Size));
+                }
+
+                using (context.PushPostTransform(m))
+                using (context.PushOpacity(opacity))
+                using (clipToBounds ? context.PushClip(bounds) : default(DrawingContext.PushedState))
+                using (visual.Clip != null ? context.PushGeometryClip(visual.Clip) : default(DrawingContext.PushedState))
+                using (visual.OpacityMask != null ? context.PushOpacityMask(visual.OpacityMask, bounds) : default(DrawingContext.PushedState))
+                using (context.PushTransformContainer())
+                {
+                    visual.Render(context);
+
+#pragma warning disable 0618
+                    var transformed =
+                        new TransformedBounds(bounds, new Rect(), context.CurrentContainerTransform);
+#pragma warning restore 0618
+
+                    if (visual is Visual)
+                    {
+                        BoundsTracker.SetTransformedBounds((Visual)visual, transformed);
+                    }
+
+                    foreach (var child in visual.VisualChildren.OrderBy(x => x, ZIndexComparer.Instance))
+                    {
+                        var childBounds = GetTransformedBounds(child);
+
+                        if (!child.ClipToBounds || clipRect.Intersects(childBounds))
+                        {
+                            var childClipRect = clipRect.Translate(-childBounds.Position);
+                            Render(context, child, childClipRect);
+                        }
+                        else
+                        {
+                            ClearTransformedBounds(child);
+                        }
+                    }
+                }
+            }
+
+            if (!visual.IsVisible)
+            {
+                ClearTransformedBounds(visual);
+            }
+        }
+
         private void OnRenderLoopTick(object sender, EventArgs e)
         private void OnRenderLoopTick(object sender, EventArgs e)
         {
         {
             if (_dirty && !_renderQueued)
             if (_dirty && !_renderQueued)
             {
             {
                 _renderQueued = true;
                 _renderQueued = true;
-                Dispatcher.UIThread.InvokeAsync(() => Render(new Rect(_root.ClientSize)));
+                Dispatcher.UIThread.InvokeAsync(() => Render(new Rect(((IRenderRoot)_root).ClientSize)));
             }
             }
         }
         }
     }
     }

+ 0 - 209
src/Avalonia.Visuals/Rendering/RendererMixin.cs

@@ -1,209 +0,0 @@
-// 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 System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
-using Avalonia.Media;
-using Avalonia.Platform;
-using Avalonia.VisualTree;
-
-namespace Avalonia.Rendering
-{
-    /// <summary>
-    /// Extension methods for rendering.
-    /// </summary>
-    /// <remarks>
-    /// This class provides implements the platform-independent parts of <see cref="IRenderTarget"/>.
-    /// </remarks>
-    [SuppressMessage("ReSharper", "LoopCanBeConvertedToQuery")]
-    [SuppressMessage("ReSharper", "ForCanBeConvertedToForeach")]
-    public static class RendererMixin
-    {
-        private static int s_frameNum;
-        private static int s_fps;
-        private static int s_currentFrames;
-        private static TimeSpan s_lastMeasure;
-        private static readonly Stopwatch s_stopwatch = Stopwatch.StartNew();
-        private static readonly Stack<List<IVisual>> s_listPool = new Stack<List<IVisual>>();
-        private static readonly ZIndexComparer s_visualComparer = new ZIndexComparer();
-
-        /// <summary>
-        /// Gets or sets a value which determines whether an FPS counted will be drawn on each
-        /// rendered frame.
-        /// </summary>
-        public static bool DrawFpsCounter { get; set; }
-
-        /// <summary>
-        /// Renders the specified visual.
-        /// </summary>
-        /// <param name="renderTarget">IRenderer instance</param>
-        /// <param name="visual">The visual to render.</param>
-        public static void Render(this IRenderTarget renderTarget, IVisual visual)
-        {
-            using (var ctx = new DrawingContext(renderTarget.CreateDrawingContext()))
-            {
-                ctx.Render(visual);
-                s_frameNum++;
-                if (DrawFpsCounter)
-                {
-                    s_currentFrames++;
-                    var now = s_stopwatch.Elapsed;
-                    var elapsed = now - s_lastMeasure;
-                    if (elapsed.TotalSeconds > 1)
-                    {
-                        s_fps = (int)(s_currentFrames / elapsed.TotalSeconds);
-                        s_currentFrames = 0;
-                        s_lastMeasure = now;
-                    }
-                    var pt = new Point(40, 40);
-                    var txt = new FormattedText(
-                        "Frame #" + s_frameNum + " FPS: " + s_fps,
-                        "Arial",
-                        18,
-                        Size.Infinity,
-                        FontStyle.Normal,
-                        TextAlignment.Left,
-                        FontWeight.Normal,
-                        TextWrapping.NoWrap);
-                    ctx.FillRectangle(Brushes.White, new Rect(pt, txt.Measure()));
-                    ctx.DrawText(Brushes.Black, pt, txt);
-                }
-            }
-        }
-
-        /// <summary>
-        /// Renders the specified visual.
-        /// </summary>
-        /// <param name="visual">The visual to render.</param>
-        /// <param name="context">The drawing context.</param>
-        public static void Render(this DrawingContext context, IVisual visual)
-        {
-            context.Render(visual, visual.Bounds);
-        }
-
-        /// <summary>
-        /// Renders the specified visual.
-        /// </summary>
-        /// <param name="visual">The visual to render.</param>
-        /// <param name="context">The drawing context.</param>
-        /// <param name="clipRect">
-        /// The current clip rect, in coordinates relative to <paramref name="visual"/>.
-        /// </param>
-        private static void Render(this DrawingContext context, IVisual visual, Rect clipRect)
-        {
-            var opacity = visual.Opacity;
-            var clipToBounds = visual.ClipToBounds;
-            var bounds = new Rect(visual.Bounds.Size);
-
-            if (visual.IsVisible && opacity > 0)
-            {
-                var m = Matrix.CreateTranslation(visual.Bounds.Position);
-
-                var renderTransform = Matrix.Identity;
-
-                if (visual.RenderTransform != null)
-                {
-                    var origin = visual.RenderTransformOrigin.ToPixels(new Size(visual.Bounds.Width, visual.Bounds.Height));
-                    var offset = Matrix.CreateTranslation(origin);
-                    renderTransform = (-offset) * visual.RenderTransform.Value * (offset);
-                }
-
-                m = renderTransform * m;
-
-                if (clipToBounds)
-                {
-                    clipRect = clipRect.Intersect(new Rect(visual.Bounds.Size));
-                }
-
-                using (context.PushPostTransform(m))
-                using (context.PushOpacity(opacity))
-                using (clipToBounds ? context.PushClip(bounds) : default(DrawingContext.PushedState))
-                using (visual.Clip != null ? context.PushGeometryClip(visual.Clip) : default(DrawingContext.PushedState))
-                using (visual.OpacityMask != null ? context.PushOpacityMask(visual.OpacityMask, bounds) : default(DrawingContext.PushedState))
-                using (context.PushTransformContainer())
-                {
-                    visual.Render(context);
-
-#pragma warning disable 0618
-                    var transformed =
-                        new TransformedBounds(bounds, new Rect(), context.CurrentContainerTransform);
-#pragma warning restore 0618
-
-                    if (visual is Visual)
-                    {
-                        BoundsTracker.SetTransformedBounds((Visual)visual, transformed);
-                    }
-
-                    var lst = GetSortedVisualList(visual.VisualChildren);
-
-                    foreach (var child in lst)
-                    {
-                        var childBounds = GetTransformedBounds(child);
-
-                        if (!child.ClipToBounds || clipRect.Intersects(childBounds))
-                        {
-                            var childClipRect = clipRect.Translate(-childBounds.Position);
-                            context.Render(child, childClipRect);
-                        }
-                        else
-                        {
-                            ClearTransformedBounds(child);
-                        }
-                    }
-
-                    ReturnListToPool(lst);
-                }
-            }
-            
-            if (!visual.IsVisible)
-            {
-                ClearTransformedBounds(visual);
-            }
-        }
-
-        private static void ClearTransformedBounds(IVisual visual)
-        {
-            foreach (var e in visual.GetSelfAndVisualDescendents())
-            {
-                BoundsTracker.SetTransformedBounds((Visual)visual, null);
-            }
-        }
-
-        private static void ReturnListToPool(List<IVisual> lst)
-        {
-            lst.Clear();
-            s_listPool.Push(lst);
-        }
-
-        private static List<IVisual> GetSortedVisualList(IReadOnlyList<IVisual> source)
-        {
-            var lst = s_listPool.Count == 0 ? new List<IVisual>() : s_listPool.Pop();
-            for (var c = 0; c < source.Count; c++)
-                lst.Add(source[c]);
-            lst.Sort(s_visualComparer);
-            return lst;
-        }
-
-        private static Rect GetTransformedBounds(IVisual visual)
-        {
-            if (visual.RenderTransform == null)
-            {
-                return visual.Bounds;
-            }
-            else
-            {
-                var origin = visual.RenderTransformOrigin.ToPixels(new Size(visual.Bounds.Width, visual.Bounds.Height));
-                var offset = Matrix.CreateTranslation(visual.Bounds.Position + origin);
-                var m = (-offset) * visual.RenderTransform.Value * (offset);
-                return visual.Bounds.TransformToAABB(m);
-            }
-        }
-
-        class ZIndexComparer : IComparer<IVisual>
-        {
-            public int Compare(IVisual x, IVisual y) => x.ZIndex.CompareTo(y.ZIndex);
-        }
-    }
-}

+ 1 - 1
src/Shared/RenderHelpers/TileBrushImplHelper.cs

@@ -104,7 +104,7 @@ namespace Avalonia.RenderHelpers
                 {
                 {
                     using (ctx.PushPostTransform(Matrix.CreateTranslation(-_visualBrush.Visual.Bounds.Position)))
                     using (ctx.PushPostTransform(Matrix.CreateTranslation(-_visualBrush.Visual.Bounds.Position)))
                     {
                     {
-                        ctx.Render(_visualBrush.Visual);
+                        Renderer.Render(_visualBrush.Visual, ctx);
                     }
                     }
                 }
                 }
             }
             }

+ 1 - 1
tests/Avalonia.Visuals.UnitTests/RenderTests_Culling.cs

@@ -162,7 +162,7 @@ namespace Avalonia.Visuals.UnitTests
             var ctx = CreateDrawingContext();
             var ctx = CreateDrawingContext();
             control.Measure(Size.Infinity);
             control.Measure(Size.Infinity);
             control.Arrange(new Rect(control.DesiredSize));
             control.Arrange(new Rect(control.DesiredSize));
-            ctx.Render(control);
+            ////ctx.Render(control);
         }
         }
 
 
         private DrawingContext CreateDrawingContext()
         private DrawingContext CreateDrawingContext()

+ 1 - 1
tests/Avalonia.Visuals.UnitTests/VisualTree/BoundsTrackerTests.cs

@@ -43,7 +43,7 @@ namespace Avalonia.Visuals.UnitTests.VisualTree
 
 
                 tree.Measure(Size.Infinity);
                 tree.Measure(Size.Infinity);
                 tree.Arrange(new Rect(0, 0, 100, 100));
                 tree.Arrange(new Rect(0, 0, 100, 100));
-                context.Render(tree);
+                ////context.Render(tree);
 
 
                 var track = target.Track(control);
                 var track = target.Track(control);
                 var results = new List<TransformedBounds?>();
                 var results = new List<TransformedBounds?>();

+ 1 - 1
tests/Avalonia.Visuals.UnitTests/VisualTree/VisualExtensionsTests_GetVisualsAt.cs

@@ -441,7 +441,7 @@ namespace Avalonia.Visuals.UnitTests.VisualTree
                 container.Arrange(new Rect(container.DesiredSize));
                 container.Arrange(new Rect(container.DesiredSize));
 
 
                 var context = new DrawingContext(Mock.Of<IDrawingContextImpl>());
                 var context = new DrawingContext(Mock.Of<IDrawingContextImpl>());
-                context.Render(container);
+                ////context.Render(container);
 
 
                 var result = container.GetVisualsAt(new Point(100, 100));
                 var result = container.GetVisualsAt(new Point(100, 100));
                 Assert.Equal(new[] { path }, result);
                 Assert.Equal(new[] { path }, result);