Browse Source

Merge pull request #861 from kekekeks/multi-render-target

Added support for multiple drawing methods for window implementations and "framebuffer"
pull/867/head
Steven Kirk 9 years ago
committed by GitHub
parent
commit
0a89f6c36e
  1. 5
      src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs
  2. 3
      src/Avalonia.Controls/Avalonia.Controls.csproj
  3. 13
      src/Avalonia.Controls/Platform/ITopLevelImpl.cs
  4. 19
      src/Avalonia.Controls/Platform/Surfaces/IFramebufferPlatformSurface.cs
  5. 37
      src/Avalonia.Controls/Platform/Surfaces/ILockedFramebuffer.cs
  6. 15
      src/Avalonia.Controls/Platform/Surfaces/PixelFormat.cs
  7. 2
      src/Avalonia.Controls/TopLevel.cs
  8. 7
      src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs
  9. 22
      src/Gtk/Avalonia.Cairo/CairoPlatform.cs
  10. 19
      src/Gtk/Avalonia.Cairo/RenderTarget.cs
  11. 2
      src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj
  12. 39
      src/Gtk/Avalonia.Gtk/FramebufferManager.cs
  13. 58
      src/Gtk/Avalonia.Gtk/PixbufFramebuffer.cs
  14. 2
      src/Gtk/Avalonia.Gtk/WindowImpl.cs
  15. 26
      src/Gtk/Avalonia.Gtk/WindowImplBase.cs
  16. 26
      src/Skia/Avalonia.Skia.Android/AndroidPlatformRenderInterface.cs
  17. 1
      src/Skia/Avalonia.Skia.Android/Avalonia.Skia.Android.csproj
  18. 16
      src/Skia/Avalonia.Skia.Android/RenderTarget.cs
  19. 2
      src/Skia/Avalonia.Skia.Android/SkiaRenderView.cs
  20. 5
      src/Skia/Avalonia.Skia.Desktop/Avalonia.Skia.Desktop.csproj
  21. 21
      src/Skia/Avalonia.Skia.Desktop/PlatformRenderInterfaceDesktop.cs
  22. 1
      src/Skia/Avalonia.Skia.iOS/Avalonia.Skia.iOS.csproj
  23. 18
      src/Skia/Avalonia.Skia.iOS/PlatformRenderingInterfaceIos.cs
  24. 5
      src/Skia/Avalonia.Skia.iOS/RenderTarget.cs
  25. 1
      src/Skia/Avalonia.Skia/Avalonia.Skia.projitems
  26. 77
      src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs
  27. 8
      src/Skia/Avalonia.Skia/PlatformRenderInterface.cs
  28. 2
      src/Skia/Avalonia.Skia/WindowDrawingContextImpl.cs
  29. 19
      src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs
  30. 14
      src/Windows/Avalonia.Direct2D1/HwndRenderTarget.cs
  31. 2
      src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
  32. 41
      src/Windows/Avalonia.Win32/FramebufferManager.cs
  33. 48
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  34. 121
      src/Windows/Avalonia.Win32/WindowFramebuffer.cs
  35. 9
      src/Windows/Avalonia.Win32/WindowImpl.cs
  36. 3
      src/iOS/Avalonia.iOS/AvaloniaView.cs
  37. 2
      tests/Avalonia.Input.UnitTests/InputElement_HitTesting.cs
  38. 2
      tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs

5
src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs

@ -9,6 +9,7 @@ using Avalonia.Input.Raw;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Skia.Android; using Avalonia.Skia.Android;
using System; using System;
using System.Collections.Generic;
using Avalonia.Controls; using Avalonia.Controls;
namespace Avalonia.Android.Platform.SkiaPlatform namespace Avalonia.Android.Platform.SkiaPlatform
@ -95,6 +96,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform
IPlatformHandle ITopLevelImpl.Handle => this; IPlatformHandle ITopLevelImpl.Handle => this;
public IEnumerable<object> Surfaces => new object[] { this };
public void Activate() public void Activate()
{ {
} }
@ -188,5 +191,5 @@ namespace Avalonia.Android.Platform.SkiaPlatform
{ {
// No window icons for mobile platforms // No window icons for mobile platforms
} }
} }
} }

3
src/Avalonia.Controls/Avalonia.Controls.csproj

@ -57,6 +57,9 @@
<Compile Include="HotkeyManager.cs" /> <Compile Include="HotkeyManager.cs" />
<Compile Include="IApplicationLifecycle.cs" /> <Compile Include="IApplicationLifecycle.cs" />
<Compile Include="IScrollable.cs" /> <Compile Include="IScrollable.cs" />
<Compile Include="Platform\Surfaces\IFramebufferPlatformSurface.cs" />
<Compile Include="Platform\Surfaces\ILockedFramebuffer.cs" />
<Compile Include="Platform\Surfaces\PixelFormat.cs" />
<Compile Include="PointEventArgs.cs" /> <Compile Include="PointEventArgs.cs" />
<Compile Include="Embedding\EmbeddableControlRoot.cs" /> <Compile Include="Embedding\EmbeddableControlRoot.cs" />
<Compile Include="Platform\IEmbeddableWindowImpl.cs" /> <Compile Include="Platform\IEmbeddableWindowImpl.cs" />

13
src/Avalonia.Controls/Platform/ITopLevelImpl.cs

@ -2,6 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using System.Collections.Generic;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Input.Raw; using Avalonia.Input.Raw;
@ -37,6 +38,18 @@ namespace Avalonia.Platform
/// </summary> /// </summary>
IPlatformHandle Handle { get; } IPlatformHandle Handle { get; }
/// <summary>
/// The list of native platform's surfaces that can be consumed by rendering subsystems.
/// </summary>
/// <remarks>
/// Rendering platform will check that list and see if it can utilize one of them to output.
/// It should be enough to expose a native window handle via IPlatformHandle
/// and add support for framebuffer (even if it's emulated one) via IFramebufferPlatformSurface.
/// If you have some rendering platform that's tied to your particular windowing platform,
/// just expose some toolkit-specific object (e. g. Func&lt;Gdk.Drawable&gt; in case of GTK#+Cairo)
/// </remarks>
IEnumerable<object> Surfaces { get; }
/// <summary> /// <summary>
/// Gets or sets a method called when the window is activated (receives focus). /// Gets or sets a method called when the window is activated (receives focus).
/// </summary> /// </summary>

19
src/Avalonia.Controls/Platform/Surfaces/IFramebufferPlatformSurface.cs

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Avalonia.Controls.Platform.Surfaces
{
public interface IFramebufferPlatformSurface
{
/// <summary>
/// Provides a framebuffer descriptor for drawing.
/// </summary>
/// <remarks>
/// Contents should be drawn on actual window after disposing
/// </remarks>
ILockedFramebuffer Lock();
}
}

37
src/Avalonia.Controls/Platform/Surfaces/ILockedFramebuffer.cs

@ -0,0 +1,37 @@
using System;
namespace Avalonia.Controls.Platform.Surfaces
{
public interface ILockedFramebuffer : IDisposable
{
/// <summary>
/// Address of the first pixel
/// </summary>
IntPtr Address { get; }
/// <summary>
/// Framebuffer width
/// </summary>
int Width { get; }
/// <summary>
/// Framebuffer height
/// </summary>
int Height { get; }
/// <summary>
/// Number of bytes per row
/// </summary>
int RowBytes { get; }
/// <summary>
/// DPI of underling screen
/// </summary>
Size Dpi { get; }
/// <summary>
/// Pixel format
/// </summary>
PixelFormat Format { get; }
}
}

15
src/Avalonia.Controls/Platform/Surfaces/PixelFormat.cs

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Avalonia.Controls.Platform.Surfaces
{
public enum PixelFormat
{
Rgb565,
Rgba8888,
Bgra8888
}
}

2
src/Avalonia.Controls/TopLevel.cs

@ -237,7 +237,7 @@ namespace Avalonia.Controls
/// <inheritdoc/> /// <inheritdoc/>
IRenderTarget IRenderRoot.CreateRenderTarget() IRenderTarget IRenderRoot.CreateRenderTarget()
{ {
return _renderInterface.CreateRenderTarget(PlatformImpl.Handle); return _renderInterface.CreateRenderTarget(PlatformImpl.Surfaces);
} }
/// <inheritdoc/> /// <inheritdoc/>

7
src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs

@ -1,6 +1,7 @@
// Copyright (c) The Avalonia Project. All rights reserved. // 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. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Collections.Generic;
using System.IO; using System.IO;
using Avalonia.Media; using Avalonia.Media;
@ -40,9 +41,11 @@ namespace Avalonia.Platform
/// <summary> /// <summary>
/// Creates a renderer. /// Creates a renderer.
/// </summary> /// </summary>
/// <param name="handle">The platform handle for the renderer.</param> /// <param name="surfaces">
/// The list of native platform surfaces that can be used for output.
/// </param>
/// <returns>An <see cref="IRenderTarget"/>.</returns> /// <returns>An <see cref="IRenderTarget"/>.</returns>
IRenderTarget CreateRenderTarget(IPlatformHandle handle); IRenderTarget CreateRenderTarget(IEnumerable<object> surfaces);
/// <summary> /// <summary>
/// Creates a render target bitmap implementation. /// Creates a render target bitmap implementation.

22
src/Gtk/Avalonia.Cairo/CairoPlatform.cs

@ -2,6 +2,8 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Cairo.Media; using Avalonia.Cairo.Media;
using Avalonia.Cairo.Media.Imaging; using Avalonia.Cairo.Media.Imaging;
using Avalonia.Media; using Avalonia.Media;
@ -50,24 +52,14 @@ namespace Avalonia.Cairo
return new FormattedTextImpl(s_pangoContext, text, fontFamily, fontSize, fontStyle, textAlignment, fontWeight); return new FormattedTextImpl(s_pangoContext, text, fontFamily, fontSize, fontStyle, textAlignment, fontWeight);
} }
public IRenderTarget CreateRenderTarget(IPlatformHandle handle) public IRenderTarget CreateRenderTarget(IEnumerable<object> surfaces)
{ {
var window = handle as Gtk.Window; var accessor = surfaces?.OfType<Func<Gdk.Drawable>>().FirstOrDefault();
if (window != null) if(accessor!=null)
{ return new RenderTarget(accessor);
window.DoubleBuffered = true;
return new RenderTarget(window);
}
var area = handle as Gtk.DrawingArea;
if (area != null)
{
area.DoubleBuffered = true;
return new RenderTarget(area);
}
throw new NotSupportedException(string.Format( throw new NotSupportedException(string.Format(
"Don't know how to create a Cairo renderer from a '{0}' handle which isn't Gtk.Window or Gtk.DrawingArea", "Don't know how to create a Cairo renderer from any of the provided surfaces."));
handle.HandleDescriptor));
} }
public IRenderTargetBitmapImpl CreateRenderTargetBitmap(int width, int height) public IRenderTargetBitmapImpl CreateRenderTargetBitmap(int width, int height)

19
src/Gtk/Avalonia.Cairo/RenderTarget.cs

