Browse Source

Merge pull request #228 from kekekeks/render-refactor

Render-related changes needed for window multiplexing mode
droid
Nikita Tsukanov 11 years ago
parent
commit
10b5177173
  1. 4
      src/Gtk/Perspex.Cairo/CairoPlatform.cs
  2. 22
      src/Gtk/Perspex.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs
  3. 5
      src/Gtk/Perspex.Cairo/Media/TileBrushes.cs
  4. 2
      src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj
  5. 39
      src/Gtk/Perspex.Cairo/RenderTarget.cs
  6. 4
      src/Gtk/Perspex.Gtk/WindowImpl.cs
  7. 2
      src/Perspex.Application/Application.cs
  8. 1
      src/Perspex.Controls/Perspex.Controls.csproj
  9. 2
      src/Perspex.Controls/Platform/ITopLevelImpl.cs
  10. 62
      src/Perspex.Controls/Platform/ITopLevelRenderer.cs
  11. 49
      src/Perspex.Controls/TopLevel.cs
  12. 22
      src/Perspex.SceneGraph/Media/Imaging/RenderTargetBitmap.cs
  13. 6
      src/Perspex.SceneGraph/Perspex.SceneGraph.csproj
  14. 4
      src/Perspex.SceneGraph/Platform/IPlatformRenderInterface.cs
  15. 29
      src/Perspex.SceneGraph/Platform/IRenderTarget.cs
  16. 10
      src/Perspex.SceneGraph/Platform/IRenderTargetBitmapImpl.cs
  17. 38
      src/Perspex.SceneGraph/Platform/IRenderer.cs
  18. 4
      src/Perspex.SceneGraph/Rendering/IRenderQueueManager.cs
  19. 7
      src/Perspex.SceneGraph/Rendering/IRenderRoot.cs
  20. 2
      src/Perspex.SceneGraph/Rendering/RenderQueueManager.cs
  21. 72
      src/Perspex.SceneGraph/Rendering/RendererBase.cs
  22. 6
      src/Perspex.SceneGraph/Visual.cs
  23. 4
      src/Windows/Perspex.Direct2D1/Direct2D1Platform.cs
  24. 4
      src/Windows/Perspex.Direct2D1/Media/DrawingContext.cs
  25. 4
      src/Windows/Perspex.Direct2D1/Media/ImageBrushImpl.cs
  26. 9
      src/Windows/Perspex.Direct2D1/Media/Imaging/RenderTargetBitmapImpl.cs
  27. 4
      src/Windows/Perspex.Direct2D1/Media/PerspexTextRenderer.cs
  28. 7
      src/Windows/Perspex.Direct2D1/Media/VisualBrushImpl.cs
  29. 2
      src/Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj
  30. 2
      src/Windows/Perspex.Direct2D1/PrimitiveExtensions.cs
  31. 19
      src/Windows/Perspex.Direct2D1/RenderTarget.cs
  32. 4
      src/Windows/Perspex.Win32/WindowImpl.cs
  33. 4
      tests/Perspex.Controls.UnitTests/ControlTests.cs
  34. 4
      tests/Perspex.Controls.UnitTests/TestRoot.cs
  35. 6
      tests/Perspex.Controls.UnitTests/TopLevelTests.cs
  36. 4
      tests/Perspex.Layout.UnitTests/FullLayoutTests.cs
  37. BIN
      tests/Perspex.RenderTests/TestBase.cs
  38. 4
      tests/Perspex.SceneGraph.UnitTests/TestRoot.cs

4
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)

22
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();
}
}
}

5
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);

2
src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj

@ -61,7 +61,7 @@
<Compile Include="Media\RadialGradientBrushImpl.cs" />
<Compile Include="Media\TileBrushes.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Renderer.cs" />
<Compile Include="RenderTarget.cs" />
<Compile Include="CairoExtensions.cs" />
<Compile Include="Media\StreamGeometryContextImpl.cs" />
<Compile Include="Media\StreamGeometryImpl.cs" />

