@ -0,0 +1,10 @@ |
|||
namespace Avalonia.Media |
|||
{ |
|||
public enum EdgeMode : byte |
|||
{ |
|||
Unspecified, |
|||
|
|||
Antialias, |
|||
Aliased |
|||
} |
|||
} |
|||
@ -1,36 +1,131 @@ |
|||
using Avalonia.Media.Imaging; |
|||
|
|||
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>
|
|||
/// Defines the <see cref="BitmapInterpolationMode"/> property.
|
|||
/// Sets the value of the BitmapInterpolationMode attached property for a visual.
|
|||
/// </summary>
|
|||
public static readonly StyledProperty<BitmapInterpolationMode> BitmapInterpolationModeProperty = |
|||
AvaloniaProperty.RegisterAttached<RenderOptions, AvaloniaObject, BitmapInterpolationMode>( |
|||
"BitmapInterpolationMode", |
|||
BitmapInterpolationMode.MediumQuality, |
|||
inherits: true); |
|||
/// <param name="visual">The control.</param>
|
|||
/// <param name="value">The left value.</param>
|
|||
public static void SetBitmapInterpolationMode(Visual visual, BitmapInterpolationMode value) |
|||
{ |
|||
visual.RenderOptions = visual.RenderOptions with { BitmapInterpolationMode = value }; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the BitmapInterpolationMode attached property for a control.
|
|||
/// Gets the value of the BitmapBlendingMode attached property for a visual.
|
|||
/// </summary>
|
|||
/// <param name="element">The control.</param>
|
|||
/// <param name="visual">The control.</param>
|
|||
/// <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>
|
|||
/// Sets the value of the BitmapInterpolationMode attached property for a control.
|
|||
/// Sets the value of the BitmapBlendingMode attached property for a visual.
|
|||
/// </summary>
|
|||
/// <param name="element">The control.</param>
|
|||
/// <param name="visual">The control.</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.Collections.Generic; |
|||
using Avalonia.Media; |
|||
using Avalonia.Media.TextFormatting; |
|||
using Avalonia.Platform; |
|||
using SharpDX.DirectWrite; |
|||
|
|||
#nullable enable |
|||
|
|||
namespace Avalonia.Direct2D1.Media |
|||
{ |
|||
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; |
|||
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 GlyphRun GlyphRun { get; } |
|||
public Rect Bounds { get; } |
|||
|
|||
public IReadOnlyList<float> GetIntersections(float lowerBound, float upperBound) => Array.Empty<float>(); |
|||
|
|||
public void Dispose() |
|||
{ |
|||
//GlyphRun?.Dispose();
|
|||
} |
|||
//_glyphRun?.Dispose();
|
|||
|
|||
public IReadOnlyList<float> GetIntersections(float lowerBound, float upperBound) |
|||
=> Array.Empty<float>(); |
|||
_glyphRun = null; |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -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.Collections.Generic; |
|||
using Avalonia.Media.TextFormatting; |
|||
using Avalonia.Media; |
|||
using Avalonia.Platform; |
|||
|
|||
namespace Avalonia.UnitTests |
|||
{ |
|||
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) |
|||
{ |
|||
width += glyphInfos[i].GlyphAdvance; |
|||
} |
|||
public IGlyphTypeface GlyphTypeface { get; } |
|||
|
|||
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 IReadOnlyList<float> GetIntersections(float lowerBound, float upperBound) |
|||
public IReadOnlyList<float> GetIntersections(float lowerLimit, float upperLimit) |
|||
=> 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 |