Browse Source

Merge branch 'master' into scenegraph

pull/827/head
danwalmsley 9 years ago
committed by GitHub
parent
commit
daafa39bba
  1. 1
      appveyor.yml
  2. 1
      build/SharpDX.props
  3. 3
      packages.cake
  4. 2
      samples/interop/WindowsInteropTest/Program.cs
  5. 9
      src/Avalonia.Controls/TextBox.cs
  6. 30
      src/Avalonia.Controls/ToolTip.cs
  7. 12
      src/Skia/Avalonia.Skia/DrawingContextImpl.cs
  8. 101
      src/Skia/Avalonia.Skia/FormattedTextImpl.cs
  9. 11
      src/Windows/Avalonia.Direct2D1/ExternalRenderTarget.cs
  10. 3
      src/Windows/Avalonia.Direct2D1/IExternalDirect2DRenderTargetSurface.cs
  11. 10
      src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj
  12. 208
      src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs
  13. 59
      src/Windows/Avalonia.Win32.Interop/Wpf/IntSize.cs
  14. 21
      src/Windows/Avalonia.Win32.Interop/Wpf/WpfAvaloniaHost.cs
  15. 18
      src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs
  16. 10
      src/Windows/Avalonia.Win32.Interop/Wpf/WritableBitmapSurface.cs

1
appveyor.yml

@ -15,6 +15,7 @@ environment:
MYGET_API_URL: https://www.myget.org/F/avalonia-ci/api/v2/package
init:
- ps: (New-Object Net.WebClient).DownloadFile('https://raw.githubusercontent.com/appveyor/ci/master/scripts/xamarin-vs2017-151-fixed.targets', "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Microsoft.Common.Targets\ImportAfter\Xamarin.Common.targets")
- ps: if (Test-Path env:nuget_address) {[System.IO.File]::AppendAllText("C:\Windows\System32\drivers\etc\hosts", "`n$($env:nuget_address)`tapi.nuget.org")}
install:
- if not exist gtk-sharp-2.12.26.msi appveyor DownloadFile http://download.xamarin.com/GTKforWindows/Windows/gtk-sharp-2.12.26.msi
- if not exist dotnet-1.0.1.exe appveyor DownloadFile https://go.microsoft.com/fwlink/?linkid=843448 -FileName "dotnet-1.0.1.exe"

1
build/SharpDX.props

@ -3,6 +3,7 @@
<PackageReference Include="SharpDX" Version="3.1.1" />
<PackageReference Include="SharpDX.Direct2D1" Version="3.1.1" />
<PackageReference Include="SharpDX.Direct3D11" Version="3.1.1" />
<PackageReference Include="SharpDX.Direct3D9" Version="3.1.1" Condition="'$(UseDirect3D9)' == 'true'" />
<PackageReference Include="SharpDX.DXGI" Version="3.1.1" />
</ItemGroup>
</Project>

3
packages.cake