39
src/Gtk/Perspex.Cairo/Renderer.cs → src/Gtk/Perspex.Cairo/RenderTarget.cs

@ -13,24 +13,26 @@ namespace Perspex.Cairo
using global::Cairo;
/// <summary>
/// A cairo renderer.
/// A cairo render target.
/// </summary>
public class Renderer : RendererBase
public class RenderTarget : IRenderTarget
{
private readonly IPlatformHandle _handle;
private readonly Surface _surface;
private Gdk.Window _window;
/// <summary>
/// Initializes a new instance of the <see cref="Renderer"/> class.
/// Initializes a new instance of the <see cref="RenderTarget"/> class.
/// </summary>
/// <param name="handle">The window handle.</param>
/// <param name="width">The width of the window.</param>
/// <param name="height">The height of the window.</param>
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
/// </summary>
/// <param name="width">The new width.</param>
/// <param name="height">The new height.</param>
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
/// <summary>
/// Creates a cairo surface that targets a platform-specific resource.
/// </summary>
/// <param name="handle">The platform-specific handle.</param>
/// <returns>A surface wrapped in an <see cref="IDrawingContext"/>.</returns>
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();
}
}

4
src/Gtk/Perspex.Gtk/WindowImpl.cs

@ -83,7 +83,7 @@ namespace Perspex.Gtk
public Action<RawInputEventArgs> Input { get; set; }
public Action<Rect, IPlatformHandle> Paint { get; set; }
public Action<Rect> Paint { get; set; }
public Action<Size> 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;
}

2
src/Perspex.Application/Application.cs

@ -168,7 +168,7 @@ namespace Perspex
.Bind<IKeyboardNavigationHandler>().ToTransient<KeyboardNavigationHandler>()
.Bind<IStyler>().ToConstant(_styler)
.Bind<ILayoutManager>().ToTransient<LayoutManager>()
.Bind<IRenderManager>().ToTransient<RenderManager>();
.Bind<IRenderQueueManager>().ToTransient<RenderQueueManager>();
}
/// <summary>

1
src/Perspex.Controls/Perspex.Controls.csproj

@ -43,6 +43,7 @@
</Compile>
<Compile Include="DockPanel.cs" />
<Compile Include="HotkeyManager.cs" />
<Compile Include="Platform\ITopLevelRenderer.cs" />
<Compile Include="SystemDialog.cs" />
<Compile Include="Generators\ITreeItemContainerGenerator.cs" />
<Compile Include="Generators\ItemContainers.cs" />

2
src/Perspex.Controls/Platform/ITopLevelImpl.cs

@ -22,7 +22,7 @@ namespace Perspex.Platform
Action<RawInputEventArgs> Input { get; set; }
Action<Rect, IPlatformHandle> Paint { get; set; }
Action<Rect> Paint { get; set; }
Action<Size> Resized { get; set; }

62
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<IDisposable>();
var initialClientSize = topLevel.PlatformImpl.ClientSize;
var queueManager = ((IRenderRoot)topLevel).RenderQueueManager;
if (queueManager == null)
return;
var platformRender = PerspexLocator.Current.GetService<IPlatformRenderInterface>();
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();
};
}
}
}

