diff --git a/src/Gtk/Perspex.Cairo/CairoPlatform.cs b/src/Gtk/Perspex.Cairo/CairoPlatform.cs index 55da932a59..ba0d8881c1 100644 --- a/src/Gtk/Perspex.Cairo/CairoPlatform.cs +++ b/src/Gtk/Perspex.Cairo/CairoPlatform.cs @@ -36,9 +36,9 @@ namespace Perspex.Cairo return new FormattedTextImpl(s_pangoContext, text, fontFamily, fontSize, fontStyle, textAlignment, fontWeight); } - public IRenderer CreateRenderer(IPlatformHandle handle, double width, double height) + public IRenderTarget CreateRenderer(IPlatformHandle handle, double width, double height) { - return new Renderer(handle, width, height); + return new RenderTarget(handle, width, height); } public IRenderTargetBitmapImpl CreateRenderTargetBitmap(int width, int height) diff --git a/src/Gtk/Perspex.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs b/src/Gtk/Perspex.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs index db35a22775..0b9183d928 100644 --- a/src/Gtk/Perspex.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs +++ b/src/Gtk/Perspex.Cairo/Media/Imaging/RenderTargetBitmapImpl.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 Perspex.Media; using Perspex.Platform; +using Perspex.Rendering; namespace Perspex.Cairo.Media.Imaging { @@ -10,10 +12,12 @@ namespace Perspex.Cairo.Media.Imaging public class RenderTargetBitmapImpl : IRenderTargetBitmapImpl { + + private readonly RenderTarget _renderTarget; public RenderTargetBitmapImpl(Cairo.ImageSurface surface) { Surface = surface; - renderer = new Renderer(Surface); + _renderTarget = new RenderTarget(Surface); } public int PixelWidth => Surface.Width; @@ -22,7 +26,7 @@ namespace Perspex.Cairo.Media.Imaging public void Dispose() { - renderer.Dispose(); + _renderTarget.Dispose(); } public Cairo.ImageSurface Surface @@ -30,15 +34,19 @@ namespace Perspex.Cairo.Media.Imaging get; } - private Renderer renderer; - public void Render(IVisual visual) + public void Save(string fileName) { - renderer.Render(visual, new PlatformHandle(IntPtr.Zero, "RTB")); + Surface.WriteToPng(fileName); } - public void Save(string fileName) + public IDrawingContext CreateDrawingContext() { - Surface.WriteToPng(fileName); + return _renderTarget.CreateDrawingContext(); + } + + void IRenderTarget.Resize(int width, int height) + { + throw new NotSupportedException(); } } } \ No newline at end of file diff --git a/src/Gtk/Perspex.Cairo/Media/TileBrushes.cs b/src/Gtk/Perspex.Cairo/Media/TileBrushes.cs index e08565785a..fd1f457a95 100644 --- a/src/Gtk/Perspex.Cairo/Media/TileBrushes.cs +++ b/src/Gtk/Perspex.Cairo/Media/TileBrushes.cs @@ -7,6 +7,7 @@ using Perspex.Cairo.Media.Imaging; using Perspex.Layout; using Perspex.Media; using Perspex.Platform; +using Perspex.Rendering; namespace Perspex.Cairo.Media { @@ -110,12 +111,12 @@ namespace Perspex.Cairo.Media scale, translate, out drawRect); - var renderer = new Renderer(intermediate); + var renderer = new RenderTarget(intermediate); context.Rectangle(drawRect.ToCairo()); context.Clip(); context.Transform(transform.ToCairo()); - renderer.Render(visual, new PlatformHandle(IntPtr.Zero, "RTB"), transform, drawRect); + renderer.Render(visual, transform, drawRect); var result = new SurfacePattern(intermediate); diff --git a/src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj b/src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj index e389fac5b2..77deb8f6b3 100644 --- a/src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj +++ b/src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj @@ -61,7 +61,7 @@ - + diff --git a/src/Gtk/Perspex.Cairo/Renderer.cs b/src/Gtk/Perspex.Cairo/RenderTarget.cs similarity index 63% rename from src/Gtk/Perspex.Cairo/Renderer.cs rename to src/Gtk/Perspex.Cairo/RenderTarget.cs index 13bb63445f..b8de2e2166 100644 --- a/src/Gtk/Perspex.Cairo/Renderer.cs +++ b/src/Gtk/Perspex.Cairo/RenderTarget.cs @@ -13,24 +13,26 @@ namespace Perspex.Cairo using global::Cairo; /// - /// A cairo renderer. + /// A cairo render target. /// - public class Renderer : RendererBase + public class RenderTarget : IRenderTarget { + private readonly IPlatformHandle _handle; private readonly Surface _surface; private Gdk.Window _window; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The window handle. /// The width of the window. /// The height of the window. - public Renderer(IPlatformHandle handle, double width, double height) + public RenderTarget(IPlatformHandle handle, double width, double height) { + _handle = handle; } - public Renderer(ImageSurface surface) + public RenderTarget(ImageSurface surface) { _surface = surface; } @@ -40,7 +42,7 @@ namespace Perspex.Cairo /// /// The new width. /// The new height. - public override void Resize(int width, int height) + public void Resize(int width, int height) { // Don't need to do anything here. } @@ -49,33 +51,26 @@ namespace Perspex.Cairo /// /// Creates a cairo surface that targets a platform-specific resource. /// - /// The platform-specific handle. /// A surface wrapped in an . - protected override IDrawingContext CreateDrawingContext(IPlatformHandle handle) + public IDrawingContext CreateDrawingContext() { - switch (handle.HandleDescriptor) + if(_surface != null) + return new DrawingContext(_surface); + + switch (_handle.HandleDescriptor) { - case "RTB": - return new DrawingContext(_surface); case "GdkWindow": if (_window == null) - _window = new Gdk.Window(handle.Handle); + _window = new Gdk.Window(_handle.Handle); return new DrawingContext(_window); default: throw new NotSupportedException(string.Format( "Don't know how to create a Cairo renderer from a '{0}' handle", - handle.HandleDescriptor)); + _handle.HandleDescriptor)); } } - - [DllImport("user32.dll")] - private static extern IntPtr GetDC(IntPtr hwnd); - - public override void Dispose() - { - if (_surface != null) - _surface.Dispose(); - } + + public void Dispose() => _surface?.Dispose(); } } diff --git a/src/Gtk/Perspex.Gtk/WindowImpl.cs b/src/Gtk/Perspex.Gtk/WindowImpl.cs index 1914207d08..c6076a85f8 100644 --- a/src/Gtk/Perspex.Gtk/WindowImpl.cs +++ b/src/Gtk/Perspex.Gtk/WindowImpl.cs @@ -83,7 +83,7 @@ namespace Perspex.Gtk public Action Input { get; set; } - public Action Paint { get; set; } + public Action Paint { get; set; } public Action Resized { get; set; } @@ -223,7 +223,7 @@ namespace Perspex.Gtk protected override bool OnExposeEvent(EventExpose evnt) { - Paint(evnt.Area.ToPerspex(), GetHandle(evnt.Window)); + Paint(evnt.Area.ToPerspex()); return true; } diff --git a/src/Perspex.Application/Application.cs b/src/Perspex.Application/Application.cs index f0a3c1a8ee..88f3a23ffe 100644 --- a/src/Perspex.Application/Application.cs +++ b/src/Perspex.Application/Application.cs @@ -168,7 +168,7 @@ namespace Perspex .Bind().ToTransient() .Bind().ToConstant(_styler) .Bind().ToTransient() - .Bind().ToTransient(); + .Bind().ToTransient(); } /// diff --git a/src/Perspex.Controls/Perspex.Controls.csproj b/src/Perspex.Controls/Perspex.Controls.csproj index 12a8f6f7e6..f29b366032 100644 --- a/src/Perspex.Controls/Perspex.Controls.csproj +++ b/src/Perspex.Controls/Perspex.Controls.csproj @@ -43,6 +43,7 @@ + diff --git a/src/Perspex.Controls/Platform/ITopLevelImpl.cs b/src/Perspex.Controls/Platform/ITopLevelImpl.cs index 1cbc5f7c60..053c340b27 100644 --- a/src/Perspex.Controls/Platform/ITopLevelImpl.cs +++ b/src/Perspex.Controls/Platform/ITopLevelImpl.cs @@ -22,7 +22,7 @@ namespace Perspex.Platform Action Input { get; set; } - Action Paint { get; set; } + Action Paint { get; set; } Action Resized { get; set; } diff --git a/src/Perspex.Controls/Platform/ITopLevelRenderer.cs b/src/Perspex.Controls/Platform/ITopLevelRenderer.cs new file mode 100644 index 0000000000..fa71860f7d --- /dev/null +++ b/src/Perspex.Controls/Platform/ITopLevelRenderer.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Perspex.Platform; +using Perspex.Rendering; + +namespace Perspex.Controls.Platform +{ + public interface ITopLevelRenderer + { + void Attach(TopLevel topLevel); + } + + + class DefaultTopLevelRenderer : ITopLevelRenderer + { + + public void Attach(TopLevel topLevel) + { + var resources = new List(); + var initialClientSize = topLevel.PlatformImpl.ClientSize; + + + var queueManager = ((IRenderRoot)topLevel).RenderQueueManager; + + if (queueManager == null) + return; + + var platformRender = PerspexLocator.Current.GetService(); + if(platformRender == null) + return; + + var viewport = platformRender + .CreateRenderer(topLevel.PlatformImpl.Handle, initialClientSize.Width, initialClientSize.Height); + resources.Add(viewport); + + + resources.Add(topLevel.GetObservable(TopLevel.ClientSizeProperty).Subscribe(clientSize => + { + viewport.Resize((int) clientSize.Width, (int) clientSize.Height); + })); + resources.Add(queueManager.RenderNeeded.Subscribe(_ + => topLevel.PlatformImpl.Invalidate(new Rect(topLevel.ClientSize)))); + + topLevel.PlatformImpl.Paint = rect => + { + viewport.Render(topLevel); + queueManager.RenderFinished(); + }; + + topLevel.Closed += delegate + { + foreach (var disposable in resources) + disposable.Dispose(); + resources.Clear(); + }; + + } + } +} diff --git a/src/Perspex.Controls/TopLevel.cs b/src/Perspex.Controls/TopLevel.cs index 5936e08404..1c0ac1e525 100644 --- a/src/Perspex.Controls/TopLevel.cs +++ b/src/Perspex.Controls/TopLevel.cs @@ -4,6 +4,7 @@ using System; using System.Reactive.Disposables; using System.Reactive.Linq; +using Perspex.Controls.Platform; using Perspex.Controls.Primitives; using Perspex.Input; using Perspex.Input.Raw; @@ -43,8 +44,8 @@ namespace Perspex.Controls public static readonly PerspexProperty PointerOverElementProperty = PerspexProperty.Register(nameof(IInputRoot.PointerOverElement)); - private readonly IRenderManager _renderManager; - private readonly IRenderer _renderer; + private readonly IRenderQueueManager _renderQueueManager; + private readonly IRenderTarget _renderTarget; private readonly IInputManager _inputManager; private readonly IAccessKeyHandler _accessKeyHandler; private readonly IKeyboardNavigationHandler _keyboardNavigationHandler; @@ -92,21 +93,21 @@ namespace Perspex.Controls _inputManager = TryGetService(dependencyResolver); _keyboardNavigationHandler = TryGetService(dependencyResolver); LayoutManager = TryGetService(dependencyResolver); - _renderManager = TryGetService(dependencyResolver); + _renderQueueManager = TryGetService(dependencyResolver); + (TryGetService(dependencyResolver) ?? new DefaultTopLevelRenderer()).Attach(this); PlatformImpl.SetInputRoot(this); PlatformImpl.Activated = HandleActivated; PlatformImpl.Deactivated = HandleDeactivated; PlatformImpl.Closed = HandleClosed; PlatformImpl.Input = HandleInput; - PlatformImpl.Paint = HandlePaint; PlatformImpl.Resized = HandleResized; Size clientSize = ClientSize = PlatformImpl.ClientSize; if (renderInterface != null) { - _renderer = renderInterface.CreateRenderer(PlatformImpl.Handle, clientSize.Width, clientSize.Height); + _renderTarget = renderInterface.CreateRenderer(PlatformImpl.Handle, clientSize.Width, clientSize.Height); } if (LayoutManager != null) @@ -116,11 +117,6 @@ namespace Perspex.Controls LayoutManager.LayoutCompleted.Subscribe(_ => HandleLayoutCompleted()); } - if (_renderManager != null) - { - _renderManager.RenderNeeded.Subscribe(_ => HandleRenderNeeded()); - } - if (_keyboardNavigationHandler != null) { _keyboardNavigationHandler.SetOwner(this); @@ -188,16 +184,11 @@ namespace Perspex.Controls { get; } - - /// - /// Gets the window renderer. - /// - IRenderer IRenderRoot.Renderer => _renderer; - + /// /// Gets the window render manager. /// - IRenderManager IRenderRoot.RenderManager => _renderManager; + IRenderQueueManager IRenderRoot.RenderQueueManager => _renderQueueManager; /// /// Gets the access key handler for the window. @@ -297,7 +288,6 @@ namespace Perspex.Controls } ClientSize = clientSize; - _renderer.Resize((int)clientSize.Width, (int)clientSize.Height); LayoutManager.ExecuteLayoutPass(); PlatformImpl.Invalidate(new Rect(clientSize)); } @@ -389,28 +379,7 @@ namespace Perspex.Controls /// private void HandleLayoutCompleted() { - _renderManager?.InvalidateRender(this); - } - - /// - /// Handles a render request from . - /// - private void HandleRenderNeeded() - { - Dispatcher.UIThread.InvokeAsync( - () => PlatformImpl.Invalidate(new Rect(ClientSize)), - DispatcherPriority.Render); - } - - /// - /// Handles a paint request from . - /// - /// The rectangle to paint. - /// An optional platform-specific handle. - private void HandlePaint(Rect rect, IPlatformHandle handle) - { - _renderer.Render(this, handle); - _renderManager.RenderFinished(); + _renderQueueManager?.InvalidateRender(this); } } } diff --git a/src/Perspex.SceneGraph/Media/Imaging/RenderTargetBitmap.cs b/src/Perspex.SceneGraph/Media/Imaging/RenderTargetBitmap.cs index 90b83dff6b..5b8bbea6da 100644 --- a/src/Perspex.SceneGraph/Media/Imaging/RenderTargetBitmap.cs +++ b/src/Perspex.SceneGraph/Media/Imaging/RenderTargetBitmap.cs @@ -3,13 +3,14 @@ using System; using Perspex.Platform; +using Perspex.Rendering; namespace Perspex.Media.Imaging { /// /// A bitmap that holds the rendering of a . /// - public class RenderTargetBitmap : Bitmap, IDisposable + public class RenderTargetBitmap : Bitmap, IDisposable, IRenderTarget { /// /// Initializes a new instance of the class. @@ -26,18 +27,6 @@ namespace Perspex.Media.Imaging /// public new IRenderTargetBitmapImpl PlatformImpl => (IRenderTargetBitmapImpl)base.PlatformImpl; - /// - /// Renders an into the bitmap. - /// - /// The visual to render. - /// - /// Before calling this method, ensure that has been measured. - /// - public void Render(IVisual visual) - { - PlatformImpl.Render(visual); - } - /// /// Disposes of the bitmap. /// @@ -57,5 +46,12 @@ namespace Perspex.Media.Imaging IPlatformRenderInterface factory = PerspexLocator.Current.GetService(); return factory.CreateRenderTargetBitmap(width, height); } + + public IDrawingContext CreateDrawingContext() => PlatformImpl.CreateDrawingContext(); + + void IRenderTarget.Resize(int width, int height) + { + throw new NotSupportedException(); + } } } diff --git a/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj b/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj index 4b8c5c3778..7824b398e6 100644 --- a/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj +++ b/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj @@ -105,7 +105,7 @@ - + @@ -114,9 +114,9 @@ - + - + diff --git a/src/Perspex.SceneGraph/Platform/IPlatformRenderInterface.cs b/src/Perspex.SceneGraph/Platform/IPlatformRenderInterface.cs index ca40ec8137..e79da32923 100644 --- a/src/Perspex.SceneGraph/Platform/IPlatformRenderInterface.cs +++ b/src/Perspex.SceneGraph/Platform/IPlatformRenderInterface.cs @@ -49,8 +49,8 @@ namespace Perspex.Platform /// The platform handle for the renderer. /// The initial width of the render. /// The initial height of the render. - /// An . - IRenderer CreateRenderer(IPlatformHandle handle, double width, double height); + /// An . + IRenderTarget CreateRenderer(IPlatformHandle handle, double width, double height); /// /// Creates a render target bitmap implementation. diff --git a/src/Perspex.SceneGraph/Platform/IRenderTarget.cs b/src/Perspex.SceneGraph/Platform/IRenderTarget.cs new file mode 100644 index 0000000000..fdbf391a05 --- /dev/null +++ b/src/Perspex.SceneGraph/Platform/IRenderTarget.cs @@ -0,0 +1,29 @@ +// Copyright (c) The Perspex Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Perspex.Media; + +namespace Perspex.Platform +{ + /// + /// Defines a render target + /// + /// + /// The interface used for obtaining drawing context from surfaces you can render on. + /// + public interface IRenderTarget : IDisposable + { + /// + /// Creates an for a rendering session. + /// + IDrawingContext CreateDrawingContext(); + + /// + /// Resizes the rendered viewport. + /// + /// The new width. + /// The new height. + void Resize(int width, int height); + } +} diff --git a/src/Perspex.SceneGraph/Platform/IRenderTargetBitmapImpl.cs b/src/Perspex.SceneGraph/Platform/IRenderTargetBitmapImpl.cs index 9e1b0e6cdd..679e243664 100644 --- a/src/Perspex.SceneGraph/Platform/IRenderTargetBitmapImpl.cs +++ b/src/Perspex.SceneGraph/Platform/IRenderTargetBitmapImpl.cs @@ -9,15 +9,7 @@ namespace Perspex.Platform /// Defines the platform-specific interface for a /// . /// - public interface IRenderTargetBitmapImpl : IBitmapImpl, IDisposable + public interface IRenderTargetBitmapImpl : IBitmapImpl, IRenderTarget { - /// - /// Renders an into the bitmap. - /// - /// The visual to render. - /// - /// Before calling this method, ensure that has been measured. - /// - void Render(IVisual visual); } } diff --git a/src/Perspex.SceneGraph/Platform/IRenderer.cs b/src/Perspex.SceneGraph/Platform/IRenderer.cs deleted file mode 100644 index e1e0f31e21..0000000000 --- a/src/Perspex.SceneGraph/Platform/IRenderer.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex.Platform -{ - /// - /// Defines a renderer. - /// - /// - /// The interface used to render s. You will usually want to inherit from - /// rather than implementing the whole interface - /// as RenderBase has a default implementation for the non-platform specific parts of a - /// renderer. - /// - public interface IRenderer : IDisposable - { - /// - /// Gets the number of times has been called. - /// - int RenderCount { get; } - - /// - /// Renders the specified visual. - /// - /// The visual to render. - /// An optional platform-specific handle. - void Render(IVisual visual, IPlatformHandle handle); - - /// - /// Resizes the rendered viewport. - /// - /// The new width. - /// The new height. - void Resize(int width, int height); - } -} diff --git a/src/Perspex.SceneGraph/Rendering/IRenderManager.cs b/src/Perspex.SceneGraph/Rendering/IRenderQueueManager.cs similarity index 88% rename from src/Perspex.SceneGraph/Rendering/IRenderManager.cs rename to src/Perspex.SceneGraph/Rendering/IRenderQueueManager.cs index cb03a8a19a..a583bcbc85 100644 --- a/src/Perspex.SceneGraph/Rendering/IRenderManager.cs +++ b/src/Perspex.SceneGraph/Rendering/IRenderQueueManager.cs @@ -7,9 +7,9 @@ using System.Reactive; namespace Perspex.Rendering { /// - /// Defines the interface for a . + /// Defines the interface for a . /// - public interface IRenderManager + public interface IRenderQueueManager { /// /// Gets an observable that is fired whenever a render is required. diff --git a/src/Perspex.SceneGraph/Rendering/IRenderRoot.cs b/src/Perspex.SceneGraph/Rendering/IRenderRoot.cs index a6f5846f75..406eedbc3b 100644 --- a/src/Perspex.SceneGraph/Rendering/IRenderRoot.cs +++ b/src/Perspex.SceneGraph/Rendering/IRenderRoot.cs @@ -10,15 +10,10 @@ namespace Perspex.Rendering /// public interface IRenderRoot { - /// - /// Gets the renderer for the tree. - /// - IRenderer Renderer { get; } - /// /// Gets the render manager which schedules renders. /// - IRenderManager RenderManager { get; } + IRenderQueueManager RenderQueueManager { get; } /// /// Translates a point to screen co-ordinates. diff --git a/src/Perspex.SceneGraph/Rendering/RenderManager.cs b/src/Perspex.SceneGraph/Rendering/RenderQueueManager.cs similarity index 96% rename from src/Perspex.SceneGraph/Rendering/RenderManager.cs rename to src/Perspex.SceneGraph/Rendering/RenderQueueManager.cs index 8f89c6d31f..514bb547a6 100644 --- a/src/Perspex.SceneGraph/Rendering/RenderManager.cs +++ b/src/Perspex.SceneGraph/Rendering/RenderQueueManager.cs @@ -10,7 +10,7 @@ namespace Perspex.Rendering /// /// Schedules the rendering of a tree. /// - public class RenderManager : IRenderManager + public class RenderQueueManager : IRenderQueueManager { private readonly Subject _renderNeeded = new Subject(); diff --git a/src/Perspex.SceneGraph/Rendering/RendererBase.cs b/src/Perspex.SceneGraph/Rendering/RendererBase.cs index 26a5a9437a..c9f79b2669 100644 --- a/src/Perspex.SceneGraph/Rendering/RendererBase.cs +++ b/src/Perspex.SceneGraph/Rendering/RendererBase.cs @@ -12,63 +12,73 @@ namespace Perspex.Rendering /// Base class for standard renderers. /// /// - /// This class provides implements the platform-independent parts of . + /// This class provides implements the platform-independent parts of . /// - public abstract class RendererBase : IRenderer + public static class RendererMixin { /// - /// Gets the number of times has been called. + /// Renders the specified visual. /// - public int RenderCount + /// IRenderer instance + /// The visual to render. + public static void Render(this IRenderTarget renderTarget, IVisual visual) { - get; - private set; + using (var ctx = renderTarget.CreateDrawingContext()) + ctx.Render(visual); } - public abstract void Dispose(); - /// /// Renders the specified visual. /// + /// IRenderer instance /// The visual to render. - /// An optional platform-specific handle. - public virtual void Render(IVisual visual, IPlatformHandle handle) + /// The current translation. + /// The current transform. + public static void Render(this IRenderTarget renderTarget, IVisual visual, Matrix translation, Matrix transform) { - Render(visual, handle, Matrix.Identity); - ++RenderCount; + using (var ctx = renderTarget.CreateDrawingContext()) + ctx.Render(visual, translation, transform); } /// /// Renders the specified visual with the specified transform and clip. /// + /// IRenderer instance /// The visual to render. - /// An optional platform-specific handle. /// The transform. /// An optional clip rectangle. - public virtual void Render(IVisual visual, IPlatformHandle handle, Matrix transform, Rect? clip = null) + public static void Render(this IRenderTarget renderTarget, IVisual visual, Matrix transform, Rect? clip = null) { - using (var context = CreateDrawingContext(handle)) - using (clip.HasValue ? context.PushClip(clip.Value) : null) - { - Render(visual, context, Matrix.Identity, transform); - } + using (var context = renderTarget.CreateDrawingContext()) + context.Render(visual, transform, clip); } /// - /// Resizes the rendered viewport. + /// Renders the specified visual. /// - /// The new width. - /// The new height. - public abstract void Resize(int width, int height); + /// The visual to render. + /// + /// The drawing context. + public static void Render(this IDrawingContext context, IVisual visual) + { + context.Render(visual, Matrix.Identity); + } /// - /// When overriden by a derived class creates an for a - /// rendering session. + /// Renders the specified visual with the specified transform and clip. /// - /// The handle to use to create the context. - /// An . - protected abstract IDrawingContext CreateDrawingContext(IPlatformHandle handle); - + /// The visual to render. + /// The drawing context. + /// The transform. + /// An optional clip rectangle. + public static void Render(this IDrawingContext context, IVisual visual, Matrix transform, Rect? clip = null) + { + using (clip.HasValue ? context.PushClip(clip.Value) : null) + { + context.Render(visual, Matrix.Identity, transform); + } + } + /// /// Renders the specified visual. /// @@ -76,7 +86,7 @@ namespace Perspex.Rendering /// The drawing context. /// The current translation. /// The current transform. - protected virtual void Render(IVisual visual, IDrawingContext context, Matrix translation, Matrix transform) + public static void Render(this IDrawingContext context, IVisual visual, Matrix translation, Matrix transform) { var opacity = visual.Opacity; @@ -108,7 +118,7 @@ namespace Perspex.Rendering foreach (var child in visual.VisualChildren.OrderBy(x => x.ZIndex)) { - Render(child, context, translation, transform); + context.Render(child, translation, transform); } } } diff --git a/src/Perspex.SceneGraph/Visual.cs b/src/Perspex.SceneGraph/Visual.cs index 46020d8e07..e835c6a76c 100644 --- a/src/Perspex.SceneGraph/Visual.cs +++ b/src/Perspex.SceneGraph/Visual.cs @@ -22,7 +22,7 @@ namespace Perspex /// /// /// The class acts as a node in the Perspex scene graph and holds - /// all the information needed for an to render the control. + /// all the information needed for an to render the control. /// To traverse the scene graph (aka Visual Tree), use the extension methods defined /// in . /// @@ -222,9 +222,9 @@ namespace Perspex .OfType() .FirstOrDefault(); - if (root != null && root.RenderManager != null) + if (root != null && root.RenderQueueManager != null) { - root.RenderManager.InvalidateRender(this); + root.RenderQueueManager.InvalidateRender(this); } } diff --git a/src/Windows/Perspex.Direct2D1/Direct2D1Platform.cs b/src/Windows/Perspex.Direct2D1/Direct2D1Platform.cs index 9005a9ffe3..fef168bd27 100644 --- a/src/Windows/Perspex.Direct2D1/Direct2D1Platform.cs +++ b/src/Windows/Perspex.Direct2D1/Direct2D1Platform.cs @@ -41,11 +41,11 @@ namespace Perspex.Direct2D1 return new FormattedTextImpl(text, fontFamily, fontSize, fontStyle, textAlignment, fontWeight); } - public IRenderer CreateRenderer(IPlatformHandle handle, double width, double height) + public IRenderTarget CreateRenderer(IPlatformHandle handle, double width, double height) { if (handle.HandleDescriptor == "HWND") { - return new Renderer(handle.Handle, width, height); + return new RenderTarget(handle.Handle, width, height); } else { diff --git a/src/Windows/Perspex.Direct2D1/Media/DrawingContext.cs b/src/Windows/Perspex.Direct2D1/Media/DrawingContext.cs index 039f6c30e0..0b6abe9353 100644 --- a/src/Windows/Perspex.Direct2D1/Media/DrawingContext.cs +++ b/src/Windows/Perspex.Direct2D1/Media/DrawingContext.cs @@ -18,7 +18,7 @@ namespace Perspex.Direct2D1.Media /// /// The Direct2D1 render target. /// - private readonly RenderTarget _renderTarget; + private readonly SharpDX.Direct2D1.RenderTarget _renderTarget; /// /// The DirectWrite factory. @@ -31,7 +31,7 @@ namespace Perspex.Direct2D1.Media /// The render target to draw to. /// The DirectWrite factory. public DrawingContext( - RenderTarget renderTarget, + SharpDX.Direct2D1.RenderTarget renderTarget, SharpDX.DirectWrite.Factory directWriteFactory) { _renderTarget = renderTarget; diff --git a/src/Windows/Perspex.Direct2D1/Media/ImageBrushImpl.cs b/src/Windows/Perspex.Direct2D1/Media/ImageBrushImpl.cs index bbadb758c4..c518b6438f 100644 --- a/src/Windows/Perspex.Direct2D1/Media/ImageBrushImpl.cs +++ b/src/Windows/Perspex.Direct2D1/Media/ImageBrushImpl.cs @@ -11,7 +11,7 @@ namespace Perspex.Direct2D1.Media { public ImageBrushImpl( ImageBrush brush, - RenderTarget target, + SharpDX.Direct2D1.RenderTarget target, Size targetSize) { if (brush.Source == null) @@ -59,7 +59,7 @@ namespace Perspex.Direct2D1.Media private BitmapBrush CreateDirectBrush( ImageBrush brush, - RenderTarget target, + SharpDX.Direct2D1.RenderTarget target, Bitmap image, Rect sourceRect, Rect destinationRect) diff --git a/src/Windows/Perspex.Direct2D1/Media/Imaging/RenderTargetBitmapImpl.cs b/src/Windows/Perspex.Direct2D1/Media/Imaging/RenderTargetBitmapImpl.cs index 51f7a71cca..97efa00d47 100644 --- a/src/Windows/Perspex.Direct2D1/Media/Imaging/RenderTargetBitmapImpl.cs +++ b/src/Windows/Perspex.Direct2D1/Media/Imaging/RenderTargetBitmapImpl.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 Perspex.Media; using Perspex.Platform; +using Perspex.Rendering; using SharpDX.Direct2D1; using SharpDX.WIC; @@ -36,10 +38,11 @@ namespace Perspex.Direct2D1.Media // TODO: } - public void Render(IVisual visual) + public IDrawingContext CreateDrawingContext() => new RenderTarget(_target).CreateDrawingContext(); + + void IRenderTarget.Resize(int width, int height) { - Renderer renderer = new Renderer(_target); - renderer.Render(visual, null); + throw new NotSupportedException(); } } } diff --git a/src/Windows/Perspex.Direct2D1/Media/PerspexTextRenderer.cs b/src/Windows/Perspex.Direct2D1/Media/PerspexTextRenderer.cs index dbd56cfa4d..297dcdb581 100644 --- a/src/Windows/Perspex.Direct2D1/Media/PerspexTextRenderer.cs +++ b/src/Windows/Perspex.Direct2D1/Media/PerspexTextRenderer.cs @@ -12,13 +12,13 @@ namespace Perspex.Direct2D1.Media { private readonly DrawingContext _context; - private readonly RenderTarget _renderTarget; + private readonly SharpDX.Direct2D1.RenderTarget _renderTarget; private readonly Brush _foreground; public PerspexTextRenderer( DrawingContext context, - RenderTarget target, + SharpDX.Direct2D1.RenderTarget target, Brush foreground) { _context = context; diff --git a/src/Windows/Perspex.Direct2D1/Media/VisualBrushImpl.cs b/src/Windows/Perspex.Direct2D1/Media/VisualBrushImpl.cs index bc049e7ca3..c57c2b1477 100644 --- a/src/Windows/Perspex.Direct2D1/Media/VisualBrushImpl.cs +++ b/src/Windows/Perspex.Direct2D1/Media/VisualBrushImpl.cs @@ -4,6 +4,7 @@ using System; using Perspex.Layout; using Perspex.Media; +using Perspex.Rendering; using SharpDX.Direct2D1; namespace Perspex.Direct2D1.Media @@ -12,7 +13,7 @@ namespace Perspex.Direct2D1.Media { public VisualBrushImpl( VisualBrush brush, - RenderTarget target, + SharpDX.Direct2D1.RenderTarget target, Size targetSize) { var visual = brush.Visual; @@ -50,9 +51,9 @@ namespace Perspex.Direct2D1.Media scale, translate, out drawRect); - var renderer = new Renderer(intermediate); + var renderer = new RenderTarget(intermediate); - renderer.Render(visual, null, transform, drawRect); + renderer.Render(visual, transform, drawRect); this.PlatformBrush = new BitmapBrush( target, diff --git a/src/Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj b/src/Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj index f352a6d7a8..0f4ec68289 100644 --- a/src/Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj +++ b/src/Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj @@ -89,7 +89,7 @@ - + diff --git a/src/Windows/Perspex.Direct2D1/PrimitiveExtensions.cs b/src/Windows/Perspex.Direct2D1/PrimitiveExtensions.cs index 2364521ed0..fac270dd7c 100644 --- a/src/Windows/Perspex.Direct2D1/PrimitiveExtensions.cs +++ b/src/Windows/Perspex.Direct2D1/PrimitiveExtensions.cs @@ -69,7 +69,7 @@ namespace Perspex.Direct2D1 /// The pen to convert. /// The render target. /// The Direct2D brush. - public static StrokeStyle ToDirect2DStrokeStyle(this Perspex.Media.Pen pen, RenderTarget target) + public static StrokeStyle ToDirect2DStrokeStyle(this Perspex.Media.Pen pen, SharpDX.Direct2D1.RenderTarget target) { if (pen.DashStyle != null) { diff --git a/src/Windows/Perspex.Direct2D1/Renderer.cs b/src/Windows/Perspex.Direct2D1/RenderTarget.cs similarity index 83% rename from src/Windows/Perspex.Direct2D1/Renderer.cs rename to src/Windows/Perspex.Direct2D1/RenderTarget.cs index b112dfea65..ea6400be80 100644 --- a/src/Windows/Perspex.Direct2D1/Renderer.cs +++ b/src/Windows/Perspex.Direct2D1/RenderTarget.cs @@ -12,20 +12,20 @@ using DwFactory = SharpDX.DirectWrite.Factory; namespace Perspex.Direct2D1 { - public class Renderer : RendererBase + public class RenderTarget : IRenderTarget { /// /// The render target. /// - private readonly RenderTarget _renderTarget; + private readonly SharpDX.Direct2D1.RenderTarget _renderTarget; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The window handle. /// The width of the window. /// The height of the window. - public Renderer(IntPtr hwnd, double width, double height) + public RenderTarget(IntPtr hwnd, double width, double height) { Direct2DFactory = PerspexLocator.Current.GetService(); DirectWriteFactory = PerspexLocator.Current.GetService(); @@ -48,10 +48,10 @@ namespace Perspex.Direct2D1 } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The render target. - public Renderer(RenderTarget renderTarget) + public RenderTarget(SharpDX.Direct2D1.RenderTarget renderTarget) { Direct2DFactory = PerspexLocator.Current.GetService(); DirectWriteFactory = PerspexLocator.Current.GetService(); @@ -77,7 +77,7 @@ namespace Perspex.Direct2D1 /// /// The new width. /// The new height. - public override void Resize(int width, int height) + public void Resize(int width, int height) { WindowRenderTarget window = _renderTarget as WindowRenderTarget; @@ -94,14 +94,13 @@ namespace Perspex.Direct2D1 /// /// Creates a drawing context for a rendering session. /// - /// The platform handle. Unused. /// An . - protected override IDrawingContext CreateDrawingContext(IPlatformHandle handle) + public IDrawingContext CreateDrawingContext() { return new DrawingContext(_renderTarget, DirectWriteFactory); } - public override void Dispose() + public void Dispose() { _renderTarget.Dispose(); } diff --git a/src/Windows/Perspex.Win32/WindowImpl.cs b/src/Windows/Perspex.Win32/WindowImpl.cs index fa3313c232..dda55f4757 100644 --- a/src/Windows/Perspex.Win32/WindowImpl.cs +++ b/src/Windows/Perspex.Win32/WindowImpl.cs @@ -51,7 +51,7 @@ namespace Perspex.Win32 public Action Input { get; set; } - public Action Paint { get; set; } + public Action Paint { get; set; } public Action Resized { get; set; } @@ -405,7 +405,7 @@ namespace Perspex.Win32 { UnmanagedMethods.RECT r; UnmanagedMethods.GetUpdateRect(_hwnd, out r, false); - Paint(new Rect(r.left, r.top, r.right - r.left, r.bottom - r.top), Handle); + Paint(new Rect(r.left, r.top, r.right - r.left, r.bottom - r.top)); UnmanagedMethods.EndPaint(_hwnd, ref ps); } } diff --git a/tests/Perspex.Controls.UnitTests/ControlTests.cs b/tests/Perspex.Controls.UnitTests/ControlTests.cs index 4a801fc0e9..d86733de3d 100644 --- a/tests/Perspex.Controls.UnitTests/ControlTests.cs +++ b/tests/Perspex.Controls.UnitTests/ControlTests.cs @@ -76,12 +76,12 @@ namespace Perspex.Controls.UnitTests get { throw new NotImplementedException(); } } - public IRenderer Renderer + public IRenderTarget RenderTarget { get { throw new NotImplementedException(); } } - public IRenderManager RenderManager + public IRenderQueueManager RenderQueueManager { get { throw new NotImplementedException(); } } diff --git a/tests/Perspex.Controls.UnitTests/TestRoot.cs b/tests/Perspex.Controls.UnitTests/TestRoot.cs index 6f564550d2..10973f7c9c 100644 --- a/tests/Perspex.Controls.UnitTests/TestRoot.cs +++ b/tests/Perspex.Controls.UnitTests/TestRoot.cs @@ -15,12 +15,12 @@ namespace Perspex.Controls.UnitTests public ILayoutManager LayoutManager => new Mock().Object; - public IRenderer Renderer + public IRenderTarget RenderTarget { get { throw new NotImplementedException(); } } - public IRenderManager RenderManager + public IRenderQueueManager RenderQueueManager { get { throw new NotImplementedException(); } } diff --git a/tests/Perspex.Controls.UnitTests/TopLevelTests.cs b/tests/Perspex.Controls.UnitTests/TopLevelTests.cs index 7c8f6a52b4..5b8c08e8e2 100644 --- a/tests/Perspex.Controls.UnitTests/TopLevelTests.cs +++ b/tests/Perspex.Controls.UnitTests/TopLevelTests.cs @@ -180,7 +180,7 @@ namespace Perspex.Controls.UnitTests var target = new TestTopLevel(impl.Object); completed.OnNext(Unit.Default); - var renderManagerMock = Mock.Get(PerspexLocator.Current.GetService()); + var renderManagerMock = Mock.Get(PerspexLocator.Current.GetService()); renderManagerMock.Verify(x => x.InvalidateRender(target)); } } @@ -313,7 +313,7 @@ namespace Perspex.Controls.UnitTests var globalStyles = new Mock(); var layoutManager = fixture.Create(); var renderInterface = fixture.Create(); - var renderManager = fixture.Create(); + var renderManager = fixture.Create(); var windowImpl = new Mock(); var theme = new Styles(); @@ -327,7 +327,7 @@ namespace Perspex.Controls.UnitTests .Bind().ToConstant(layoutManager) .Bind().ToConstant(renderInterface) .Bind().ToConstant(new Mock().Object) - .Bind().ToConstant(renderManager) + .Bind().ToConstant(renderManager) .Bind().ToConstant(new Styler()); } diff --git a/tests/Perspex.Layout.UnitTests/FullLayoutTests.cs b/tests/Perspex.Layout.UnitTests/FullLayoutTests.cs index fb714e5278..c9df6639cd 100644 --- a/tests/Perspex.Layout.UnitTests/FullLayoutTests.cs +++ b/tests/Perspex.Layout.UnitTests/FullLayoutTests.cs @@ -134,7 +134,7 @@ namespace Perspex.Layout.UnitTests var formattedText = fixture.Create(); var globalStyles = new Mock(); var renderInterface = fixture.Create(); - var renderManager = fixture.Create(); + var renderManager = fixture.Create(); var theme = new DefaultTheme(); var windowImpl = new Mock(); @@ -148,7 +148,7 @@ namespace Perspex.Layout.UnitTests .Bind().ToConstant(new LayoutManager()) .Bind().ToConstant(renderInterface) .Bind().ToConstant(new Mock().Object) - .Bind().ToConstant(renderManager) + .Bind().ToConstant(renderManager) .Bind().ToConstant(new Styler()) .Bind().ToConstant(windowImpl.Object); } diff --git a/tests/Perspex.RenderTests/TestBase.cs b/tests/Perspex.RenderTests/TestBase.cs index 2940c5ab31..7344d4d137 100644 Binary files a/tests/Perspex.RenderTests/TestBase.cs and b/tests/Perspex.RenderTests/TestBase.cs differ diff --git a/tests/Perspex.SceneGraph.UnitTests/TestRoot.cs b/tests/Perspex.SceneGraph.UnitTests/TestRoot.cs index 41215cfa08..99a1fd0d4a 100644 --- a/tests/Perspex.SceneGraph.UnitTests/TestRoot.cs +++ b/tests/Perspex.SceneGraph.UnitTests/TestRoot.cs @@ -9,12 +9,12 @@ namespace Perspex.SceneGraph.UnitTests { public class TestRoot : TestVisual, IRenderRoot { - public IRenderer Renderer + public IRenderTarget RenderTarget { get { throw new NotImplementedException(); } } - public IRenderManager RenderManager + public IRenderQueueManager RenderQueueManager { get { throw new NotImplementedException(); } }