@ -81,6 +81,7 @@ public class Packages
var SharpDXVersion = packageVersions["SharpDX"].FirstOrDefault().Item1;
var SharpDXDirect2D1Version = packageVersions["SharpDX.Direct2D1"].FirstOrDefault().Item1;
var SharpDXDirect3D11Version = packageVersions["SharpDX.Direct3D11"].FirstOrDefault().Item1;
var SharpDXDirect3D9Version = packageVersions["SharpDX.Direct3D9"].FirstOrDefault().Item1;
var SharpDXDXGIVersion = packageVersions["SharpDX.DXGI"].FirstOrDefault().Item1;
context.Information("Package: Serilog, version: {0}", SerilogVersion);
@ -93,6 +94,7 @@ public class Packages
context.Information("Package: SharpDX, version: {0}", SharpDXVersion);
context.Information("Package: SharpDX.Direct2D1, version: {0}", SharpDXDirect2D1Version);
context.Information("Package: SharpDX.Direct3D11, version: {0}", SharpDXDirect3D11Version);
context.Information("Package: SharpDX.Direct3D9, version: {0}", SharpDXDirect3D9Version);
context.Information("Package: SharpDX.DXGI, version: {0}", SharpDXDXGIVersion);
var nugetPackagesDir = System.Environment.GetEnvironmentVariable("NUGET_HOME")
@ -476,6 +478,7 @@ public class Packages
{
new NuSpecDependency() { Id = "Avalonia.Win32", Version = parameters.Version },
new NuSpecDependency() { Id = "Avalonia.Direct2D1", Version = parameters.Version },
new NuSpecDependency() { Id = "SharpDX.Direct3D9", Version = SharpDXDirect3D9Version },
},
Files = new []
{

2
samples/interop/WindowsInteropTest/Program.cs

@ -15,7 +15,7 @@ namespace WindowsInteropTest
{
System.Windows.Forms.Application.EnableVisualStyles();
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
AppBuilder.Configure<App>().UseWin32().UseSkia().SetupWithoutStarting();
AppBuilder.Configure<App>().UseWin32().UseDirect2D1().SetupWithoutStarting();
System.Windows.Forms.Application.Run(new SelectorForm());
}
}

9
src/Avalonia.Controls/TextBox.cs

@ -236,6 +236,11 @@ namespace Avalonia.Controls
{
_presenter = e.NameScope.Get<TextPresenter>("PART_TextPresenter");
_presenter.Cursor = new Cursor(StandardCursorType.Ibeam);
if(IsFocused)
{
_presenter.ShowCaret();
}
}
protected override void OnGotFocus(GotFocusEventArgs e)
@ -254,7 +259,7 @@ namespace Avalonia.Controls
}
else
{
_presenter.ShowCaret();
_presenter?.ShowCaret();
}
}
@ -263,7 +268,7 @@ namespace Avalonia.Controls
base.OnLostFocus(e);
SelectionStart = 0;
SelectionEnd = 0;
_presenter.HideCaret();
_presenter?.HideCaret();
}
protected override void OnTextInput(TextInputEventArgs e)

30
src/Avalonia.Controls/ToolTip.cs

@ -106,24 +106,28 @@ namespace Avalonia.Controls
if (control != null && control.IsVisible && control.GetVisualRoot() != null)
{
var cp = (control.GetVisualRoot() as IInputRoot)?.MouseDevice?.GetPosition(control);
var position = control.PointToScreen(cp ?? new Point(0, 0)) + new Vector(0, 22);
if (s_popup == null)
if (cp.HasValue && control.IsVisible && new Rect(control.Bounds.Size).Contains(cp.Value))
{
s_popup = new PopupRoot();
s_popup.Content = new ToolTip();
}
else
{
((ISetLogicalParent)s_popup).SetParent(null);
}
var position = control.PointToScreen(cp.Value) + new Vector(0, 22);
if (s_popup == null)
{
s_popup = new PopupRoot();
s_popup.Content = new ToolTip();
}
else
{
((ISetLogicalParent)s_popup).SetParent(null);
}
((ISetLogicalParent)s_popup).SetParent(control);
((ToolTip)s_popup.Content).Content = GetTip(control);
s_popup.Position = position;
s_popup.Show();
((ToolTip)s_popup.Content).Content = GetTip(control);
s_popup.Position = position;
s_popup.Show();
s_current = control;
s_current = control;
}
}
}

12
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@ -154,23 +154,17 @@ namespace Avalonia.Skia
var rv = new PaintWrapper(paint);
paint.IsStroke = false;
// TODO: SkiaSharp does not contain alpha yet!
double opacity = brush.Opacity * _currentOpacity;
//paint.SetAlpha(paint.GetAlpha() * opacity);
paint.IsAntialias = true;
SKColor color = new SKColor(255, 255, 255, 255);
var solid = brush as ISolidColorBrush;
if (solid != null)
color = solid.Color.ToSKColor();
paint.Color = (new SKColor(color.Red, color.Green, color.Blue, (byte)(color.Alpha * opacity)));
if (solid != null)
{
paint.Color = new SKColor(solid.Color.R, solid.Color.G, solid.Color.B, (byte) (solid.Color.A * opacity));
return rv;
}
paint.Color = (new SKColor(255, 255, 255, (byte)(255 * opacity)));
var gradient = brush as IGradientBrush;
if (gradient != null)