49
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<IInputElement> PointerOverElementProperty =
PerspexProperty.Register<TopLevel, IInputElement>(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<IInputManager>(dependencyResolver);
_keyboardNavigationHandler = TryGetService<IKeyboardNavigationHandler>(dependencyResolver);
LayoutManager = TryGetService<ILayoutManager>(dependencyResolver);
_renderManager = TryGetService<IRenderManager>(dependencyResolver);
_renderQueueManager = TryGetService<IRenderQueueManager>(dependencyResolver);
(TryGetService<ITopLevelRenderer>(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;
}
/// <summary>
/// Gets the window renderer.
/// </summary>
IRenderer IRenderRoot.Renderer => _renderer;
/// <summary>
/// Gets the window render manager.
/// </summary>
IRenderManager IRenderRoot.RenderManager => _renderManager;
IRenderQueueManager IRenderRoot.RenderQueueManager => _renderQueueManager;
/// <summary>
/// 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
/// </summary>
private void HandleLayoutCompleted()
{
_renderManager?.InvalidateRender(this);
}
/// <summary>
/// Handles a render request from <see cref="RenderManager.RenderNeeded"/>.
/// </summary>
private void HandleRenderNeeded()
{
Dispatcher.UIThread.InvokeAsync(
() => PlatformImpl.Invalidate(new Rect(ClientSize)),
DispatcherPriority.Render);
}
/// <summary>
/// Handles a paint request from <see cref="ITopLevelImpl.Paint"/>.
/// </summary>
/// <param name="rect">The rectangle to paint.</param>
/// <param name="handle">An optional platform-specific handle.</param>
private void HandlePaint(Rect rect, IPlatformHandle handle)
{
_renderer.Render(this, handle);
_renderManager.RenderFinished();
_renderQueueManager?.InvalidateRender(this);
}
}
}

22
src/Perspex.SceneGraph/Media/Imaging/RenderTargetBitmap.cs

@ -3,13 +3,14 @@
using System;
using Perspex.Platform;
using Perspex.Rendering;
namespace Perspex.Media.Imaging
{
/// <summary>
/// A bitmap that holds the rendering of a <see cref="IVisual"/>.
/// </summary>
public class RenderTargetBitmap : Bitmap, IDisposable
public class RenderTargetBitmap : Bitmap, IDisposable, IRenderTarget
{
/// <summary>
/// Initializes a new instance of the <see cref="RenderTargetBitmap"/> class.
@ -26,18 +27,6 @@ namespace Perspex.Media.Imaging
/// </summary>
public new IRenderTargetBitmapImpl PlatformImpl => (IRenderTargetBitmapImpl)base.PlatformImpl;
/// <summary>
/// Renders an <see cref="IVisual"/> into the bitmap.
/// </summary>
/// <param name="visual">The visual to render.</param>
/// <remarks>
/// Before calling this method, ensure that <paramref name="visual"/> has been measured.
/// </remarks>
public void Render(IVisual visual)
{
PlatformImpl.Render(visual);
}
/// <summary>
/// Disposes of the bitmap.
/// </summary>
@ -57,5 +46,12 @@ namespace Perspex.Media.Imaging
IPlatformRenderInterface factory = PerspexLocator.Current.GetService<IPlatformRenderInterface>();
return factory.CreateRenderTargetBitmap(width, height);
}
public IDrawingContext CreateDrawingContext() => PlatformImpl.CreateDrawingContext();
void IRenderTarget.Resize(int width, int height)
{
throw new NotSupportedException();
}
}
}

6
src/Perspex.SceneGraph/Perspex.SceneGraph.csproj

@ -105,7 +105,7 @@
<Compile Include="Platform\IBitmapImpl.cs" />
<Compile Include="Platform\IGeometryImpl.cs" />
<Compile Include="Platform\IPlatformRenderInterface.cs" />
<Compile Include="Platform\IRenderer.cs" />
<Compile Include="Platform\IRenderTarget.cs" />
<Compile Include="Platform\IRenderTargetBitmapImpl.cs" />
<Compile Include="Platform\IStreamGeometryContextImpl.cs" />
<Compile Include="Platform\IStreamGeometryImpl.cs" />
@ -114,9 +114,9 @@
<Compile Include="RelativeRect.cs" />
<Compile Include="Rect.cs" />
<Compile Include="Rendering\IRenderRoot.cs" />
<Compile Include="Rendering\IRenderManager.cs" />
<Compile Include="Rendering\IRenderQueueManager.cs" />
<Compile Include="Rendering\RendererBase.cs" />
<Compile Include="Rendering\RenderManager.cs" />
<Compile Include="Rendering\RenderQueueManager.cs" />
<Compile Include="Size.cs" />
<Compile Include="Thickness.cs" />
<Compile Include="Vector.cs" />

