46 changed files with 741 additions and 510 deletions
@ -0,0 +1,94 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using Avalonia.Animation.Animators; |
||||
|
using Avalonia.Media; |
||||
|
|
||||
|
namespace Avalonia.Animation; |
||||
|
|
||||
|
partial class Animation |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Sets the value of the Animator attached property for a setter.
|
||||
|
/// </summary>
|
||||
|
/// <param name="setter">The animation setter.</param>
|
||||
|
/// <param name="value">The property animator value.</param>
|
||||
|
[Obsolete("CustomAnimatorBase will be removed before 11.0, use InterpolatingAnimator<T>", true)] |
||||
|
public static void SetAnimator(IAnimationSetter setter, CustomAnimatorBase value) |
||||
|
{ |
||||
|
s_animators[setter] = (value.WrapperType, value.CreateWrapper); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Sets the value of the Animator attached property for a setter.
|
||||
|
/// </summary>
|
||||
|
/// <param name="setter">The animation setter.</param>
|
||||
|
/// <param name="value">The property animator value.</param>
|
||||
|
public static void SetAnimator(IAnimationSetter setter, ICustomAnimator value) |
||||
|
{ |
||||
|
s_animators[setter] = (value.WrapperType, value.CreateWrapper); |
||||
|
} |
||||
|
|
||||
|
private readonly static List<(Func<AvaloniaProperty, bool> Condition, Type Animator, Func<IAnimator> Factory)> |
||||
|
Animators = new() |
||||
|
{ |
||||
|
(prop =>(typeof(double).IsAssignableFrom(prop.PropertyType) && typeof(Transform).IsAssignableFrom(prop.OwnerType)), |
||||
|
typeof(TransformAnimator), () => new TransformAnimator()), |
||||
|
(prop => typeof(bool).IsAssignableFrom(prop.PropertyType), typeof(BoolAnimator), () => new BoolAnimator()), |
||||
|
(prop => typeof(byte).IsAssignableFrom(prop.PropertyType), typeof(ByteAnimator), () => new ByteAnimator()), |
||||
|
(prop => typeof(Int16).IsAssignableFrom(prop.PropertyType), typeof(Int16Animator), () => new Int16Animator()), |
||||
|
(prop => typeof(Int32).IsAssignableFrom(prop.PropertyType), typeof(Int32Animator), () => new Int32Animator()), |
||||
|
(prop => typeof(Int64).IsAssignableFrom(prop.PropertyType), typeof(Int64Animator), () => new Int64Animator()), |
||||
|
(prop => typeof(UInt16).IsAssignableFrom(prop.PropertyType), typeof(UInt16Animator), () => new UInt16Animator()), |
||||
|
(prop => typeof(UInt32).IsAssignableFrom(prop.PropertyType), typeof(UInt32Animator), () => new UInt32Animator()), |
||||
|
(prop => typeof(UInt64).IsAssignableFrom(prop.PropertyType), typeof(UInt64Animator), () => new UInt64Animator()), |
||||
|
(prop => typeof(float).IsAssignableFrom(prop.PropertyType), typeof(FloatAnimator), () => new FloatAnimator()), |
||||
|
(prop => typeof(double).IsAssignableFrom(prop.PropertyType), typeof(DoubleAnimator), () => new DoubleAnimator()), |
||||
|
(prop => typeof(decimal).IsAssignableFrom(prop.PropertyType), typeof(DecimalAnimator), () => new DecimalAnimator()), |
||||
|
}; |
||||
|
|
||||
|
static Animation() |
||||
|
{ |
||||
|
RegisterAnimator<IEffect?, EffectAnimator>(); |
||||
|
RegisterAnimator<BoxShadow, BoxShadowAnimator>(); |
||||
|
RegisterAnimator<BoxShadows, BoxShadowsAnimator>(); |
||||
|
RegisterAnimator<IBrush?, BaseBrushAnimator>(); |
||||
|
RegisterAnimator<CornerRadius, CornerRadiusAnimator>(); |
||||
|
RegisterAnimator<Color, ColorAnimator>(); |
||||
|
RegisterAnimator<Vector, VectorAnimator>(); |
||||
|
RegisterAnimator<Point, PointAnimator>(); |
||||
|
RegisterAnimator<Rect, RectAnimator>(); |
||||
|
RegisterAnimator<RelativePoint, RelativePointAnimator>(); |
||||
|
RegisterAnimator<Size, SizeAnimator>(); |
||||
|
RegisterAnimator<Thickness, ThicknessAnimator>(); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Registers a <see cref="Animator{T}"/> that can handle
|
||||
|
/// a value type that matches the specified condition.
|
||||
|
/// </summary>
|
||||
|
static void RegisterAnimator<T, TAnimator>() |
||||
|
where TAnimator : Animator<T>, new() |
||||
|
{ |
||||
|
Animators.Insert(0, |
||||
|
(prop => typeof(T).IsAssignableFrom(prop.PropertyType), typeof(TAnimator), () => new TAnimator())); |
||||
|
} |
||||
|
|
||||
|
public static void RegisterCustomAnimator<T, TAnimator>() where TAnimator : InterpolatingAnimator<T>, new() |
||||
|
{ |
||||
|
Animators.Insert(0, (prop => typeof(T).IsAssignableFrom(prop.PropertyType), |
||||
|
typeof(InterpolatingAnimator<T>.AnimatorWrapper), () => new TAnimator().CreateWrapper())); |
||||
|
} |
||||
|
|
||||
|
private static (Type Type, Func<IAnimator> Factory)? GetAnimatorType(AvaloniaProperty property) |
||||
|
{ |
||||
|
foreach (var (condition, type, factory) in Animators) |
||||
|
{ |
||||
|
if (condition(property)) |
||||
|
{ |
||||
|
return (type, factory); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,116 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using System.Threading; |
||||
|
using Avalonia.Platform; |
||||
|
using Avalonia.Remote.Protocol.Viewport; |
||||
|
using PlatformPixelFormat = Avalonia.Platform.PixelFormat; |
||||
|
using ProtocolPixelFormat = Avalonia.Remote.Protocol.Viewport.PixelFormat; |
||||
|
|
||||
|
namespace Avalonia.Controls.Remote.Server |
||||
|
{ |
||||
|
internal partial class RemoteServerTopLevelImpl |
||||
|
{ |
||||
|
private enum FrameStatus |
||||
|
{ |
||||
|
NotRendered, |
||||
|
Rendered, |
||||
|
CopiedToMessage |
||||
|
} |
||||
|
|
||||
|
private sealed class Framebuffer |
||||
|
{ |
||||
|
public static Framebuffer Empty { get; } = new(ProtocolPixelFormat.Rgba8888, default, 1.0); |
||||
|
|
||||
|
private readonly double _dpi; |
||||
|
private readonly PixelSize _frameSize; |
||||
|
private readonly object _dataLock = new(); |
||||
|
private readonly byte[] _data; // for rendering only
|
||||
|
private readonly byte[] _dataCopy; // for messages only
|
||||
|
private FrameStatus _status = FrameStatus.NotRendered; |
||||
|
|
||||
|
public Framebuffer(ProtocolPixelFormat format, Size clientSize, double renderScaling) |
||||
|
{ |
||||
|
var frameSize = PixelSize.FromSize(clientSize, renderScaling); |
||||
|
if (frameSize.Width <= 0 || frameSize.Height <= 0) |
||||
|
frameSize = PixelSize.Empty; |
||||
|
|
||||
|
var bpp = format == ProtocolPixelFormat.Rgb565 ? 2 : 4; |
||||
|
var stride = frameSize.Width * bpp; |
||||
|
var dataLength = Math.Max(0, stride * frameSize.Height); |
||||
|
|
||||
|
_dpi = renderScaling * 96.0; |
||||
|
_frameSize = frameSize; |
||||
|
Format = format; |
||||
|
ClientSize = clientSize; |
||||
|
RenderScaling = renderScaling; |
||||
|
|
||||
|
(Stride, _data, _dataCopy) = dataLength > 0 ? |
||||
|
(stride, new byte[dataLength], new byte[dataLength]) : |
||||
|
(0, Array.Empty<byte>(), Array.Empty<byte>()); |
||||
|
} |
||||
|
|
||||
|
public ProtocolPixelFormat Format { get; } |
||||
|
|
||||
|
public Size ClientSize { get; } |
||||
|
|
||||
|
public double RenderScaling { get; } |
||||
|
|
||||
|
public int Stride { get; } |
||||
|
|
||||
|
public FrameStatus GetStatus() |
||||
|
{ |
||||
|
lock (_dataLock) |
||||
|
return _status; |
||||
|
} |
||||
|
|
||||
|
public ILockedFramebuffer Lock(Action onUnlocked) |
||||
|
{ |
||||
|
var handle = GCHandle.Alloc(_data, GCHandleType.Pinned); |
||||
|
Monitor.Enter(_dataLock); |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
return new LockedFramebuffer( |
||||
|
handle.AddrOfPinnedObject(), |
||||
|
_frameSize, |
||||
|
Stride, |
||||
|
new Vector(_dpi, _dpi), |
||||
|
new PlatformPixelFormat((PixelFormatEnum)Format), |
||||
|
() => |
||||
|
{ |
||||
|
handle.Free(); |
||||
|
Array.Copy(_data, _dataCopy, _data.Length); |
||||
|
_status = FrameStatus.Rendered; |
||||
|
Monitor.Exit(_dataLock); |
||||
|
onUnlocked(); |
||||
|
}); |
||||
|
} |
||||
|
catch |
||||
|
{ |
||||
|
handle.Free(); |
||||
|
Monitor.Exit(_dataLock); |
||||
|
throw; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <remarks>The returned message must NOT be kept around, as it contains a shared buffer.</remarks>
|
||||
|
public FrameMessage ToMessage(long sequenceId) |
||||
|
{ |
||||
|
lock (_dataLock) |
||||
|
_status = FrameStatus.CopiedToMessage; |
||||
|
|
||||
|
return new FrameMessage |
||||
|
{ |
||||
|
SequenceId = sequenceId, |
||||
|
Data = _dataCopy, |
||||
|
Format = Format, |
||||
|
Width = _frameSize.Width, |
||||
|
Height = _frameSize.Height, |
||||
|
Stride = Stride, |
||||
|
DpiX = _dpi, |
||||
|
DpiY = _dpi |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue