|
|
|
@ -11,20 +11,29 @@ namespace Avalonia.MonoMac |
|
|
|
{ |
|
|
|
private readonly TopLevelImpl.TopLevelView _view; |
|
|
|
private readonly CGSize _logicalSize; |
|
|
|
private bool _isDeferred; |
|
|
|
|
|
|
|
public EmulatedFramebuffer(TopLevelImpl.TopLevelView view, CGSize logicalSize, CGSize pixelSize) |
|
|
|
[DllImport("libc")] |
|
|
|
static extern void memset(IntPtr p, int c, IntPtr size); |
|
|
|
|
|
|
|
public EmulatedFramebuffer(TopLevelImpl.TopLevelView view) |
|
|
|
{ |
|
|
|
_view = view; |
|
|
|
_logicalSize = logicalSize; |
|
|
|
|
|
|
|
_isDeferred = !Dispatcher.UIThread.CheckAccess(); |
|
|
|
_logicalSize = _view.LogicalSize; |
|
|
|
var pixelSize = _view.PixelSize; |
|
|
|
Width = (int)pixelSize.Width; |
|
|
|
Height = (int)pixelSize.Height; |
|
|
|
RowBytes = Width * 4; |
|
|
|
Dpi = new Vector(96 * pixelSize.Width / _logicalSize.Width, 96 * pixelSize.Height / _logicalSize.Height); |
|
|
|
Format = PixelFormat.Rgba8888; |
|
|
|
Address = Marshal.AllocHGlobal(Height * RowBytes); |
|
|
|
var size = Height * RowBytes; |
|
|
|
Address = Marshal.AllocHGlobal(size); |
|
|
|
memset(Address, 0, new IntPtr(size)); |
|
|
|
} |
|
|
|
|
|
|
|
class DeferredRenderingHelper : IDisposable |
|
|
|
class CocoaDrawLock : IDisposable |
|
|
|
{ |
|
|
|
private readonly NSView _view; |
|
|
|
public void Dispose() |
|
|
|
@ -32,17 +41,17 @@ namespace Avalonia.MonoMac |
|
|
|
_view.NonUIUnlockFocus(); |
|
|
|
} |
|
|
|
|
|
|
|
public DeferredRenderingHelper(NSView view) |
|
|
|
public CocoaDrawLock(NSView view) |
|
|
|
{ |
|
|
|
_view = view; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
DeferredRenderingHelper SetupWindowContext() |
|
|
|
CocoaDrawLock LockCocoaDrawing() |
|
|
|
{ |
|
|
|
if (!_view.NonUILockFocusIfCanDraw()) |
|
|
|
return null; |
|
|
|
return new DeferredRenderingHelper(_view); |
|
|
|
return new CocoaDrawLock(_view); |
|
|
|
} |
|
|
|
|
|
|
|
public void Dispose() |
|
|
|
@ -50,51 +59,45 @@ namespace Avalonia.MonoMac |
|
|
|
if (Address == IntPtr.Zero) |
|
|
|
return; |
|
|
|
var nfo = (int) CGBitmapFlags.ByteOrder32Big | (int) CGImageAlphaInfo.PremultipliedLast; |
|
|
|
|
|
|
|
DeferredRenderingHelper deferred = null; |
|
|
|
var isDeferred = !Dispatcher.UIThread.CheckAccess(); |
|
|
|
if (!isDeferred || (deferred = SetupWindowContext()) != null) |
|
|
|
IDisposable drawLock = LockCocoaDrawing(); |
|
|
|
CGImage image = null; |
|
|
|
try |
|
|
|
{ |
|
|
|
CGImage image = null; |
|
|
|
try |
|
|
|
using (var colorSpace = CGColorSpace.CreateDeviceRGB()) |
|
|
|
using (var bContext = new CGBitmapContext(Address, Width, Height, 8, Width * 4, |
|
|
|
colorSpace, (CGImageAlphaInfo)nfo)) |
|
|
|
image = bContext.ToImage(); |
|
|
|
lock (_view.SyncRoot) |
|
|
|
{ |
|
|
|
lock (_view.SyncRoot) |
|
|
|
if (!_isDeferred || drawLock != null) |
|
|
|
{ |
|
|
|
using (deferred) |
|
|
|
using (var colorSpace = CGColorSpace.CreateDeviceRGB()) |
|
|
|
using (var bContext = new CGBitmapContext(Address, Width, Height, 8, Width * 4, |
|
|
|
colorSpace, (CGImageAlphaInfo) nfo)) |
|
|
|
using (var nscontext = NSGraphicsContext.CurrentContext) |
|
|
|
using (var context = nscontext.GraphicsPort) |
|
|
|
{ |
|
|
|
if (!isDeferred || deferred != null) |
|
|
|
{ |
|
|
|
using (var nscontext = NSGraphicsContext.CurrentContext) |
|
|
|
using (var context = nscontext.GraphicsPort) |
|
|
|
{ |
|
|
|
image = bContext.ToImage(); |
|
|
|
context.SetFillColor(255, 255, 255, 255); |
|
|
|
context.FillRect(new CGRect(default(CGPoint), _view.LogicalSize)); |
|
|
|
context.TranslateCTM(0, _view.LogicalSize.Height - _logicalSize.Height); |
|
|
|
context.DrawImage(new CGRect(default(CGPoint), _logicalSize), image); |
|
|
|
context.Flush(); |
|
|
|
nscontext.FlushGraphics(); |
|
|
|
} |
|
|
|
} |
|
|
|
context.SetFillColor(255, 255, 255, 255); |
|
|
|
context.FillRect(new CGRect(default(CGPoint), _view.LogicalSize)); |
|
|
|
context.TranslateCTM(0, _view.LogicalSize.Height - _logicalSize.Height); |
|
|
|
context.DrawImage(new CGRect(default(CGPoint), _logicalSize), image); |
|
|
|
context.Flush(); |
|
|
|
nscontext.FlushGraphics(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
finally |
|
|
|
} |
|
|
|
finally |
|
|
|
{ |
|
|
|
if (image != null) |
|
|
|
{ |
|
|
|
if (image != null) |
|
|
|
{ |
|
|
|
if (deferred == null) |
|
|
|
image.Dispose(); |
|
|
|
else |
|
|
|
_view.SetBackBufferImage(new SavedImage(image, _logicalSize)); |
|
|
|
} |
|
|
|
if (!_isDeferred) |
|
|
|
image.Dispose(); |
|
|
|
else |
|
|
|
_view.SetBackBufferImage(new SavedImage(image, _logicalSize)); |
|
|
|
} |
|
|
|
Marshal.FreeHGlobal(Address); |
|
|
|
Address = IntPtr.Zero; |
|
|
|
drawLock?.Dispose(); |
|
|
|
} |
|
|
|
Marshal.FreeHGlobal(Address); |
|
|
|
Address = IntPtr.Zero; |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|