4
src/Perspex.SceneGraph/Platform/IPlatformRenderInterface.cs

@ -49,8 +49,8 @@ namespace Perspex.Platform
/// <param name="handle">The platform handle for the renderer.</param>
/// <param name="width">The initial width of the render.</param>
/// <param name="height">The initial height of the render.</param>
/// <returns>An <see cref="IRenderer"/>.</returns>
IRenderer CreateRenderer(IPlatformHandle handle, double width, double height);
/// <returns>An <see cref="IRenderTarget"/>.</returns>
IRenderTarget CreateRenderer(IPlatformHandle handle, double width, double height);
/// <summary>
/// Creates a render target bitmap implementation.

29
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
{
/// <summary>
/// Defines a render target
/// </summary>
/// <remarks>
/// The interface used for obtaining drawing context from surfaces you can render on.
/// </remarks>
public interface IRenderTarget : IDisposable
{
/// <summary>
/// Creates an <see cref="IDrawingContext"/> for a rendering session.
/// </summary>
IDrawingContext CreateDrawingContext();
/// <summary>
/// Resizes the rendered viewport.
/// </summary>
/// <param name="width">The new width.</param>
/// <param name="height">The new height.</param>
void Resize(int width, int height);
}
}

10
src/Perspex.SceneGraph/Platform/IRenderTargetBitmapImpl.cs

@ -9,15 +9,7 @@ namespace Perspex.Platform
/// Defines the platform-specific interface for a
/// <see cref="Perspex.Media.Imaging.RenderTargetBitmap"/>.
/// </summary>
public interface IRenderTargetBitmapImpl : IBitmapImpl, IDisposable
public interface IRenderTargetBitmapImpl : IBitmapImpl, IRenderTarget
{
/// <summary>
/// Renders an <see cref="IVisual"/> into the bitmap.
/// </summary>
/// <param name="visual">The visual to render.</param>
/// <remarks>
/// Before calling this method, ensure that <paramref name="visual"/> has been measured.
/// </remarks>
void Render(IVisual visual);
}
}

38
src/Perspex.SceneGraph/Platform/IRenderer.cs

@ -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
{
/// <summary>
/// Defines a renderer.
/// </summary>
/// <remarks>
/// The interface used to render <see cref="IVisual"/>s. You will usually want to inherit from
/// <see cref="Perspex.Rendering.RendererBase"/> rather than implementing the whole interface
/// as RenderBase has a default implementation for the non-platform specific parts of a
/// renderer.
/// </remarks>
public interface IRenderer : IDisposable
{
/// <summary>
/// Gets the number of times <see cref="Render"/> has been called.
/// </summary>
int RenderCount { get; }
/// <summary>
/// Renders the specified visual.
/// </summary>
/// <param name="visual">The visual to render.</param>
/// <param name="handle">An optional platform-specific handle.</param>
void Render(IVisual visual, IPlatformHandle handle);
/// <summary>
/// Resizes the rendered viewport.
/// </summary>
/// <param name="width">The new width.</param>
/// <param name="height">The new height.</param>
void Resize(int width, int height);
}
}

4
src/Perspex.SceneGraph/Rendering/IRenderManager.cs → src/Perspex.SceneGraph/Rendering/IRenderQueueManager.cs