101
src/Skia/Avalonia.Skia/FormattedTextImpl.cs

@ -42,7 +42,6 @@ namespace Avalonia.Skia
_paint.Typeface = skiaTypeface;
_paint.TextSize = (float)(typeface?.FontSize ?? 12);
_paint.TextAlign = textAlignment.ToSKTextAlign();
_paint.BlendMode = SKBlendMode.Src;
_wrapping = wrapping;
_constraint = constraint;
@ -200,66 +199,65 @@ namespace Avalonia.Skia
}
ctx->Canvas->restore();
*/
SKPaint paint = _paint;
IDisposable currd = null;
var currentWrapper = foreground;
try
using (var paint = _paint.Clone())
{
SKPaint currFGPaint = ApplyWrapperTo(ref foreground, ref currd, paint);
bool hasCusomFGBrushes = _foregroundBrushes.Any();
for (int c = 0; c < _skiaLines.Count; c++)
IDisposable currd = null;
var currentWrapper = foreground;
SKPaint currentPaint = null;
try
{
AvaloniaFormattedTextLine line = _skiaLines[c];
float x = TransformX(origin.X, 0, paint.TextAlign);
ApplyWrapperTo(ref currentPaint, foreground, ref currd, paint);
bool hasCusomFGBrushes = _foregroundBrushes.Any();
if (!hasCusomFGBrushes)
{
var subString = Text.Substring(line.Start, line.Length);
canvas.DrawText(subString, x, origin.Y + line.Top + _lineOffset, paint);
}
else
for (int c = 0; c < _skiaLines.Count; c++)
{
float currX = x;
string subStr;
int len;
AvaloniaFormattedTextLine line = _skiaLines[c];
for (int i = line.Start; i < line.Start + line.Length;)
{
var fb = GetNextForegroundBrush(ref line, i, out len);
if (fb != null)
{
//TODO: figure out how to get the brush size
currentWrapper = context.CreatePaint(fb, new Size());
}
else
{
if (!currentWrapper.Equals(foreground)) currentWrapper.Dispose();
currentWrapper = foreground;
}
float x = TransformX(origin.X, 0, paint.TextAlign);
subStr = Text.Substring(i, len);
if (!hasCusomFGBrushes)
{
var subString = Text.Substring(line.Start, line.Length);
canvas.DrawText(subString, x, origin.Y + line.Top + _lineOffset, paint);
}
else
{
float currX = x;
string subStr;
int len;
if (currFGPaint != currentWrapper.Paint)
for (int i = line.Start; i < line.Start + line.Length;)
{
currFGPaint = ApplyWrapperTo(ref currentWrapper, ref currd, paint);
var fb = GetNextForegroundBrush(ref line, i, out len);
if (fb != null)
{
//TODO: figure out how to get the brush size
currentWrapper = context.CreatePaint(fb, new Size());
}
else
{
if (!currentWrapper.Equals(foreground)) currentWrapper.Dispose();
currentWrapper = foreground;
}
subStr = Text.Substring(i, len);
ApplyWrapperTo(ref currentPaint, currentWrapper, ref currd, paint);
canvas.DrawText(subStr, currX, origin.Y + line.Top + _lineOffset, paint);
i += len;
currX += paint.MeasureText(subStr);
}
canvas.DrawText(subStr, currX, origin.Y + line.Top + _lineOffset, paint);
i += len;
currX += paint.MeasureText(subStr);
}
}
}
}
finally
{
if (!currentWrapper.Equals(foreground)) currentWrapper.Dispose();
currd?.Dispose();
finally
{
if (!currentWrapper.Equals(foreground)) currentWrapper.Dispose();
currd?.Dispose();
}
}
}
@ -278,12 +276,13 @@ namespace Avalonia.Skia
private Size _size;
private List<AvaloniaFormattedTextLine> _skiaLines;
private static SKPaint ApplyWrapperTo(ref DrawingContextImpl.PaintWrapper wrapper,
private static void ApplyWrapperTo(ref SKPaint current, DrawingContextImpl.PaintWrapper wrapper,
ref IDisposable curr, SKPaint paint)
{
if (current == wrapper.Paint)
return;
curr?.Dispose();
curr = wrapper.ApplyTo(paint);
return wrapper.Paint;
}
private static bool IsBreakChar(char c)

11
src/Windows/Avalonia.Direct2D1/ExternalRenderTarget.cs

@ -15,7 +15,6 @@ namespace Avalonia.Direct2D1
{
private readonly IExternalDirect2DRenderTargetSurface _externalRenderTargetProvider;
private readonly DirectWriteFactory _dwFactory;
private SharpDX.Direct2D1.RenderTarget _target;
public ExternalRenderTarget(IExternalDirect2DRenderTargetSurface externalRenderTargetProvider,
DirectWriteFactory dwFactory)
{
@ -25,15 +24,14 @@ namespace Avalonia.Direct2D1
public void Dispose()
{
_target?.Dispose();
_target = null;
_externalRenderTargetProvider.DestroyRenderTarget();
}
public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
{
_target = _target ?? _externalRenderTargetProvider.CreateRenderTarget();
var target = _externalRenderTargetProvider.GetOrCreateRenderTarget();
_externalRenderTargetProvider.BeforeDrawing();
return new DrawingContextImpl(visualBrushRenderer, _target, _dwFactory, null, () =>
return new DrawingContextImpl(visualBrushRenderer, target, _dwFactory, null, () =>
{
try
{
@ -41,8 +39,7 @@ namespace Avalonia.Direct2D1
}
catch (SharpDXException ex) when ((uint) ex.HResult == 0x8899000C) // D2DERR_RECREATE_TARGET
{
_target?.Dispose();
_target = null;
_externalRenderTargetProvider.DestroyRenderTarget();
}
});
}

3
src/Windows/Avalonia.Direct2D1/IExternalDirect2DRenderTargetSurface.cs

@ -8,7 +8,8 @@ namespace Avalonia.Direct2D1
{
public interface IExternalDirect2DRenderTargetSurface
{
SharpDX.Direct2D1.RenderTarget CreateRenderTarget();
SharpDX.Direct2D1.RenderTarget GetOrCreateRenderTarget();
void DestroyRenderTarget();
void BeforeDrawing();
void AfterDrawing();
}

10
src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj

@ -49,6 +49,8 @@
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Wpf\CursorShim.cs" />
<Compile Include="Wpf\Direct2DImageSurface.cs" />
<Compile Include="Wpf\IntSize.cs" />
<Compile Include="Wpf\WpfInteropExtensions.cs" />
<Compile Include="Wpf\WpfAvaloniaHost.cs" />
<Compile Include="Wpf\WpfMouseDevice.cs" />
@ -104,10 +106,18 @@
<Project>{6417e941-21bc-467b-a771-0de389353ce6}</Project>
<Name>Avalonia.Markup</Name>
</ProjectReference>
<ProjectReference Include="..\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj">
<Project>{3e908f67-5543-4879-a1dc-08eace79b3cd}</Project>
<Name>Avalonia.Direct2D1</Name>
</ProjectReference>
<ProjectReference Include="..\Avalonia.Win32\Avalonia.Win32.csproj">
<Project>{811a76cf-1cf6-440f-963b-bbe31bd72a82}</Project>
<Name>Avalonia.Win32</Name>
</ProjectReference>
</ItemGroup>
<PropertyGroup>
<UseDirect3D9>true</UseDirect3D9>
</PropertyGroup>
<Import Project="..\..\..\build\SharpDX.props" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

208
src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs

@ -0,0 +1,208 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interop;
using Avalonia.Direct2D1;
using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.Direct3D11;
using SharpDX.Direct3D9;
using SharpDX.DXGI;
using AlphaMode = SharpDX.Direct2D1.AlphaMode;
using Device = SharpDX.Direct3D11.Device;
using Format = SharpDX.DXGI.Format;
using MapFlags = SharpDX.Direct3D11.MapFlags;
using PresentParameters = SharpDX.DXGI.PresentParameters;
using Query = SharpDX.Direct3D11.Query;
using QueryType = SharpDX.Direct3D11.QueryType;
using RenderTarget = SharpDX.Direct2D1.RenderTarget;
using Surface = SharpDX.DXGI.Surface;
using SwapEffect = SharpDX.DXGI.SwapEffect;
using Usage = SharpDX.Direct3D9.Usage;
namespace Avalonia.Win32.Interop.Wpf
{
class Direct2DImageSurface : IExternalDirect2DRenderTargetSurface, IDisposable
{
class SwapBuffer: IDisposable
{
private readonly Query _event;
private readonly SharpDX.Direct3D11.Resource _resource;
private readonly SharpDX.Direct3D11.Resource _sharedResource;
public SharpDX.Direct3D9.Surface Texture { get; }
public RenderTarget Target { get;}
public IntSize Size { get; }
public SwapBuffer(IntSize size, Vector dpi)
{
int width = (int) size.Width;
int height = (int) size.Height;
_event = new Query(s_dxDevice, new QueryDescription {Type = QueryType.Event});
using (var texture = new Texture2D(s_dxDevice, new Texture2DDescription
{
Width = width,
Height = height,
ArraySize = 1,
MipLevels = 1,
Format = Format.B8G8R8A8_UNorm,
Usage = ResourceUsage.Default,
SampleDescription = new SampleDescription(2, 0),
BindFlags = BindFlags.RenderTarget,
}))
using (var surface = texture.QueryInterface<Surface>())
{
_resource = texture.QueryInterface<SharpDX.Direct3D11.Resource>();
Target = new RenderTarget(AvaloniaLocator.Current.GetService<SharpDX.Direct2D1.Factory>(), surface,
new RenderTargetProperties
{
DpiX = (float) dpi.X,
DpiY = (float) dpi.Y,
MinLevel = FeatureLevel.Level_10,
PixelFormat = new PixelFormat(Format.B8G8R8A8_UNorm, AlphaMode.Premultiplied),
});
}
using (var texture = new Texture2D(s_dxDevice, new Texture2DDescription
{
Width = width,
Height = height,
ArraySize = 1,
MipLevels = 1,
Format = Format.B8G8R8A8_UNorm,
Usage = ResourceUsage.Default,
SampleDescription = new SampleDescription(1, 0),
BindFlags = BindFlags.RenderTarget|BindFlags.ShaderResource,
OptionFlags = ResourceOptionFlags.Shared,
}))
using (var resource = texture.QueryInterface<SharpDX.DXGI.Resource>())
{
_sharedResource = texture.QueryInterface<SharpDX.Direct3D11.Resource>();
var handle = resource.SharedHandle;
using (var texture9 = new Texture(s_d3DDevice, texture.Description.Width,
texture.Description.Height, 1,
Usage.RenderTarget, SharpDX.Direct3D9.Format.A8R8G8B8, Pool.Default, ref handle))
Texture = texture9.GetSurfaceLevel(0);
}
Size = size;
}
public void Dispose()
{
Texture?.Dispose();
Target?.Dispose();
_resource?.Dispose();
_sharedResource?.Dispose();
_event?.Dispose();
}
public void Flush()
{
s_dxDevice.ImmediateContext.ResolveSubresource(_resource, 0, _sharedResource, 0, Format.B8G8R8A8_UNorm);
s_dxDevice.ImmediateContext.Flush();
s_dxDevice.ImmediateContext.End(_event);
s_dxDevice.ImmediateContext.GetData(_event).Dispose();
}
}
private D3DImage _image;
private SwapBuffer _backBuffer;
private readonly WpfTopLevelImpl _impl;
private static Device s_dxDevice;
private static Direct3DEx s_d3DContext;
private static DeviceEx s_d3DDevice;
private Vector _oldDpi;
[DllImport("user32.dll", SetLastError = false)]
private static extern IntPtr GetDesktopWindow();
void EnsureDirectX()
{
if(s_d3DDevice != null)
return;
s_d3DContext = new Direct3DEx();
SharpDX.Direct3D9.PresentParameters presentparams = new SharpDX.Direct3D9.PresentParameters
{
Windowed = true,
SwapEffect = SharpDX.Direct3D9.SwapEffect.Discard,
DeviceWindowHandle = GetDesktopWindow(),
PresentationInterval = PresentInterval.Default
};
s_dxDevice = s_dxDevice ?? AvaloniaLocator.Current.GetService<SharpDX.DXGI.Device>()
.QueryInterface<SharpDX.Direct3D11.Device>();
s_d3DDevice = new DeviceEx(s_d3DContext, 0, DeviceType.Hardware, IntPtr.Zero, CreateFlags.HardwareVertexProcessing | CreateFlags.Multithreaded | CreateFlags.FpuPreserve, presentparams);
}
public Direct2DImageSurface(WpfTopLevelImpl impl)
{
_impl = impl;
}
public RenderTarget GetOrCreateRenderTarget()
{
EnsureDirectX();
var scale = _impl.GetScaling();
var size = new IntSize(_impl.ActualWidth * scale.X, _impl.ActualHeight * scale.Y);
var dpi = scale * 96;
if (_backBuffer!=null && _backBuffer.Size == size)
return _backBuffer.Target;
if (_image == null || _oldDpi.X != dpi.X || _oldDpi.Y != dpi.Y)
{
_image = new D3DImage(dpi.X, dpi.Y);
}
_impl.ImageSource = _image;
RemoveAndDispose(ref _backBuffer);
if (size == default(IntSize))
{
_image.Lock();
_image.SetBackBuffer(D3DResourceType.IDirect3DSurface9, IntPtr.Zero);
_image.Unlock();
return null;
}
_backBuffer = new SwapBuffer(size, dpi);
return _backBuffer.Target;
}
void RemoveAndDispose<T>(ref T d) where T : IDisposable
{
d?.Dispose();
d = default(T);
}
void Swap()
{
_backBuffer.Flush();
_image.Lock();
_image.SetBackBuffer(D3DResourceType.IDirect3DSurface9, _backBuffer?.Texture?.NativePointer ?? IntPtr.Zero, true);
_image.AddDirtyRect(new Int32Rect(0, 0, _image.PixelWidth, _image.PixelHeight));
_image.Unlock();
}
public void DestroyRenderTarget()
{
RemoveAndDispose(ref _backBuffer);
}
public void BeforeDrawing()
{
}
public void AfterDrawing() => Swap();
public void Dispose()
{
RemoveAndDispose(ref _backBuffer);
}
}
}

59
src/Windows/Avalonia.Win32.Interop/Wpf/IntSize.cs

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Avalonia.Win32.Interop.Wpf
{
struct IntSize : IEquatable<IntSize>
{
public bool Equals(IntSize other)
{
return Width == other.Width && Height == other.Height;
}
public IntSize(int width, int height)
{
Width = width;
Height = height;
}
public IntSize(double width, double height) : this((int) width, (int) height)
{
}
public static implicit operator IntSize(System.Windows.Size size)
{
return new IntSize {Width = (int) size.Width, Height = (int) size.Height};
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
return obj is IntSize && Equals((IntSize) obj);
}
public override int GetHashCode()
{
unchecked
{
return (Width * 397) ^ Height;
}
}
public static bool operator ==(IntSize left, IntSize right)
{
return left.Equals(right);
}
public static bool operator !=(IntSize left, IntSize right)
{
return !left.Equals(right);
}
public int Width { get; set; }
public int Height { get; set; }
}
}

21
src/Windows/Avalonia.Win32.Interop/Wpf/WpfAvaloniaHost.cs

@ -21,15 +21,32 @@ namespace Avalonia.Win32.Interop.Wpf
{
private WpfTopLevelImpl _impl;
private readonly SynchronizationContext _sync;
private bool _hasChildren;
public WpfAvaloniaHost()
{
_sync = SynchronizationContext.Current;
_impl = new WpfTopLevelImpl();
_impl.ControlRoot.Prepare();
_impl.Visibility = Visibility.Visible;
AddLogicalChild(_impl);
AddVisualChild(_impl);
SnapsToDevicePixels = true;
UseLayoutRounding = true;
PresentationSource.AddSourceChangedHandler(this, OnSourceChanged);
}
private void OnSourceChanged(object sender, SourceChangedEventArgs e)
{
if (e.NewSource != null && !_hasChildren)
{
AddLogicalChild(_impl);
AddVisualChild(_impl);
_hasChildren = true;
}
else
{
RemoveVisualChild(_impl);
RemoveLogicalChild(_impl);
_hasChildren = false;
}
}
public object Content

18
src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs

@ -60,7 +60,7 @@ namespace Avalonia.Win32.Interop.Wpf
PresentationSource.AddSourceChangedHandler(this, OnSourceChanged);
_hook = WndProc;
_ttl = this;
_surfaces = new object[] {new WritableBitmapSurface(this)};
_surfaces = new object[] {new WritableBitmapSurface(this), new Direct2DImageSurface(this)};
_mouse = new WpfMouseDevice(this);
_keyboard = AvaloniaLocator.Current.GetService<IKeyboardDevice>();
@ -88,7 +88,12 @@ namespace Avalonia.Win32.Interop.Wpf
_ttl.ScalingChanged?.Invoke(_ttl.Scaling);
}
public void Dispose() => _ttl.Closed?.Invoke();
public void Dispose()
{
_ttl.Closed?.Invoke();
foreach(var d in _surfaces.OfType<IDisposable>())
d.Dispose();
}
Size ITopLevelImpl.ClientSize => _finalSize;
IMouseDevice ITopLevelImpl.MouseDevice => _mouse;
@ -224,6 +229,13 @@ namespace Avalonia.Win32.Interop.Wpf
Action<double> ITopLevelImpl.ScalingChanged { get; set; }
Action ITopLevelImpl.Closed { get; set; }
public new event Action LostFocus;
internal Vector GetScaling()
{
var src = PresentationSource.FromVisual(this)?.CompositionTarget;
if (src == null)
return new Vector(1, 1);
return new Vector(src.TransformToDevice.M11, src.TransformToDevice.M22);
}
}
}

10
src/Windows/Avalonia.Win32.Interop/Wpf/WritableBitmapSurface.cs

@ -24,7 +24,7 @@ namespace Avalonia.Win32.Interop.Wpf
public ILockedFramebuffer Lock()
{
var scale = GetScaling();
var scale = _impl.GetScaling();
var size = new Size(_impl.ActualWidth * scale.X, _impl.ActualHeight * scale.Y);
var dpi = scale * 96;
if (_bitmap == null || _bitmap.PixelWidth != (int) size.Width || _bitmap.PixelHeight != (int) size.Height)
@ -69,13 +69,5 @@ namespace Avalonia.Win32.Interop.Wpf
public Vector Dpi { get; }
public PixelFormat Format => PixelFormat.Bgra8888;
}
Vector GetScaling()
{
var src = PresentationSource.FromVisual(_impl)?.CompositionTarget;
if (src == null)
return new Vector(1, 1);
return new Vector(src.TransformToDevice.M11, src.TransformToDevice.M22);
}
}
}

Loading…
Cancel
Save