Browse Source
Conflicts: src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cspull/1184/head
40 changed files with 420 additions and 85 deletions
@ -0,0 +1,26 @@ |
|||
using System; |
|||
using Avalonia.Media; |
|||
using Avalonia.Platform; |
|||
|
|||
namespace Avalonia.Rendering.SceneGraph |
|||
{ |
|||
/// <summary>
|
|||
/// Base class for draw operations that have bounds.
|
|||
/// </summary>
|
|||
internal abstract class DrawOperation : IDrawOperation |
|||
{ |
|||
public DrawOperation(Rect bounds, Matrix transform, Pen pen) |
|||
{ |
|||
bounds = bounds.Inflate((pen?.Thickness ?? 0) / 2).TransformToAABB(transform); |
|||
Bounds = new Rect( |
|||
new Point(Math.Floor(bounds.X), Math.Floor(bounds.Y)), |
|||
new Point(Math.Ceiling(bounds.Right), Math.Ceiling(bounds.Bottom))); |
|||
} |
|||
|
|||
public Rect Bounds { get; } |
|||
|
|||
public abstract bool HitTest(Point p); |
|||
|
|||
public abstract void Render(IDrawingContextImpl context); |
|||
} |
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
using System; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace Avalonia.Gtk3 |
|||
{ |
|||
class X11 |
|||
{ |
|||
[DllImport("libX11.so.6")] |
|||
public static extern IntPtr XOpenDisplay(IntPtr name); |
|||
|
|||
[DllImport("libX11.so.6")] |
|||
public static extern IntPtr XFreeGC(IntPtr display, IntPtr gc); |
|||
|
|||
[DllImport("libX11.so.6")] |
|||
public static extern IntPtr XCreateGC(IntPtr display, IntPtr drawable, ulong valuemask, IntPtr values); |
|||
|
|||
[DllImport("libX11.so.6")] |
|||
public static extern int XInitImage(ref XImage image); |
|||
|
|||
[DllImport("libX11.so.6")] |
|||
public static extern int XDestroyImage(ref XImage image); |
|||
|
|||
[DllImport("libX11.so.6")] |
|||
public static extern IntPtr XSetErrorHandler(XErrorHandler handler); |
|||
|
|||
public delegate int XErrorHandler(IntPtr display, IntPtr error); |
|||
|
|||
[DllImport("libX11.so.6")] |
|||
public static extern int XPutImage(IntPtr display, IntPtr drawable, IntPtr gc, ref XImage image, |
|||
int srcx, int srcy, int destx, int desty, uint width, uint height); |
|||
|
|||
|
|||
public unsafe struct XImage |
|||
{ |
|||
public int width, height; /* size of image */ |
|||
public int xoffset; /* number of pixels offset in X direction */ |
|||
public int format; /* XYBitmap, XYPixmap, ZPixmap */ |
|||
public IntPtr data; /* pointer to image data */ |
|||
public int byte_order; /* data byte order, LSBFirst, MSBFirst */ |
|||
public int bitmap_unit; /* quant. of scanline 8, 16, 32 */ |
|||
public int bitmap_bit_order; /* LSBFirst, MSBFirst */ |
|||
public int bitmap_pad; /* 8, 16, 32 either XY or ZPixmap */ |
|||
public int depth; /* depth of image */ |
|||
public int bytes_per_line; /* accelerator to next scanline */ |
|||
public int bits_per_pixel; /* bits per pixel (ZPixmap) */ |
|||
public ulong red_mask; /* bits in z arrangement */ |
|||
public ulong green_mask; |
|||
public ulong blue_mask; |
|||
private fixed byte funcs[128]; |
|||
} |
|||
|
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
using System; |
|||
using System.Runtime.InteropServices; |
|||
using Avalonia.Platform; |
|||
|
|||
namespace Avalonia.Gtk3 |
|||
{ |
|||
class X11Framebuffer : ILockedFramebuffer |
|||
{ |
|||
private readonly IntPtr _display; |
|||
private readonly IntPtr _xid; |
|||
private IUnmanagedBlob _blob; |
|||
|
|||
public X11Framebuffer(IntPtr display, IntPtr xid, int width, int height, int factor) |
|||
{ |
|||
_display = display; |
|||
_xid = xid; |
|||
Width = width*factor; |
|||
Height = height*factor; |
|||
RowBytes = Width * 4; |
|||
Dpi = new Vector(96, 96) * factor; |
|||
Format = PixelFormat.Bgra8888; |
|||
_blob = AvaloniaLocator.Current.GetService<IRuntimePlatform>().AllocBlob(RowBytes * Height); |
|||
Address = _blob.Address; |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
var image = new X11.XImage(); |
|||
int bitsPerPixel = 32; |
|||
image.width = Width; |
|||
image.height = Height; |
|||
image.format = 2; //ZPixmap;
|
|||
image.data = Address; |
|||
image.byte_order = 0;// LSBFirst;
|
|||
image.bitmap_unit = bitsPerPixel; |
|||
image.bitmap_bit_order = 0;// LSBFirst;
|
|||
image.bitmap_pad = bitsPerPixel; |
|||
image.depth = 24; |
|||
image.bytes_per_line = RowBytes - Width * 4; |
|||
image.bits_per_pixel = bitsPerPixel; |
|||
X11.XInitImage(ref image); |
|||
var gc = X11.XCreateGC(_display, _xid, 0, IntPtr.Zero); |
|||
X11.XPutImage(_display, _xid, gc, ref image, 0, 0, 0, 0, (uint) Width, (uint) Height); |
|||
X11.XFreeGC(_display, gc); |
|||
_blob.Dispose(); |
|||
} |
|||
|
|||
public IntPtr Address { get; } |
|||
public int Width { get; } |
|||
public int Height { get; } |
|||
public int RowBytes { get; } |
|||
public Vector Dpi { get; } |
|||
public PixelFormat Format { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,84 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
using Avalonia.Controls.Platform.Surfaces; |
|||
using Avalonia.Direct2D1.Media; |
|||
using Avalonia.Direct2D1.Media.Imaging; |
|||
using Avalonia.Platform; |
|||
using Avalonia.Rendering; |
|||
using Avalonia.Win32.Interop; |
|||
using SharpDX.Direct2D1; |
|||
using SharpDX.WIC; |
|||
using PixelFormat = Avalonia.Platform.PixelFormat; |
|||
|
|||
namespace Avalonia.Direct2D1 |
|||
{ |
|||
class FramebufferShimRenderTarget : IRenderTarget |
|||
{ |
|||
private readonly IFramebufferPlatformSurface _surface; |
|||
private readonly ImagingFactory _imagingFactory; |
|||
private readonly Factory _d2DFactory; |
|||
private readonly SharpDX.DirectWrite.Factory _dwriteFactory; |
|||
|
|||
public FramebufferShimRenderTarget(IFramebufferPlatformSurface surface, |
|||
ImagingFactory imagingFactory, Factory d2dFactory, SharpDX.DirectWrite.Factory dwriteFactory) |
|||
{ |
|||
_surface = surface; |
|||
_imagingFactory = imagingFactory; |
|||
_d2DFactory = d2dFactory; |
|||
_dwriteFactory = dwriteFactory; |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
|
|||
} |
|||
|
|||
public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer) |
|||
{ |
|||
var locked = _surface.Lock(); |
|||
if (locked.Format == PixelFormat.Rgb565) |
|||
{ |
|||
locked.Dispose(); |
|||
throw new ArgumentException("Unsupported pixel format: " + locked.Format); |
|||
} |
|||
|
|||
return new FramebufferShim(locked, _imagingFactory, _d2DFactory, _dwriteFactory) |
|||
.CreateDrawingContext(visualBrushRenderer); |
|||
} |
|||
|
|||
class FramebufferShim : WicRenderTargetBitmapImpl |
|||
{ |
|||
private readonly ILockedFramebuffer _target; |
|||
|
|||
public FramebufferShim(ILockedFramebuffer target, |
|||
ImagingFactory imagingFactory, Factory d2dFactory, SharpDX.DirectWrite.Factory dwriteFactory |
|||
) : base(imagingFactory, d2dFactory, dwriteFactory, |
|||
target.Width, target.Height, target.Dpi.X, target.Dpi.Y, target.Format) |
|||
{ |
|||
_target = target; |
|||
} |
|||
|
|||
public override IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer) |
|||
{ |
|||
return base.CreateDrawingContext(visualBrushRenderer, () => |
|||
{ |
|||
using (var l = WicImpl.Lock(BitmapLockFlags.Read)) |
|||
{ |
|||
for (var y = 0; y < _target.Height; y++) |
|||
{ |
|||
UnmanagedMethods.CopyMemory( |
|||
_target.Address + _target.RowBytes * y, |
|||
l.Data.DataPointer + l.Stride * y, |
|||
(uint) Math.Min(l.Stride, _target.RowBytes)); |
|||
} |
|||
} |
|||
Dispose(); |
|||
_target.Dispose(); |
|||
|
|||
}); |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
using System; |
|||
using Avalonia.Media; |
|||
using Avalonia.Platform; |
|||
using Avalonia.Rendering.SceneGraph; |
|||
using Xunit; |
|||
|
|||
namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph |
|||
{ |
|||
public class DrawOperationTests |
|||
{ |
|||
[Fact] |
|||
public void Empty_Bounds_Remain_Empty() |
|||
{ |
|||
var target = new TestDrawOperation(Rect.Empty, Matrix.Identity, null); |
|||
|
|||
Assert.Equal(Rect.Empty, target.Bounds); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(10, 10, 10, 10, 1, 1, 1, 9, 9, 12, 12)] |
|||
[InlineData(10, 10, 10, 10, 1, 1, 2, 9, 9, 12, 12)] |
|||
[InlineData(10, 10, 10, 10, 1.5, 1.5, 1, 14, 14, 17, 17)] |
|||
public void Rectangle_Bounds_Are_Snapped_To_Pixels( |
|||
double x, |
|||
double y, |
|||
double width, |
|||
double height, |
|||
double scaleX, |
|||
double scaleY, |
|||
double? penThickness, |
|||
double expectedX, |
|||
double expectedY, |
|||
double expectedWidth, |
|||
double expectedHeight) |
|||
{ |
|||
var target = new TestDrawOperation( |
|||
new Rect(x, y, width, height), |
|||
Matrix.CreateScale(scaleX, scaleY), |
|||
penThickness.HasValue ? new Pen(Brushes.Black, penThickness.Value) : null); |
|||
Assert.Equal(new Rect(expectedX, expectedY, expectedWidth, expectedHeight), target.Bounds); |
|||
} |
|||
|
|||
private class TestDrawOperation : DrawOperation |
|||
{ |
|||
public TestDrawOperation(Rect bounds, Matrix transform, Pen pen) |
|||
:base(bounds, transform, pen) |
|||
{ |
|||
} |
|||
|
|||
public override bool HitTest(Point p) => false; |
|||
|
|||
public override void Render(IDrawingContextImpl context) { } |
|||
} |
|||
} |
|||
} |
|||
|
After Width: | Height: | Size: 800 B |
|
After Width: | Height: | Size: 786 B |
|
After Width: | Height: | Size: 800 B |
Loading…
Reference in new issue