@ -7,9 +7,9 @@ using System.Reactive;
namespace Perspex.Rendering
{
/// <summary>
/// Defines the interface for a <see cref="RenderManager"/>.
/// Defines the interface for a <see cref="RenderQueueManager"/>.
/// </summary>
public interface IRenderManager
public interface IRenderQueueManager
{
/// <summary>
/// Gets an observable that is fired whenever a render is required.

7
src/Perspex.SceneGraph/Rendering/IRenderRoot.cs

@ -10,15 +10,10 @@ namespace Perspex.Rendering
/// </summary>
public interface IRenderRoot
{
/// <summary>
/// Gets the renderer for the tree.
/// </summary>
IRenderer Renderer { get; }
/// <summary>
/// Gets the render manager which schedules renders.
/// </summary>
IRenderManager RenderManager { get; }
IRenderQueueManager RenderQueueManager { get; }
/// <summary>
/// Translates a point to screen co-ordinates.

2
src/Perspex.SceneGraph/Rendering/RenderManager.cs → src/Perspex.SceneGraph/Rendering/RenderQueueManager.cs

@ -10,7 +10,7 @@ namespace Perspex.Rendering
/// <summary>
/// Schedules the rendering of a tree.
/// </summary>
public class RenderManager : IRenderManager
public class RenderQueueManager : IRenderQueueManager
{
private readonly Subject<Unit> _renderNeeded = new Subject<Unit>();

72
src/Perspex.SceneGraph/Rendering/RendererBase.cs

@ -12,63 +12,73 @@ namespace Perspex.Rendering
/// Base class for standard renderers.
/// </summary>
/// <remarks>
/// This class provides implements the platform-independent parts of <see cref="IRenderer"/>.
/// This class provides implements the platform-independent parts of <see cref="IRenderTarget"/>.
/// </remarks>
public abstract class RendererBase : IRenderer
public static class RendererMixin
{
/// <summary>
/// Gets the number of times <see cref="Render(IVisual, IPlatformHandle)"/> has been called.
/// Renders the specified visual.
/// </summary>
public int RenderCount
/// <param name="renderTarget">IRenderer instance</param>
/// <param name="visual">The visual to render.</param>
public static void Render(this IRenderTarget renderTarget, IVisual visual)
{
get;
private set;
using (var ctx = renderTarget.CreateDrawingContext())
ctx.Render(visual);
}
public abstract void Dispose();
/// <summary>
/// Renders the specified visual.
/// </summary>
/// <param name="renderTarget">IRenderer instance</param>
/// <param name="visual">The visual to render.</param>
/// <param name="handle">An optional platform-specific handle.</param>
public virtual void Render(IVisual visual, IPlatformHandle handle)
/// <param name="translation">The current translation.</param>
/// <param name="transform">The current transform.</param>
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);
}
/// <summary>
/// Renders the specified visual with the specified transform and clip.
/// </summary>
/// <param name="renderTarget">IRenderer instance</param>
/// <param name="visual">The visual to render.</param>
/// <param name="handle">An optional platform-specific handle.</param>
/// <param name="transform">The transform.</param>
/// <param name="clip">An optional clip rectangle.</param>
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);
}
/// <summary>
/// Resizes the rendered viewport.
/// Renders the specified visual.
/// </summary>
/// <param name="width">The new width.</param>
/// <param name="height">The new height.</param>
public abstract void Resize(int width, int height);
/// <param name="visual">The visual to render.</param>
///
/// <param name="context">The drawing context.</param>
public static void Render(this IDrawingContext context, IVisual visual)
{
context.Render(visual, Matrix.Identity);
}
/// <summary>
/// When overriden by a derived class creates an <see cref="IDrawingContext"/> for a
/// rendering session.
/// Renders the specified visual with the specified transform and clip.
/// </summary>
/// <param name="handle">The handle to use to create the context.</param>
/// <returns>An <see cref="IDrawingContext"/>.</returns>
protected abstract IDrawingContext CreateDrawingContext(IPlatformHandle handle);
/// <param name="visual">The visual to render.</param>
/// <param name="context">The drawing context.</param>
/// <param name="transform">The transform.</param>
/// <param name="clip">An optional clip rectangle.</param>
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);
}
}
/// <summary>
/// Renders the specified visual.
/// </summary>
@ -76,7 +86,7 @@ namespace Perspex.Rendering
/// <param name="context">The drawing context.</param>
/// <param name="translation">The current translation.</param>
/// <param name="transform">The current transform.</param>
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);
}
}
}

