@ -0,0 +1,10 @@ |
|||||
|
namespace Avalonia.Media |
||||
|
{ |
||||
|
public enum EdgeMode : byte |
||||
|
{ |
||||
|
Unspecified, |
||||
|
|
||||
|
Antialias, |
||||
|
Aliased |
||||
|
} |
||||
|
} |
||||
@ -1,36 +1,131 @@ |
|||||
using Avalonia.Media.Imaging; |
using Avalonia.Media.Imaging; |
||||
|
|
||||
namespace Avalonia.Media |
namespace Avalonia.Media |
||||
{ |
{ |
||||
public class RenderOptions |
public readonly record struct RenderOptions |
||||
{ |
{ |
||||
|
public BitmapInterpolationMode BitmapInterpolationMode { get; init; } |
||||
|
public EdgeMode EdgeMode { get; init; } |
||||
|
public TextRenderingMode TextRenderingMode { get; init; } |
||||
|
public BitmapBlendingMode BitmapBlendingMode { get; init; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the value of the BitmapInterpolationMode attached property for a visual.
|
||||
|
/// </summary>
|
||||
|
/// <param name="visual">The control.</param>
|
||||
|
/// <returns>The control's left coordinate.</returns>
|
||||
|
public static BitmapInterpolationMode GetBitmapInterpolationMode(Visual visual) |
||||
|
{ |
||||
|
return visual.RenderOptions.BitmapInterpolationMode; |
||||
|
} |
||||
|
|
||||
/// <summary>
|
/// <summary>
|
||||
/// Defines the <see cref="BitmapInterpolationMode"/> property.
|
/// Sets the value of the BitmapInterpolationMode attached property for a visual.
|
||||
/// </summary>
|
/// </summary>
|
||||
public static readonly StyledProperty<BitmapInterpolationMode> BitmapInterpolationModeProperty = |
/// <param name="visual">The control.</param>
|
||||
AvaloniaProperty.RegisterAttached<RenderOptions, AvaloniaObject, BitmapInterpolationMode>( |
/// <param name="value">The left value.</param>
|
||||
"BitmapInterpolationMode", |
public static void SetBitmapInterpolationMode(Visual visual, BitmapInterpolationMode value) |
||||
BitmapInterpolationMode.MediumQuality, |
{ |
||||
inherits: true); |
visual.RenderOptions = visual.RenderOptions with { BitmapInterpolationMode = value }; |
||||
|
} |
||||
|
|
||||
/// <summary>
|
/// <summary>
|
||||
/// Gets the value of the BitmapInterpolationMode attached property for a control.
|
/// Gets the value of the BitmapBlendingMode attached property for a visual.
|
||||
/// </summary>
|
/// </summary>
|
||||
/// <param name="element">The control.</param>
|
/// <param name="visual">The control.</param>
|
||||
/// <returns>The control's left coordinate.</returns>
|
/// <returns>The control's left coordinate.</returns>
|
||||
public static BitmapInterpolationMode GetBitmapInterpolationMode(AvaloniaObject element) |
public static BitmapBlendingMode GetBitmapBlendingMode(Visual visual) |
||||
{ |
{ |
||||
return element.GetValue(BitmapInterpolationModeProperty); |
return visual.RenderOptions.BitmapBlendingMode; |
||||
} |
} |
||||
|
|
||||
/// <summary>
|
/// <summary>
|
||||
/// Sets the value of the BitmapInterpolationMode attached property for a control.
|
/// Sets the value of the BitmapBlendingMode attached property for a visual.
|
||||
/// </summary>
|
/// </summary>
|
||||
/// <param name="element">The control.</param>
|
/// <param name="visual">The control.</param>
|
||||
/// <param name="value">The left value.</param>
|
/// <param name="value">The left value.</param>
|
||||
public static void SetBitmapInterpolationMode(AvaloniaObject element, BitmapInterpolationMode value) |
public static void SetBitmapBlendingMode(Visual visual, BitmapBlendingMode value) |
||||
{ |
{ |
||||
element.SetValue(BitmapInterpolationModeProperty, value); |
visual.RenderOptions = visual.RenderOptions with { BitmapBlendingMode = value }; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the value of the EdgeMode attached property for a visual.
|
||||
|
/// </summary>
|
||||
|
/// <param name="visual">The control.</param>
|
||||
|
/// <returns>The control's left coordinate.</returns>
|
||||
|
public static EdgeMode GetEdgeMode(Visual visual) |
||||
|
{ |
||||
|
return visual.RenderOptions.EdgeMode; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Sets the value of the EdgeMode attached property for a visual.
|
||||
|
/// </summary>
|
||||
|
/// <param name="visual">The control.</param>
|
||||
|
/// <param name="value">The left value.</param>
|
||||
|
public static void SetEdgeMode(Visual visual, EdgeMode value) |
||||
|
{ |
||||
|
visual.RenderOptions = visual.RenderOptions with { EdgeMode = value }; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the value of the TextRenderingMode attached property for a visual.
|
||||
|
/// </summary>
|
||||
|
/// <param name="visual">The control.</param>
|
||||
|
/// <returns>The control's left coordinate.</returns>
|
||||
|
public static TextRenderingMode GetTextRenderingMode(Visual visual) |
||||
|
{ |
||||
|
return visual.RenderOptions.TextRenderingMode; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Sets the value of the TextRenderingMode attached property for a visual.
|
||||
|
/// </summary>
|
||||
|
/// <param name="visual">The control.</param>
|
||||
|
/// <param name="value">The left value.</param>
|
||||
|
public static void SetTextRenderingMode(Visual visual, TextRenderingMode value) |
||||
|
{ |
||||
|
visual.RenderOptions = visual.RenderOptions with { TextRenderingMode = value }; |
||||
|
} |
||||
|
|
||||
|
public RenderOptions MergeWith(RenderOptions other) |
||||
|
{ |
||||
|
var bitmapInterpolationMode = BitmapInterpolationMode; |
||||
|
|
||||
|
if (bitmapInterpolationMode == BitmapInterpolationMode.Unspecified) |
||||
|
{ |
||||
|
bitmapInterpolationMode = other.BitmapInterpolationMode; |
||||
|
} |
||||
|
|
||||
|
var edgeMode = EdgeMode; |
||||
|
|
||||
|
if (edgeMode == EdgeMode.Unspecified) |
||||
|
{ |
||||
|
edgeMode = other.EdgeMode; |
||||
|
} |
||||
|
|
||||
|
var textRenderingMode = TextRenderingMode; |
||||
|
|
||||
|
if (textRenderingMode == TextRenderingMode.Unspecified) |
||||
|
{ |
||||
|
textRenderingMode = other.TextRenderingMode; |
||||
|
} |
||||
|
|
||||
|
var bitmapBlendingMode = BitmapBlendingMode; |
||||
|
|
||||
|
if (bitmapBlendingMode == BitmapBlendingMode.Unspecified) |
||||
|
{ |
||||
|
bitmapBlendingMode = other.BitmapBlendingMode; |
||||
|
} |
||||
|
|
||||
|
return new RenderOptions |
||||
|
{ |
||||
|
BitmapInterpolationMode = bitmapInterpolationMode, |
||||
|
EdgeMode = edgeMode, |
||||
|
TextRenderingMode = textRenderingMode, |
||||
|
BitmapBlendingMode = bitmapBlendingMode |
||||
|
}; |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,11 @@ |
|||||
|
namespace Avalonia.Media |
||||
|
{ |
||||
|
public enum TextRenderingMode : byte |
||||
|
{ |
||||
|
Unspecified, |
||||
|
|
||||
|
SubpixelAntialias, |
||||
|
Antialias, |
||||
|
Alias |
||||
|
} |
||||
|
} |
||||
@ -1,22 +0,0 @@ |
|||||
using System; |
|
||||
using System.Drawing; |
|
||||
|
|
||||
namespace Avalonia.Platform |
|
||||
{ |
|
||||
public interface IGlyphRunBuffer |
|
||||
{ |
|
||||
Span<ushort> GlyphIndices { get; } |
|
||||
|
|
||||
IGlyphRunImpl Build(); |
|
||||
} |
|
||||
|
|
||||
public interface IHorizontalGlyphRunBuffer : IGlyphRunBuffer |
|
||||
{ |
|
||||
Span<float> GlyphPositions { get; } |
|
||||
} |
|
||||
|
|
||||
public interface IPositionedGlyphRunBuffer : IGlyphRunBuffer |
|
||||
{ |
|
||||
Span<PointF> GlyphPositions { get; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,68 +0,0 @@ |
|||||
using Avalonia.Platform; |
|
||||
using Avalonia.Media.Imaging; |
|
||||
|
|
||||
namespace Avalonia.Rendering.SceneGraph |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// A node in the scene graph which represents an bitmap blending mode push or pop.
|
|
||||
/// </summary>
|
|
||||
internal class BitmapBlendModeNode : IDrawOperation |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="BitmapBlendModeNode"/> class that represents an
|
|
||||
/// <see cref="BitmapBlendingMode"/> push.
|
|
||||
/// </summary>
|
|
||||
/// <param name="bitmapBlend">The <see cref="BitmapBlendingMode"/> to push.</param>
|
|
||||
public BitmapBlendModeNode(BitmapBlendingMode bitmapBlend) |
|
||||
{ |
|
||||
BlendingMode = bitmapBlend; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="BitmapBlendModeNode"/> class that represents an
|
|
||||
/// <see cref="BitmapBlendingMode"/> pop.
|
|
||||
/// </summary>
|
|
||||
public BitmapBlendModeNode() |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public Rect Bounds => default; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the BitmapBlend to be pushed or null if the operation represents a pop.
|
|
||||
/// </summary>
|
|
||||
public BitmapBlendingMode? BlendingMode { get; } |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public bool HitTest(Point p) => false; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Determines if this draw operation equals another.
|
|
||||
/// </summary>
|
|
||||
/// <param name="blendingMode">the <see cref="BitmapBlendModeNode"/> how to compare</param>
|
|
||||
/// <returns>True if the draw operations are the same, otherwise false.</returns>
|
|
||||
/// <remarks>
|
|
||||
/// The properties of the other draw operation are passed in as arguments to prevent
|
|
||||
/// allocation of a not-yet-constructed draw operation object.
|
|
||||
/// </remarks>
|
|
||||
public bool Equals(BitmapBlendingMode? blendingMode) => BlendingMode == blendingMode; |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public void Render(IDrawingContextImpl context) |
|
||||
{ |
|
||||
if (BlendingMode.HasValue) |
|
||||
{ |
|
||||
context.PushBitmapBlendMode(BlendingMode.Value); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
context.PopBitmapBlendMode(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public void Dispose() |
|
||||
{ |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,31 +1,106 @@ |
|||||
using System; |
using System; |
||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
|
using Avalonia.Media; |
||||
|
using Avalonia.Media.TextFormatting; |
||||
using Avalonia.Platform; |
using Avalonia.Platform; |
||||
using SharpDX.DirectWrite; |
using SharpDX.DirectWrite; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
namespace Avalonia.Direct2D1.Media |
namespace Avalonia.Direct2D1.Media |
||||
{ |
{ |
||||
internal class GlyphRunImpl : IGlyphRunImpl |
internal class GlyphRunImpl : IGlyphRunImpl |
||||
{ |
{ |
||||
public GlyphRunImpl(GlyphRun glyphRun, Size size, Point baselineOrigin) |
private readonly GlyphTypefaceImpl _glyphTypefaceImpl; |
||||
|
|
||||
|
private readonly short[] _glyphIndices; |
||||
|
private readonly float[] _glyphAdvances; |
||||
|
private readonly GlyphOffset[] _glyphOffsets; |
||||
|
|
||||
|
private SharpDX.DirectWrite.GlyphRun? _glyphRun; |
||||
|
|
||||
|
public GlyphRunImpl(IGlyphTypeface glyphTypeface, double fontRenderingEmSize, |
||||
|
IReadOnlyList<GlyphInfo> glyphInfos, Point baselineOrigin, Rect bounds) |
||||
{ |
{ |
||||
Bounds = new Rect(new Point(baselineOrigin.X, 0), size); |
_glyphTypefaceImpl = (GlyphTypefaceImpl)glyphTypeface; |
||||
|
|
||||
|
FontRenderingEmSize = fontRenderingEmSize; |
||||
BaselineOrigin = baselineOrigin; |
BaselineOrigin = baselineOrigin; |
||||
GlyphRun = glyphRun; |
Bounds = bounds; |
||||
|
|
||||
|
var glyphCount = glyphInfos.Count; |
||||
|
|
||||
|
_glyphIndices = new short[glyphCount]; |
||||
|
|
||||
|
for (var i = 0; i < glyphCount; i++) |
||||
|
{ |
||||
|
_glyphIndices[i] = (short)glyphInfos[i].GlyphIndex; |
||||
|
} |
||||
|
|
||||
|
_glyphAdvances = new float[glyphCount]; |
||||
|
|
||||
|
var width = 0.0; |
||||
|
|
||||
|
for (var i = 0; i < glyphCount; i++) |
||||
|
{ |
||||
|
var advance = glyphInfos[i].GlyphAdvance; |
||||
|
|
||||
|
width += advance; |
||||
|
|
||||
|
_glyphAdvances[i] = (float)advance; |
||||
|
} |
||||
|
|
||||
|
_glyphOffsets = new GlyphOffset[glyphCount]; |
||||
|
|
||||
|
for (var i = 0; i < glyphCount; i++) |
||||
|
{ |
||||
|
var (x, y) = glyphInfos[i].GlyphOffset; |
||||
|
|
||||
|
_glyphOffsets[i] = new GlyphOffset |
||||
|
{ |
||||
|
AdvanceOffset = (float)x, |
||||
|
AscenderOffset = (float)y |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public SharpDX.DirectWrite.GlyphRun GlyphRun |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
if (_glyphRun != null) |
||||
|
{ |
||||
|
return _glyphRun; |
||||
|
} |
||||
|
|
||||
|
_glyphRun = new SharpDX.DirectWrite.GlyphRun |
||||
|
{ |
||||
|
FontFace = _glyphTypefaceImpl.FontFace, |
||||
|
FontSize = (float)FontRenderingEmSize, |
||||
|
Advances = _glyphAdvances, |
||||
|
Indices = _glyphIndices, |
||||
|
Offsets = _glyphOffsets |
||||
|
}; |
||||
|
|
||||
|
return _glyphRun; |
||||
|
} |
||||
} |
} |
||||
|
|
||||
public Rect Bounds{ get; } |
public IGlyphTypeface GlyphTypeface => _glyphTypefaceImpl; |
||||
|
|
||||
|
public double FontRenderingEmSize { get; } |
||||
|
|
||||
public Point BaselineOrigin { get; } |
public Point BaselineOrigin { get; } |
||||
|
|
||||
public GlyphRun GlyphRun { get; } |
public Rect Bounds { get; } |
||||
|
|
||||
|
public IReadOnlyList<float> GetIntersections(float lowerBound, float upperBound) => Array.Empty<float>(); |
||||
|
|
||||
public void Dispose() |
public void Dispose() |
||||
{ |
{ |
||||
//GlyphRun?.Dispose();
|
//_glyphRun?.Dispose();
|
||||
} |
|
||||
|
|
||||
public IReadOnlyList<float> GetIntersections(float lowerBound, float upperBound) |
_glyphRun = null; |
||||
=> Array.Empty<float>(); |
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,21 +0,0 @@ |
|||||
using System.Collections.Generic; |
|
||||
using Avalonia.Platform; |
|
||||
|
|
||||
namespace Avalonia.Benchmarks |
|
||||
{ |
|
||||
internal class NullGlyphRun : IGlyphRunImpl |
|
||||
{ |
|
||||
public Rect Bounds => default; |
|
||||
|
|
||||
public Point BaselineOrigin => default; |
|
||||
|
|
||||
public void Dispose() |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
public IReadOnlyList<float> GetIntersections(float lowerBound, float upperBound) |
|
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,33 +1,34 @@ |
|||||
using System; |
using System; |
||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
using Avalonia.Media.TextFormatting; |
using Avalonia.Media; |
||||
using Avalonia.Platform; |
using Avalonia.Platform; |
||||
|
|
||||
namespace Avalonia.UnitTests |
namespace Avalonia.UnitTests |
||||
{ |
{ |
||||
public class MockGlyphRun : IGlyphRunImpl |
public class MockGlyphRun : IGlyphRunImpl |
||||
{ |
{ |
||||
public MockGlyphRun(IReadOnlyList<GlyphInfo> glyphInfos) |
public MockGlyphRun(IGlyphTypeface glyphTypeface, double fontRenderingEmSize, Point baselineOrigin, Rect bounds) |
||||
{ |
{ |
||||
var width = 0.0; |
GlyphTypeface = glyphTypeface; |
||||
|
FontRenderingEmSize = fontRenderingEmSize; |
||||
|
BaselineOrigin = baselineOrigin; |
||||
|
Bounds =bounds; |
||||
|
} |
||||
|
|
||||
for (var i = 0; i < glyphInfos.Count; ++i) |
public IGlyphTypeface GlyphTypeface { get; } |
||||
{ |
|
||||
width += glyphInfos[i].GlyphAdvance; |
|
||||
} |
|
||||
|
|
||||
Bounds = new Rect(new Size(width, 10)); |
public double FontRenderingEmSize { get; } |
||||
} |
|
||||
|
|
||||
public Rect Bounds { get; } |
public Point BaselineOrigin { get; } |
||||
|
|
||||
public Point BaselineOrigin => new Point(0, 8); |
public Rect Bounds { get; } |
||||
|
|
||||
public void Dispose() |
public void Dispose() |
||||
{ |
{ |
||||
|
|
||||
} |
} |
||||
|
|
||||
public IReadOnlyList<float> GetIntersections(float lowerBound, float upperBound) |
public IReadOnlyList<float> GetIntersections(float lowerLimit, float upperLimit) |
||||
=> Array.Empty<float>(); |
=> Array.Empty<float>(); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
|
After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 271 B After Width: | Height: | Size: 199 B |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 7.0 KiB |