using System; using System.Runtime.CompilerServices; using System.Windows; using System.Windows.Media; using WPFDark.Internals; namespace WPFDark { public readonly ref struct LayoutRounder { public readonly double DpiScale; private readonly FrameworkElement element; private readonly double inverseDpiScale; [MethodImpl(MethodImplOptions.AggressiveInlining)] public LayoutRounder(FrameworkElement element) { this.element = element; DpiScale = element.PixelsPerDip(); inverseDpiScale = 1d / DpiScale; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Pen GetBorderPen(ByteColor color) => Caches.GetPen(color, RoundLayoutValue(FrameworkElementExtensions.BorderWidth)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public double RoundRenderWidth(bool isWithBorder) { return isWithBorder ? RoundLayoutValue(element.RenderSize.Width - FrameworkElementExtensions.BorderWidth) : RoundLayoutValue(element.RenderSize.Width); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public double RoundRenderHeight(bool isWithBorder) { return isWithBorder ? RoundLayoutValue(element.RenderSize.Height - FrameworkElementExtensions.BorderWidth) : RoundLayoutValue(element.RenderSize.Height); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rect RoundRenderRectangle(bool isWithBorder) { // ReSharper disable ConditionIsAlwaysTrueOrFalse if (isWithBorder) { return new Rect( RoundLayoutValue(FrameworkElementExtensions.BorderHalfWidth), RoundLayoutValue(FrameworkElementExtensions.BorderHalfWidth), RoundRenderWidth(isWithBorder), RoundRenderHeight(isWithBorder)); } else { return new Rect(0, 0, RoundRenderWidth(isWithBorder), RoundRenderHeight(isWithBorder)); } // ReSharper restore ConditionIsAlwaysTrueOrFalse } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ImmutableRect_double RoundLayoutRect(in ImmutableRect_double rect) { return new ImmutableRect_double( RoundLayoutValue(rect.X), RoundLayoutValue(rect.Y), RoundLayoutValue(rect.Width), RoundLayoutValue(rect.Height)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rect RoundLayoutRect(double x, double y, double w, double h) { return new Rect( RoundLayoutValue(x), RoundLayoutValue(y), RoundLayoutValue(w), RoundLayoutValue(h)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rect RoundLayoutRect(Rect rect) { return new Rect( RoundLayoutValue(rect.X), RoundLayoutValue(rect.Y), RoundLayoutValue(rect.Width), RoundLayoutValue(rect.Height)); } public double RoundLayoutValue(double value) { double newValue; if (NumberHelper.AreClose(DpiScale, 1d) == false) { newValue = Math.Round(value * DpiScale) * inverseDpiScale; if (double.IsNaN(newValue) || double.IsInfinity(newValue) || NumberHelper.AreClose(newValue, double.MaxValue)) { newValue = value; } } else { newValue = value; } return newValue; } } }