6
src/Perspex.SceneGraph/Visual.cs

@ -22,7 +22,7 @@ namespace Perspex
/// </summary>
/// <remarks>
/// The <see cref="Visual"/> class acts as a node in the Perspex scene graph and holds
/// all the information needed for an <see cref="IRenderer"/> to render the control.
/// all the information needed for an <see cref="IRenderTarget"/> to render the control.
/// To traverse the scene graph (aka Visual Tree), use the extension methods defined
/// in <see cref="VisualExtensions"/>.
/// </remarks>
@ -222,9 +222,9 @@ namespace Perspex
.OfType<IRenderRoot>()
.FirstOrDefault();
if (root != null && root.RenderManager != null)
if (root != null && root.RenderQueueManager != null)
{
root.RenderManager.InvalidateRender(this);
root.RenderQueueManager.InvalidateRender(this);
}
}

4
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
{

4
src/Windows/Perspex.Direct2D1/Media/DrawingContext.cs

@ -18,7 +18,7 @@ namespace Perspex.Direct2D1.Media
/// <summary>
/// The Direct2D1 render target.
/// </summary>
private readonly RenderTarget _renderTarget;
private readonly SharpDX.Direct2D1.RenderTarget _renderTarget;
/// <summary>
/// The DirectWrite factory.
@ -31,7 +31,7 @@ namespace Perspex.Direct2D1.Media
/// <param name="renderTarget">The render target to draw to.</param>
/// <param name="directWriteFactory">The DirectWrite factory.</param>
public DrawingContext(
RenderTarget renderTarget,
SharpDX.Direct2D1.RenderTarget renderTarget,
SharpDX.DirectWrite.Factory directWriteFactory)
{
_renderTarget = renderTarget;

4
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)

9
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();
}
}
}

4
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;

7
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,

2
src/Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj

@ -89,7 +89,7 @@
<Compile Include="Media\FormattedTextImpl.cs" />
<Compile Include="PrimitiveExtensions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Renderer.cs" />
<Compile Include="RenderTarget.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />

2
src/Windows/Perspex.Direct2D1/PrimitiveExtensions.cs

@ -69,7 +69,7 @@ namespace Perspex.Direct2D1
/// <param name="pen">The pen to convert.</param>
/// <param name="target">The render target.</param>
/// <returns>The Direct2D brush.</returns>
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)
{

19
src/Windows/Perspex.Direct2D1/Renderer.cs → 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
{
/// <summary>
/// The render target.
/// </summary>
private readonly RenderTarget _renderTarget;
private readonly SharpDX.Direct2D1.RenderTarget _renderTarget;
/// <summary>
/// Initializes a new instance of the <see cref="Renderer"/> class.
/// Initializes a new instance of the <see cref="RenderTarget"/> class.
/// </summary>
/// <param name="hwnd">The window handle.</param>
/// <param name="width">The width of the window.</param>
/// <param name="height">The height of the window.</param>
public Renderer(IntPtr hwnd, double width, double height)
public RenderTarget(IntPtr hwnd, double width, double height)
{
Direct2DFactory = PerspexLocator.Current.GetService<Factory>();
DirectWriteFactory = PerspexLocator.Current.GetService<DwFactory>();
@ -48,10 +48,10 @@ namespace Perspex.Direct2D1
}
/// <summary>
/// Initializes a new instance of the <see cref="Renderer"/> class.
/// Initializes a new instance of the <see cref="RenderTarget"/> class.
/// </summary>
/// <param name="renderTarget">The render target.</param>
public Renderer(RenderTarget renderTarget)
public RenderTarget(SharpDX.Direct2D1.RenderTarget renderTarget)
{
Direct2DFactory = PerspexLocator.Current.GetService<Factory>();
DirectWriteFactory = PerspexLocator.Current.GetService<DwFactory>();
@ -77,7 +77,7 @@ namespace Perspex.Direct2D1
/// </summary>
/// <param name="width">The new width.</param>
/// <param name="height">The new height.</param>
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
/// <summary>
/// Creates a drawing context for a rendering session.
/// </summary>
/// <param name="handle">The platform handle. Unused.</param>
/// <returns>An <see cref="IDrawingContext"/>.</returns>
protected override IDrawingContext CreateDrawingContext(IPlatformHandle handle)
public IDrawingContext CreateDrawingContext()
{
return new DrawingContext(_renderTarget, DirectWriteFactory);
}
public override void Dispose()
public void Dispose()
{
_renderTarget.Dispose();
}

4
src/Windows/Perspex.Win32/WindowImpl.cs

@ -51,7 +51,7 @@ namespace Perspex.Win32
public Action<RawInputEventArgs> Input { get; set; }
public Action<Rect, IPlatformHandle> Paint { get; set; }
public Action<Rect> Paint { get; set; }
public Action<Size> 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);
}
}