@ -20,8 +20,8 @@ namespace Avalonia.Cairo
public class RenderTarget : IRenderTarget public class RenderTarget : IRenderTarget
{ {
private readonly Surface _surface; private readonly Surface _surface;
private readonly Gtk.Window _window; private readonly Func<Gdk.Drawable> _drawableAccessor;
private readonly Gtk.DrawingArea _area;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RenderTarget"/> class. /// Initializes a new instance of the <see cref="RenderTarget"/> class.
@ -29,9 +29,9 @@ namespace Avalonia.Cairo
/// <param name="window">The window.</param> /// <param name="window">The window.</param>
/// <param name="width">The width of the window.</param> /// <param name="width">The width of the window.</param>
/// <param name="height">The height of the window.</param> /// <param name="height">The height of the window.</param>
public RenderTarget(Gtk.Window window) public RenderTarget(Func<Gdk.Drawable> drawable)
{ {
_window = window; _drawableAccessor = drawable;
} }
public RenderTarget(ImageSurface surface) public RenderTarget(ImageSurface surface)
@ -39,11 +39,6 @@ namespace Avalonia.Cairo
_surface = surface; _surface = surface;
} }
public RenderTarget(DrawingArea area)
{
_area = area;
}
/// <summary> /// <summary>
/// Creates a cairo surface that targets a platform-specific resource. /// Creates a cairo surface that targets a platform-specific resource.
/// </summary> /// </summary>
@ -52,12 +47,10 @@ namespace Avalonia.Cairo
public IDrawingContextImpl CreateMediaDrawingContext() public IDrawingContextImpl CreateMediaDrawingContext()
{ {
if (_window != null) if (_drawableAccessor != null)
return new Media.DrawingContext(_window.GdkWindow); return new Media.DrawingContext(_drawableAccessor());
if (_surface != null) if (_surface != null)
return new Media.DrawingContext(_surface); return new Media.DrawingContext(_surface);
if (_area != null)
return new Media.DrawingContext(_area.GdkWindow);
throw new InvalidOperationException("Unspecified render target"); throw new InvalidOperationException("Unspecified render target");
} }

2
src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj

@ -48,7 +48,9 @@
<Compile Include="ClipboardImpl.cs" /> <Compile Include="ClipboardImpl.cs" />
<Compile Include="EmbeddableImpl.cs" /> <Compile Include="EmbeddableImpl.cs" />
<Compile Include="Embedding\GtkAvaloniaControlHost.cs" /> <Compile Include="Embedding\GtkAvaloniaControlHost.cs" />
<Compile Include="FramebufferManager.cs" />
<Compile Include="IconImpl.cs" /> <Compile Include="IconImpl.cs" />
<Compile Include="PixbufFramebuffer.cs" />
<Compile Include="SystemDialogImpl.cs" /> <Compile Include="SystemDialogImpl.cs" />
<Compile Include="CursorFactory.cs" /> <Compile Include="CursorFactory.cs" />
<Compile Include="GtkExtensions.cs" /> <Compile Include="GtkExtensions.cs" />

39
src/Gtk/Avalonia.Gtk/FramebufferManager.cs

@ -0,0 +1,39 @@
using System;
using Avalonia.Controls.Platform.Surfaces;
namespace Avalonia.Gtk
{
class FramebufferManager : IFramebufferPlatformSurface, IDisposable
{
private readonly WindowImplBase _window;
private PixbufFramebuffer _fb;
public FramebufferManager(WindowImplBase window)
{
_window = window;
}
public void Dispose()
{
_fb?.Deallocate();
}
public ILockedFramebuffer Lock()
{
if(_window.CurrentDrawable == null)
throw new InvalidOperationException("Window is not in drawing state");
var drawable = _window.CurrentDrawable;
var width = (int) _window.ClientSize.Width;
var height = (int) _window.ClientSize.Height;
if (_fb == null || _fb.Width != width ||
_fb.Height != height)
{
_fb?.Dispose();
_fb = new PixbufFramebuffer(width, height);
}
_fb.SetDrawable(drawable);
return _fb;
}
}
}

58
src/Gtk/Avalonia.Gtk/PixbufFramebuffer.cs

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Platform;
using Gdk;
namespace Avalonia.Gtk
{
class PixbufFramebuffer : ILockedFramebuffer
{
private Pixbuf _pixbuf;
private Drawable _drawable;
public PixbufFramebuffer(int width, int height)
{
_pixbuf = new Pixbuf(Gdk.Colorspace.Rgb, false, 8, width, height);
}
public void SetDrawable(Drawable drawable)
{
_drawable = drawable;
}
public void Deallocate()
{
_pixbuf.Dispose();
_pixbuf = null;
}
public void Dispose()
{
using (var gc = new Gdk.GC(_drawable))
_drawable.DrawPixbuf(gc, _pixbuf, 0, 0, 0, 0, Width, Height, RgbDither.None, 0, 0);
_drawable = null;
}
public IntPtr Address => _pixbuf.Pixels;
public int Width => _pixbuf.Width;
public int Height => _pixbuf.Height;
public int RowBytes => _pixbuf.Rowstride;
//TODO: Proper DPI detect
public Size Dpi => new Size(96, 96);
public PixelFormat Format
{
get
{
if (AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetRuntimeInfo().OperatingSystem ==
OperatingSystemType.WinNT)
return PixelFormat.Bgra8888;
return PixelFormat.Rgba8888;
}
}
}
}

2
src/Gtk/Avalonia.Gtk/WindowImpl.cs

@ -10,7 +10,7 @@ namespace Avalonia.Gtk
{ {
private Gtk.Window _window; private Gtk.Window _window;
private Gtk.Window Window => _window ?? (_window = (Gtk.Window) Widget); private Gtk.Window Window => _window ?? (_window = (Gtk.Window) Widget);
public WindowImpl(Gtk.WindowType type) : base(new PlatformHandleAwareWindow(type)) public WindowImpl(Gtk.WindowType type) : base(new PlatformHandleAwareWindow(type))
{ {
Init(); Init();

26
src/Gtk/Avalonia.Gtk/WindowImplBase.cs

@ -2,14 +2,11 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using System.Reactive.Disposables; using System.Collections.Generic;
using System.Runtime.InteropServices; using Avalonia.Input;
using Gdk;
using Avalonia.Controls;
using Avalonia.Input.Raw; using Avalonia.Input.Raw;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Input; using Gdk;
using Avalonia.Threading;
using Action = System.Action; using Action = System.Action;
using WindowEdge = Avalonia.Controls.WindowEdge; using WindowEdge = Avalonia.Controls.WindowEdge;
@ -21,8 +18,7 @@ namespace Avalonia.Gtk
{ {
private IInputRoot _inputRoot; private IInputRoot _inputRoot;
protected Gtk.Widget _window; protected Gtk.Widget _window;
public Gtk.Widget Widget => _window; private FramebufferManager _framebuffer;
private Gtk.IMContext _imContext; private Gtk.IMContext _imContext;
@ -33,6 +29,7 @@ namespace Avalonia.Gtk
protected WindowImplBase(Gtk.Widget window) protected WindowImplBase(Gtk.Widget window)
{ {
_window = window; _window = window;
_framebuffer = new FramebufferManager(this);
Init(); Init();
} }
@ -43,7 +40,6 @@ namespace Avalonia.Gtk
_imContext = new Gtk.IMMulticontext(); _imContext = new Gtk.IMMulticontext();
_imContext.Commit += ImContext_Commit; _imContext.Commit += ImContext_Commit;
_window.Realized += OnRealized; _window.Realized += OnRealized;
_window.DoubleBuffered = false;
_window.Realize(); _window.Realize();
_window.ButtonPressEvent += OnButtonPressEvent; _window.ButtonPressEvent += OnButtonPressEvent;
_window.ButtonReleaseEvent += OnButtonReleaseEvent; _window.ButtonReleaseEvent += OnButtonReleaseEvent;
@ -57,6 +53,8 @@ namespace Avalonia.Gtk
} }
public IPlatformHandle Handle { get; private set; } public IPlatformHandle Handle { get; private set; }
public Gtk.Widget Widget => _window;
public Gdk.Drawable CurrentDrawable { get; private set; }
void OnRealized (object sender, EventArgs eventArgs) void OnRealized (object sender, EventArgs eventArgs)
{ {
@ -127,6 +125,13 @@ namespace Avalonia.Gtk
public Action<double> ScalingChanged { get; set; } public Action<double> ScalingChanged { get; set; }
public IEnumerable<object> Surfaces => new object[]
{
Handle,
new Func<Gdk.Drawable>(() => CurrentDrawable),
_framebuffer
};
public IPopupImpl CreatePopup() public IPopupImpl CreatePopup()
{ {
return new PopupImpl(); return new PopupImpl();
@ -283,7 +288,9 @@ namespace Avalonia.Gtk
void OnExposeEvent(object o, Gtk.ExposeEventArgs args) void OnExposeEvent(object o, Gtk.ExposeEventArgs args)
{ {
CurrentDrawable = args.Event.Window;
Paint(args.Event.Area.ToAvalonia()); Paint(args.Event.Area.ToAvalonia());
CurrentDrawable = null;
args.RetVal = true; args.RetVal = true;
} }
@ -306,6 +313,7 @@ namespace Avalonia.Gtk
public void Dispose() public void Dispose()
{ {
_framebuffer.Dispose();
_window.Hide(); _window.Hide();
_window.Dispose(); _window.Dispose();
_window = null; _window = null;

26
src/Skia/Avalonia.Skia.Android/AndroidPlatformRenderInterface.cs

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Avalonia.Platform;
namespace Avalonia.Skia
{
partial class PlatformRenderInterface
{
public IRenderTarget CreateRenderTarget(IEnumerable<object> surfaces)
{
var surfaceView = surfaces?.OfType<SurfaceView>().FirstOrDefault();
if (surfaceView == null)
throw new ArgumentException("Avalonia.Skia.Android is only capable of drawing on SurfaceView");
return new WindowRenderTarget(surfaceView);
}
}
}

1
src/Skia/Avalonia.Skia.Android/Avalonia.Skia.Android.csproj

@ -87,6 +87,7 @@
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="AndroidPlatformRenderInterface.cs" />
<Compile Include="AndroidRenderTarget.cs" /> <Compile Include="AndroidRenderTarget.cs" />
<Compile Include="RenderTarget.cs" /> <Compile Include="RenderTarget.cs" />
<Compile Include="SkiaRenderView.cs" /> <Compile Include="SkiaRenderView.cs" />

16
src/Skia/Avalonia.Skia.Android/RenderTarget.cs

@ -26,14 +26,14 @@ namespace Avalonia.Skia
internal class WindowRenderTarget : RenderTarget internal class WindowRenderTarget : RenderTarget
{ {
private readonly IPlatformHandle _hwnd; private readonly SurfaceView _surfaceView;
Bitmap _bitmap; Bitmap _bitmap;
int Width { get; set; } int Width { get; set; }
int Height { get; set; } int Height { get; set; }
public WindowRenderTarget(IPlatformHandle hwnd) public WindowRenderTarget(SurfaceView surfaceView)
{ {
_hwnd = hwnd; _surfaceView = surfaceView;
FixSize(); FixSize();
} }
@ -63,9 +63,8 @@ namespace Avalonia.Skia
private void GetPlatformWindowSize(out int w, out int h) private void GetPlatformWindowSize(out int w, out int h)
{ {
var surfaceView = _hwnd as SurfaceView; w = _surfaceView.Width;
w = surfaceView.Width; h = _surfaceView.Height;
h = surfaceView.Height;
} }
public override DrawingContext CreateDrawingContext() public override DrawingContext CreateDrawingContext()
@ -85,11 +84,10 @@ namespace Avalonia.Skia
public void Present() public void Present()
{ {
var surfaceView = _hwnd as SurfaceView;
Canvas canvas = null; Canvas canvas = null;
try try
{ {
canvas = surfaceView.Holder.LockCanvas(null); canvas = _surfaceView.Holder.LockCanvas(null);
_bitmap.UnlockPixels(); _bitmap.UnlockPixels();
canvas.DrawBitmap(_bitmap, 0, 0, null); canvas.DrawBitmap(_bitmap, 0, 0, null);
} }
@ -99,7 +97,7 @@ namespace Avalonia.Skia
finally finally
{ {
if (canvas != null) if (canvas != null)
surfaceView.Holder.UnlockCanvasAndPost(canvas); _surfaceView.Holder.UnlockCanvasAndPost(canvas);
} }
_bitmap.UnlockPixels(); _bitmap.UnlockPixels();

2
src/Skia/Avalonia.Skia.Android/SkiaRenderView.cs

@ -22,7 +22,7 @@ namespace Avalonia.Skia.Android
{ {
_renderTarget = _renderTarget =
AvaloniaLocator.Current.GetService<IPlatformRenderInterface>() AvaloniaLocator.Current.GetService<IPlatformRenderInterface>()
.CreateRenderTarget(this); .CreateRenderTarget(new object[]{this});
} }
protected override void Draw() protected override void Draw()

5
src/Skia/Avalonia.Skia.Desktop/Avalonia.Skia.Desktop.csproj

@ -72,11 +72,8 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="PlatformRenderInterfaceDesktop.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="..\..\Windows\Avalonia.Win32\Interop\UnmanagedMethods.cs">
<Link>UnmanagedMethods.cs</Link>
</Compile>
<Compile Include="RenderTarget.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\Avalonia.Animation\Avalonia.Animation.csproj"> <ProjectReference Include="..\..\Avalonia.Animation\Avalonia.Animation.csproj">

21
src/Skia/Avalonia.Skia.Desktop/PlatformRenderInterfaceDesktop.cs

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Platform;
namespace Avalonia.Skia
{
partial class PlatformRenderInterface
{
public IRenderTarget CreateRenderTarget(IEnumerable<object> surfaces)
{
var fb = surfaces?.OfType<IFramebufferPlatformSurface>().FirstOrDefault();
if (fb == null)
throw new Exception("Avalonia.Skia.Deskop currently only supports framebuffer render target");
return new FramebufferRenderTarget(fb);
}
}
}

1
src/Skia/Avalonia.Skia.iOS/Avalonia.Skia.iOS.csproj

@ -37,6 +37,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="PlatformRenderingInterfaceIos.cs" />
<Compile Include="RenderTarget.cs" /> <Compile Include="RenderTarget.cs" />
<Compile Include="SkiaView.cs" /> <Compile Include="SkiaView.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />

18
src/Skia/Avalonia.Skia.iOS/PlatformRenderingInterfaceIos.cs

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Avalonia.Platform;
using Foundation;
using UIKit;
namespace Avalonia.Skia
{
partial class PlatformRenderInterface
{
public IRenderTarget CreateRenderTarget(IEnumerable<object> surfaces)
{
return new WindowRenderTarget();
}
}
}

5
src/Skia/Avalonia.Skia.iOS/RenderTarget.cs

@ -26,14 +26,13 @@ namespace Avalonia.Skia
internal class WindowRenderTarget : RenderTarget internal class WindowRenderTarget : RenderTarget
{ {
private readonly IPlatformHandle _hwnd;
SKBitmap _bitmap; SKBitmap _bitmap;
int Width { get; set; } int Width { get; set; }
int Height { get; set; } int Height { get; set; }
public WindowRenderTarget(IPlatformHandle hwnd) public WindowRenderTarget()
{ {
_hwnd = hwnd;
FixSize(); FixSize();
} }

1
src/Skia/Avalonia.Skia/Avalonia.Skia.projitems

@ -12,6 +12,7 @@
<Compile Include="$(MSBuildThisFileDirectory)BitmapImpl.cs" /> <Compile Include="$(MSBuildThisFileDirectory)BitmapImpl.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DrawingContextImpl.cs" /> <Compile Include="$(MSBuildThisFileDirectory)DrawingContextImpl.cs" />
<Compile Include="$(MSBuildThisFileDirectory)FormattedTextImpl.cs" /> <Compile Include="$(MSBuildThisFileDirectory)FormattedTextImpl.cs" />
<Compile Include="$(MSBuildThisFileDirectory)FramebufferRenderTarget.cs" />
<Compile Include="$(MSBuildThisFileDirectory)PlatformRenderInterface.cs" /> <Compile Include="$(MSBuildThisFileDirectory)PlatformRenderInterface.cs" />
<Compile Include="$(MSBuildThisFileDirectory)SkiaPlatform.cs" /> <Compile Include="$(MSBuildThisFileDirectory)SkiaPlatform.cs" />
<Compile Include="$(MSBuildThisFileDirectory)SkiaSharpExtensions.cs" /> <Compile Include="$(MSBuildThisFileDirectory)SkiaSharpExtensions.cs" />

77
src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs

@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Text;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Media;
using Avalonia.Platform;
using SkiaSharp;
namespace Avalonia.Skia
{
public class FramebufferRenderTarget : IRenderTarget
{
private readonly IFramebufferPlatformSurface _surface;
public FramebufferRenderTarget(IFramebufferPlatformSurface surface)
{
_surface = surface;
}
public void Dispose()
{
//Nothing to do here, since we don't own framebuffer
}
class FramebufferDrawingContextImpl : DrawingContextImpl
{
private readonly SKCanvas _canvas;
private readonly SKSurface _surface;
private readonly ILockedFramebuffer _framebuffer;
public FramebufferDrawingContextImpl(SKCanvas canvas, SKSurface surface, ILockedFramebuffer framebuffer) : base(canvas)
{
_canvas = canvas;
_surface = surface;
_framebuffer = framebuffer;
}
public override void Dispose()
{
_canvas.Dispose();
_surface.Dispose();
_framebuffer.Dispose();
base.Dispose();
}
}
SKColorType TranslatePixelFormat(PixelFormat fmt)
{
if(fmt == PixelFormat.Rgb565)
return SKColorType.Rgb565;
if(fmt == PixelFormat.Bgra8888)
return SKColorType.Bgra8888;
if (fmt == PixelFormat.Rgba8888)
return SKColorType.Rgba8888;
throw new ArgumentException("Unknown pixel format: " + fmt);
}
public DrawingContext CreateDrawingContext()
{
var fb = _surface.Lock();
SKImageInfo nfo = new SKImageInfo(fb.Width, fb.Height, TranslatePixelFormat(fb.Format),
SKAlphaType.Opaque);
var surface = SKSurface.Create(nfo, fb.Address, fb.RowBytes);
if (surface == null)
throw new Exception("Unable to create a surface for pixel format " + fb.Format);
var canvas = surface.Canvas;
canvas.RestoreToCount(0);
canvas.Save();
canvas.Clear(SKColors.Red);
canvas.ResetMatrix();
return new DrawingContext(new FramebufferDrawingContextImpl(canvas, surface, fb),
Matrix.CreateScale(fb.Dpi.Width / 96, fb.Dpi.Height / 96));
}
}
}

8
src/Skia/Avalonia.Skia/PlatformRenderInterface.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Platform; using Avalonia.Platform;
@ -7,7 +8,7 @@ using SkiaSharp;
namespace Avalonia.Skia namespace Avalonia.Skia
{ {
public class PlatformRenderInterface : IPlatformRenderInterface, IRendererFactory public partial class PlatformRenderInterface : IPlatformRenderInterface, IRendererFactory
{ {
public IBitmapImpl CreateBitmap(int width, int height) public IBitmapImpl CreateBitmap(int width, int height)
{ {
@ -63,10 +64,5 @@ namespace Avalonia.Skia
return new BitmapImpl(width, height); return new BitmapImpl(width, height);
} }
public IRenderTarget CreateRenderTarget(IPlatformHandle handle)
{
return new WindowRenderTarget(handle);
}
} }
} }

2
src/Skia/Avalonia.Skia/WindowDrawingContextImpl.cs

@ -1,6 +1,7 @@
namespace Avalonia.Skia namespace Avalonia.Skia
{ {
#if !DESKTOP
// not sure we need this yet // not sure we need this yet
internal class WindowDrawingContextImpl : DrawingContextImpl internal class WindowDrawingContextImpl : DrawingContextImpl
{ {
@ -18,4 +19,5 @@ namespace Avalonia.Skia
_target.Present(); _target.Present();
} }
} }
#endif
} }

19
src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs

@ -2,11 +2,14 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using Avalonia.Direct2D1.Media; using Avalonia.Direct2D1.Media;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Rendering; using Avalonia.Rendering;
namespace Avalonia namespace Avalonia
@ -99,18 +102,16 @@ namespace Avalonia.Direct2D1
return new Renderer(root, renderLoop); return new Renderer(root, renderLoop);
} }
public IRenderTarget CreateRenderTarget(IPlatformHandle handle) public IRenderTarget CreateRenderTarget(IEnumerable<object> surfaces)
{ {
if (handle.HandleDescriptor == "HWND") var nativeWindow = surfaces?.OfType<IPlatformHandle>().FirstOrDefault();
if (nativeWindow != null)
{ {
return new HwndRenderTarget(handle.Handle); if(nativeWindow.HandleDescriptor != "HWND")
} throw new NotSupportedException("Don't know how to create a Direct2D1 renderer from " + nativeWindow.HandleDescriptor);
else return new HwndRenderTarget(nativeWindow);
{
throw new NotSupportedException(string.Format(
"Don't know how to create a Direct2D1 renderer from a '{0}' handle",
handle.HandleDescriptor));
} }
throw new NotSupportedException("Don't know how to create a Direct2D1 renderer from any of provided surfaces");
} }
public IRenderTargetBitmapImpl CreateRenderTargetBitmap(int width, int height) public IRenderTargetBitmapImpl CreateRenderTargetBitmap(int width, int height)

14
src/Windows/Avalonia.Direct2D1/HwndRenderTarget.cs

@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Platform;
using Avalonia.Win32.Interop; using Avalonia.Win32.Interop;
using SharpDX; using SharpDX;
using SharpDX.DXGI; using SharpDX.DXGI;
@ -11,16 +13,16 @@ namespace Avalonia.Direct2D1
{ {
class HwndRenderTarget : SwapChainRenderTarget class HwndRenderTarget : SwapChainRenderTarget
{ {
private readonly IntPtr _hwnd; private readonly IPlatformHandle _window;
public HwndRenderTarget(IntPtr hwnd) public HwndRenderTarget(IPlatformHandle window)
{ {
_hwnd = hwnd; _window = window;
} }
protected override SwapChain1 CreateSwapChain(Factory2 dxgiFactory, SwapChainDescription1 swapChainDesc) protected override SwapChain1 CreateSwapChain(Factory2 dxgiFactory, SwapChainDescription1 swapChainDesc)
{ {
return new SwapChain1(dxgiFactory, DxgiDevice, _hwnd, ref swapChainDesc); return new SwapChain1(dxgiFactory, DxgiDevice, _window.Handle, ref swapChainDesc);
} }
protected override Size2F GetWindowDpi() protected override Size2F GetWindowDpi()
@ -30,7 +32,7 @@ namespace Avalonia.Direct2D1
uint dpix, dpiy; uint dpix, dpiy;
var monitor = UnmanagedMethods.MonitorFromWindow( var monitor = UnmanagedMethods.MonitorFromWindow(
_hwnd, _window.Handle,
UnmanagedMethods.MONITOR.MONITOR_DEFAULTTONEAREST); UnmanagedMethods.MONITOR.MONITOR_DEFAULTTONEAREST);
if (UnmanagedMethods.GetDpiForMonitor( if (UnmanagedMethods.GetDpiForMonitor(
@ -49,7 +51,7 @@ namespace Avalonia.Direct2D1
protected override Size2 GetWindowSize() protected override Size2 GetWindowSize()
{ {
UnmanagedMethods.RECT rc; UnmanagedMethods.RECT rc;
UnmanagedMethods.GetClientRect(_hwnd, out rc); UnmanagedMethods.GetClientRect(_window.Handle, out rc);
return new Size2(rc.right - rc.left, rc.bottom - rc.top); return new Size2(rc.right - rc.left, rc.bottom - rc.top);
} }
} }

2
src/Windows/Avalonia.Win32/Avalonia.Win32.csproj

@ -69,6 +69,8 @@
<SubType>Component</SubType> <SubType>Component</SubType>
</Compile> </Compile>
<Compile Include="Embedding\WpfAvaloniaControlHost.cs" /> <Compile Include="Embedding\WpfAvaloniaControlHost.cs" />
<Compile Include="WindowFramebuffer.cs" />
<Compile Include="FramebufferManager.cs" />
<Compile Include="IconImpl.cs" /> <Compile Include="IconImpl.cs" />
<Compile Include="RenderLoop.cs" /> <Compile Include="RenderLoop.cs" />
<Compile Include="SystemDialogImpl.cs" /> <Compile Include="SystemDialogImpl.cs" />

41
src/Windows/Avalonia.Win32/FramebufferManager.cs

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Win32.Interop;
namespace Avalonia.Win32
{
class FramebufferManager : IFramebufferPlatformSurface, IDisposable
{
private readonly IntPtr _hwnd;
private WindowFramebuffer _fb;
public FramebufferManager(IntPtr hwnd)
{
_hwnd = hwnd;
}
public ILockedFramebuffer Lock()
{
UnmanagedMethods.RECT rc;
UnmanagedMethods.GetClientRect(_hwnd, out rc);
var width = rc.right - rc.left;
var height = rc.bottom - rc.top;
if (_fb == null || _fb.Width != width || _fb.Height != height)
{
_fb?.Deallocate();
_fb = null;
_fb = new WindowFramebuffer(_hwnd, width, height);
}
return _fb;
}
public void Dispose()
{
_fb?.Deallocate();
}
}
}

48
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@ -568,6 +568,27 @@ namespace Avalonia.Win32.Interop
public byte rgbReserved; public byte rgbReserved;
} }
[StructLayout(LayoutKind.Sequential)]
public struct BITMAPINFOHEADER
{
public uint biSize;
public int biWidth;
public int biHeight;
public ushort biPlanes;
public ushort biBitCount;
public uint biCompression;
public uint biSizeImage;
public int biXPelsPerMeter;
public int biYPelsPerMeter;
public uint biClrUsed;
public uint biClrImportant;
public void Init()
{
biSize = (uint)Marshal.SizeOf(this);
}
}
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct BITMAPINFO public struct BITMAPINFO
{ {
@ -859,6 +880,31 @@ namespace Avalonia.Win32.Interop
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("gdi32.dll")]
public static extern int SetDIBitsToDevice(IntPtr hdc, int XDest, int YDest, uint
dwWidth, uint dwHeight, int XSrc, int YSrc, uint uStartScan, uint cScanLines,
IntPtr lpvBits, [In] ref BITMAPINFOHEADER lpbmi, uint fuColorUse);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("gdi32.dll", SetLastError = true)]
public static extern IntPtr CreateDIBSection(IntPtr hDC, ref BITMAPINFOHEADER pBitmapInfo, int un, out IntPtr lplpVoid, IntPtr handle, int dw);
[DllImport("gdi32.dll")]
public static extern int DeleteObject(IntPtr hObject);
[DllImport("gdi32.dll", SetLastError = true)]
public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport("gdi32.dll")]
public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr CreateFileMapping(IntPtr hFile,
IntPtr lpFileMappingAttributes,
uint flProtect,
uint dwMaximumSizeHigh,
uint dwMaximumSizeLow,
string lpName);
public enum MONITOR public enum MONITOR
{ {
MONITOR_DEFAULTTONULL = 0x00000000, MONITOR_DEFAULTTONULL = 0x00000000,
@ -1177,6 +1223,7 @@ namespace Avalonia.Win32.Interop
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter); uint SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter);
} }
@ -1197,5 +1244,6 @@ namespace Avalonia.Win32.Interop
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
uint Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder); uint Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder);
} }
} }

121
src/Windows/Avalonia.Win32/WindowFramebuffer.cs

@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Interop;
using System.Windows.Media;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Win32.Interop;
using PixelFormat = Avalonia.Controls.Platform.Surfaces.PixelFormat;
namespace Avalonia.Win32
{
public class WindowFramebuffer : ILockedFramebuffer
{
private readonly IntPtr _handle;
private IntPtr _pBitmap;
private UnmanagedMethods.BITMAPINFOHEADER _bmpInfo;
public WindowFramebuffer(IntPtr handle, int width, int height)
{
if (width <= 0)
throw new ArgumentException("width is less than zero");
if (height <= 0)
throw new ArgumentException("height is less than zero");
_handle = handle;
_bmpInfo.Init();
_bmpInfo.biPlanes = 1;
_bmpInfo.biBitCount = 32;
_bmpInfo.Init();
_bmpInfo.biWidth = width;
_bmpInfo.biHeight = -height;
_pBitmap = Marshal.AllocHGlobal(width * height * 4);
}
~WindowFramebuffer()
{
Deallocate();
}
public IntPtr Address => _pBitmap;
public int RowBytes => Width * 4;
public PixelFormat Format => PixelFormat.Bgra8888;
public Size Dpi
{
get
{
if (UnmanagedMethods.ShCoreAvailable)
{
uint dpix, dpiy;
var monitor = UnmanagedMethods.MonitorFromWindow(_handle,
UnmanagedMethods.MONITOR.MONITOR_DEFAULTTONEAREST);
if (UnmanagedMethods.GetDpiForMonitor(
monitor,
UnmanagedMethods.MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI,
out dpix,
out dpiy) == 0)
{
return new Size(dpix, dpiy);
}
}
return new Size(96, 96);
}
}
public int Width => _bmpInfo.biWidth;
public int Height => -_bmpInfo.biHeight;
public void DrawToDevice(IntPtr hDC, int destX = 0, int destY = 0, int srcX = 0, int srcY = 0, int width = -1,
int height = -1)
{
if(_pBitmap == IntPtr.Zero)
throw new ObjectDisposedException("Framebuffer");
if (width == -1)
width = Width;
if (height == -1)
height = Height;
UnmanagedMethods.SetDIBitsToDevice(hDC, destX, destY, (uint) width, (uint) height, srcX, srcY,
0, (uint)Height, _pBitmap, ref _bmpInfo, 0);
}
public bool DrawToWindow(IntPtr hWnd, int destX = 0, int destY = 0, int srcX = 0, int srcY = 0, int width = -1,
int height = -1)
{
if (_pBitmap == IntPtr.Zero)
throw new ObjectDisposedException("Framebuffer");
if (hWnd == IntPtr.Zero)
return false;
IntPtr hDC = UnmanagedMethods.GetDC(hWnd);
if (hDC == IntPtr.Zero)
return false;
DrawToDevice(hDC, destX, destY, srcX, srcY, width, height);
UnmanagedMethods.ReleaseDC(hWnd, hDC);
return true;
}
public void Dispose()
{
//It's not an *actual* dispose. This call means "We are done drawing"
DrawToWindow(_handle);
}
public void Deallocate()
{
if (_pBitmap != IntPtr.Zero)
{
Marshal.FreeHGlobal(_pBitmap);
_pBitmap = IntPtr.Zero;
}
}
}
}

9
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -11,6 +11,7 @@ using System.Reactive.Disposables;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Input.Raw; using Avalonia.Input.Raw;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Win32.Input; using Avalonia.Win32.Input;
@ -35,10 +36,12 @@ namespace Avalonia.Win32
private bool _decorated = true; private bool _decorated = true;
private double _scaling = 1; private double _scaling = 1;
private WindowState _showWindowState; private WindowState _showWindowState;
private FramebufferManager _framebuffer;
public WindowImpl() public WindowImpl()
{ {
CreateWindow(); CreateWindow();
_framebuffer = new FramebufferManager(_hwnd);
s_instances.Add(this); s_instances.Add(this);
} }
@ -161,6 +164,11 @@ namespace Avalonia.Win32
} }
} }
public IEnumerable<object> Surfaces => new object[]
{
Handle, _framebuffer
};
public void Activate() public void Activate()
{ {
UnmanagedMethods.SetActiveWindow(_hwnd); UnmanagedMethods.SetActiveWindow(_hwnd);
@ -174,6 +182,7 @@ namespace Avalonia.Win32
public void Dispose() public void Dispose()
{ {
s_instances.Remove(this); s_instances.Remove(this);
_framebuffer.Dispose();
UnmanagedMethods.DestroyWindow(_hwnd); UnmanagedMethods.DestroyWindow(_hwnd);
} }

3
src/iOS/Avalonia.iOS/AvaloniaView.cs

@ -149,6 +149,9 @@ namespace Avalonia.iOS
} }
public Size MaxClientSize => Bounds.Size.ToAvalonia(); public Size MaxClientSize => Bounds.Size.ToAvalonia();
public IEnumerable<object> Surfaces => new object[] { this };
public void SetTitle(string title) public void SetTitle(string title)
{ {
//Not supported //Not supported

2
tests/Avalonia.Input.UnitTests/InputElement_HitTesting.cs

@ -340,7 +340,7 @@ namespace Avalonia.Input.UnitTests
throw new NotImplementedException(); throw new NotImplementedException();
} }
public IRenderTarget CreateRenderTarget(IPlatformHandle handle) public IRenderTarget CreateRenderTarget(IEnumerable<object> surfaces)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }

2
tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs

@ -20,7 +20,7 @@ namespace Avalonia.Visuals.UnitTests.VisualTree
throw new NotImplementedException(); throw new NotImplementedException();
} }
public IRenderTarget CreateRenderTarget(IPlatformHandle handle) public IRenderTarget CreateRenderTarget(IEnumerable<object> surfaces)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }

Loading…
Cancel
Save