4
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(); }
}

4
tests/Perspex.Controls.UnitTests/TestRoot.cs

@ -15,12 +15,12 @@ namespace Perspex.Controls.UnitTests
public ILayoutManager LayoutManager => new Mock<ILayoutManager>().Object;
public IRenderer Renderer
public IRenderTarget RenderTarget
{
get { throw new NotImplementedException(); }
}
public IRenderManager RenderManager
public IRenderQueueManager RenderQueueManager
{
get { throw new NotImplementedException(); }
}

6
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<IRenderManager>());
var renderManagerMock = Mock.Get(PerspexLocator.Current.GetService<IRenderQueueManager>());
renderManagerMock.Verify(x => x.InvalidateRender(target));
}
}
@ -313,7 +313,7 @@ namespace Perspex.Controls.UnitTests
var globalStyles = new Mock<IGlobalStyles>();
var layoutManager = fixture.Create<ILayoutManager>();
var renderInterface = fixture.Create<IPlatformRenderInterface>();
var renderManager = fixture.Create<IRenderManager>();
var renderManager = fixture.Create<IRenderQueueManager>();
var windowImpl = new Mock<IWindowImpl>();
var theme = new Styles();
@ -327,7 +327,7 @@ namespace Perspex.Controls.UnitTests
.Bind<ILayoutManager>().ToConstant(layoutManager)
.Bind<IPlatformRenderInterface>().ToConstant(renderInterface)
.Bind<IPlatformThreadingInterface>().ToConstant(new Mock<IPlatformThreadingInterface>().Object)
.Bind<IRenderManager>().ToConstant(renderManager)
.Bind<IRenderQueueManager>().ToConstant(renderManager)
.Bind<IStyler>().ToConstant(new Styler());
}

4
tests/Perspex.Layout.UnitTests/FullLayoutTests.cs

@ -134,7 +134,7 @@ namespace Perspex.Layout.UnitTests
var formattedText = fixture.Create<IFormattedTextImpl>();
var globalStyles = new Mock<IGlobalStyles>();
var renderInterface = fixture.Create<IPlatformRenderInterface>();
var renderManager = fixture.Create<IRenderManager>();
var renderManager = fixture.Create<IRenderQueueManager>();
var theme = new DefaultTheme();
var windowImpl = new Mock<IWindowImpl>();
@ -148,7 +148,7 @@ namespace Perspex.Layout.UnitTests
.Bind<ILayoutManager>().ToConstant(new LayoutManager())
.Bind<IPlatformRenderInterface>().ToConstant(renderInterface)
.Bind<IPlatformThreadingInterface>().ToConstant(new Mock<IPlatformThreadingInterface>().Object)
.Bind<IRenderManager>().ToConstant(renderManager)
.Bind<IRenderQueueManager>().ToConstant(renderManager)
.Bind<IStyler>().ToConstant(new Styler())
.Bind<IWindowImpl>().ToConstant(windowImpl.Object);
}

BIN
tests/Perspex.RenderTests/TestBase.cs

Binary file not shown.

4
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(); }
}

Loading…
Cancel
Save