Merge branch 'master' into fixes/DevTools/WithoutApplicationLifetime
@@ -263,9 +263,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo.iOS", "samples
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Headless", "Headless", "{FF237916-7150-496B-89ED-6CA3292896E7}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.XUnit", "src\Headless\Avalonia.Headless.XUnit\Avalonia.Headless.XUnit.csproj", "{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Headless.XUnit", "src\Headless\Avalonia.Headless.XUnit\Avalonia.Headless.XUnit.csproj", "{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Headless.UnitTests", "tests\Avalonia.Headless.UnitTests\Avalonia.Headless.UnitTests.csproj", "{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Headless.UnitTests", "tests\Avalonia.Headless.UnitTests\Avalonia.Headless.UnitTests.csproj", "{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -606,14 +606,6 @@ Global
|
||||
{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@@ -642,6 +634,14 @@ Global
|
||||
{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -686,6 +686,8 @@ Global
|
||||
{AF915D5C-AB00-4EA0-B5E6-001F4AE84E68} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
|
||||
{4D36CEC8-53F2-40A5-9A37-79AAE356E2DA} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
|
||||
{351337F5-D66F-461B-A957-4EF60BDB4BA6} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
|
||||
{8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC} = {FF237916-7150-496B-89ED-6CA3292896E7}
|
||||
{B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E} = {FF237916-7150-496B-89ED-6CA3292896E7}
|
||||
{909A8CBD-7D0E-42FD-B841-022AD8925820} = {8B6A8209-894F-4BA1-B880-965FD453982C}
|
||||
{11BE52AF-E2DD-4CF0-B19A-05285ACAF571} = {9B9E3891-2366-4253-A952-D08BCEB71098}
|
||||
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5} = {9B9E3891-2366-4253-A952-D08BCEB71098}
|
||||
@@ -709,10 +711,6 @@ Global
|
||||
{C810060E-3809-4B74-A125-F11533AF9C1B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
|
||||
{C692FE73-43DB-49CE-87FC-F03ED61F25C9} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
|
||||
{F4E36AA8-814E-4704-BC07-291F70F45193} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
|
||||
{8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC} = {FF237916-7150-496B-89ED-6CA3292896E7}
|
||||
{B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E} = {FF237916-7150-496B-89ED-6CA3292896E7}
|
||||
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119} = {FF237916-7150-496B-89ED-6CA3292896E7}
|
||||
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
|
||||
{DDA28789-C21A-4654-86CE-D01E81F095C5} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
|
||||
{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
|
||||
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533} = {9B9E3891-2366-4253-A952-D08BCEB71098}
|
||||
@@ -721,6 +719,8 @@ Global
|
||||
{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D} = {9B9E3891-2366-4253-A952-D08BCEB71098}
|
||||
{4CDAD037-34A2-4CCF-A03A-C6C7B988A572} = {9B9E3891-2366-4253-A952-D08BCEB71098}
|
||||
{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD} = {9B9E3891-2366-4253-A952-D08BCEB71098}
|
||||
{F47F8316-4D4B-4026-8EF3-16B2CFDA8119} = {FF237916-7150-496B-89ED-6CA3292896E7}
|
||||
{3B2405E8-9E7A-46D1-8E2D-EF9ED124C9F2} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Presenters;
|
||||
using Avalonia.Input.TextInput;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Win32.WinRT.Composition;
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Rendering.SceneGraph;
|
||||
using Avalonia.Threading;
|
||||
using Avalonia.Utilities;
|
||||
using Avalonia.Media.Imaging;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Avalonia.Media
|
||||
{
|
||||
@@ -54,12 +53,10 @@ namespace Avalonia.Media
|
||||
/// <param name="source">The image.</param>
|
||||
/// <param name="sourceRect">The rect in the image to draw.</param>
|
||||
/// <param name="destRect">The rect in the output to draw to.</param>
|
||||
/// <param name="bitmapInterpolationMode">The bitmap interpolation mode.</param>
|
||||
public virtual void DrawImage(IImage source, Rect sourceRect, Rect destRect,
|
||||
BitmapInterpolationMode bitmapInterpolationMode = default)
|
||||
public virtual void DrawImage(IImage source, Rect sourceRect, Rect destRect)
|
||||
{
|
||||
_ = source ?? throw new ArgumentNullException(nameof(source));
|
||||
source.Draw(this, sourceRect, destRect, bitmapInterpolationMode);
|
||||
source.Draw(this, sourceRect, destRect);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -69,8 +66,7 @@ namespace Avalonia.Media
|
||||
/// <param name="opacity">The opacity to draw with.</param>
|
||||
/// <param name="sourceRect">The rect in the image to draw.</param>
|
||||
/// <param name="destRect">The rect in the output to draw to.</param>
|
||||
/// <param name="bitmapInterpolationMode">The bitmap interpolation mode.</param>
|
||||
internal abstract void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default);
|
||||
internal abstract void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect);
|
||||
|
||||
/// <summary>
|
||||
/// Draws a line.
|
||||
@@ -287,8 +283,7 @@ namespace Avalonia.Media
|
||||
Opacity,
|
||||
Clip,
|
||||
GeometryClip,
|
||||
OpacityMask,
|
||||
BitmapBlendMode
|
||||
OpacityMask
|
||||
}
|
||||
|
||||
public RestoreState(DrawingContext context, PushedStateType type)
|
||||
@@ -313,8 +308,6 @@ namespace Avalonia.Media
|
||||
_context.PopGeometryClipCore();
|
||||
else if (_type == PushedStateType.OpacityMask)
|
||||
_context.PopOpacityMaskCore();
|
||||
else if (_type == PushedStateType.BitmapBlendMode)
|
||||
_context.PopBitmapBlendModeCore();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,16 +388,6 @@ namespace Avalonia.Media
|
||||
}
|
||||
protected abstract void PushOpacityMaskCore(IBrush mask, Rect bounds);
|
||||
|
||||
public PushedState PushBitmapBlendMode(BitmapBlendingMode blendingMode)
|
||||
{
|
||||
PushBitmapBlendMode(blendingMode);
|
||||
_states ??= StateStackPool.Get();
|
||||
_states.Push(new RestoreState(this, RestoreState.PushedStateType.BitmapBlendMode));
|
||||
return new PushedState(this);
|
||||
}
|
||||
|
||||
protected abstract void PushBitmapBlendModeCore(BitmapBlendingMode blendingMode);
|
||||
|
||||
/// <summary>
|
||||
/// Pushes a matrix transformation.
|
||||
/// </summary>
|
||||
@@ -432,7 +415,6 @@ namespace Avalonia.Media
|
||||
protected abstract void PopGeometryClipCore();
|
||||
protected abstract void PopOpacityCore();
|
||||
protected abstract void PopOpacityMaskCore();
|
||||
protected abstract void PopBitmapBlendModeCore();
|
||||
protected abstract void PopTransformCore();
|
||||
|
||||
private static bool PenIsVisible(IPen? pen)
|
||||
|
||||
@@ -196,13 +196,7 @@ namespace Avalonia.Media
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override void PushBitmapBlendModeCore(BitmapBlendingMode blendingMode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal override void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect,
|
||||
BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default)
|
||||
internal override void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -321,8 +315,6 @@ namespace Avalonia.Media
|
||||
|
||||
protected override void PopOpacityMaskCore() => Pop();
|
||||
|
||||
protected override void PopBitmapBlendModeCore() => Pop();
|
||||
|
||||
protected override void PopTransformCore() => Pop();
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using Avalonia.Metadata;
|
||||
using Avalonia.Media.Imaging;
|
||||
|
||||
namespace Avalonia.Media
|
||||
{
|
||||
@@ -43,8 +42,7 @@ namespace Avalonia.Media
|
||||
void IImage.Draw(
|
||||
DrawingContext context,
|
||||
Rect sourceRect,
|
||||
Rect destRect,
|
||||
BitmapInterpolationMode bitmapInterpolationMode)
|
||||
Rect destRect)
|
||||
{
|
||||
var drawing = Drawing;
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Avalonia.Media
|
||||
{
|
||||
public enum EdgeMode : byte
|
||||
{
|
||||
Unspecified,
|
||||
|
||||
Antialias,
|
||||
Aliased
|
||||
}
|
||||
}
|
||||
@@ -153,7 +153,7 @@ namespace Avalonia.Media
|
||||
/// <summary>
|
||||
/// Gets the conservative bounding box of the <see cref="GlyphRun"/>.
|
||||
/// </summary>
|
||||
public Rect Bounds => PlatformImpl.Item.Bounds;
|
||||
public Rect Bounds => new Rect(new Size(Metrics.WidthIncludingTrailingWhitespace, Metrics.Height));
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -166,7 +166,7 @@ namespace Avalonia.Media
|
||||
/// </summary>
|
||||
public Point BaselineOrigin
|
||||
{
|
||||
get => PlatformImpl.Item.BaselineOrigin;
|
||||
get => _baselineOrigin ?? new Point(0, Metrics.Baseline);
|
||||
set => Set(ref _baselineOrigin, value);
|
||||
}
|
||||
|
||||
@@ -676,13 +676,17 @@ namespace Avalonia.Media
|
||||
}
|
||||
}
|
||||
|
||||
return new GlyphRunMetrics(
|
||||
width,
|
||||
trailingWhitespaceLength,
|
||||
newLineLength,
|
||||
firstCluster,
|
||||
lastCluster
|
||||
);
|
||||
return new GlyphRunMetrics
|
||||
{
|
||||
Baseline = -GlyphTypeface.Metrics.Ascent * Scale,
|
||||
Width = width,
|
||||
WidthIncludingTrailingWhitespace = widthIncludingTrailingWhitespace,
|
||||
Height = height,
|
||||
NewLineLength = newLineLength,
|
||||
TrailingWhitespaceLength = trailingWhitespaceLength,
|
||||
FirstCluster = firstCluster,
|
||||
LastCluster = lastCluster
|
||||
};
|
||||
}
|
||||
|
||||
private int GetTrailingWhitespaceLength(bool isReversed, out int newLineLength, out int glyphCount)
|
||||
@@ -820,10 +824,11 @@ namespace Avalonia.Media
|
||||
private IRef<IGlyphRunImpl> CreateGlyphRunImpl()
|
||||
{
|
||||
var platformImpl = s_renderInterface.CreateGlyphRun(
|
||||
GlyphTypeface,
|
||||
FontRenderingEmSize,
|
||||
GlyphInfos,
|
||||
_baselineOrigin ?? new Point(0, -GlyphTypeface.Metrics.Ascent * Scale));
|
||||
GlyphTypeface,
|
||||
FontRenderingEmSize,
|
||||
GlyphInfos,
|
||||
BaselineOrigin,
|
||||
Bounds);
|
||||
|
||||
_platformImpl = RefCountable.Create(platformImpl);
|
||||
|
||||
@@ -835,5 +840,16 @@ namespace Avalonia.Media
|
||||
_platformImpl?.Dispose();
|
||||
_platformImpl = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the intersections of specified upper and lower limit.
|
||||
/// </summary>
|
||||
/// <param name="lowerLimit">Upper limit.</param>
|
||||
/// <param name="upperLimit">Lower limit.</param>
|
||||
/// <returns></returns>
|
||||
public IReadOnlyList<float> GetIntersections(float lowerLimit, float upperLimit)
|
||||
{
|
||||
return PlatformImpl.Item.GetIntersections(lowerLimit, upperLimit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,23 +2,20 @@
|
||||
{
|
||||
public readonly record struct GlyphRunMetrics
|
||||
{
|
||||
public GlyphRunMetrics(double width, int trailingWhitespaceLength, int newLineLength, int firstCluster, int lastCluster)
|
||||
{
|
||||
Width = width;
|
||||
TrailingWhitespaceLength = trailingWhitespaceLength;
|
||||
NewLineLength = newLineLength;
|
||||
FirstCluster = firstCluster;
|
||||
LastCluster = lastCluster;
|
||||
}
|
||||
public double Baseline { get; init; }
|
||||
|
||||
public double Width { get; }
|
||||
public double Width { get; init; }
|
||||
|
||||
public int TrailingWhitespaceLength { get; }
|
||||
public double WidthIncludingTrailingWhitespace { get; init; }
|
||||
|
||||
public int NewLineLength { get; }
|
||||
public double Height { get; init; }
|
||||
|
||||
public int FirstCluster { get; }
|
||||
public int TrailingWhitespaceLength { get; init; }
|
||||
|
||||
public int LastCluster { get; }
|
||||
public int NewLineLength { get; init; }
|
||||
|
||||
public int FirstCluster { get; init; }
|
||||
|
||||
public int LastCluster { get; init; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,9 @@ namespace Avalonia.Media
|
||||
/// <param name="context">The drawing context.</param>
|
||||
/// <param name="sourceRect">The rect in the image to draw.</param>
|
||||
/// <param name="destRect">The rect in the output to draw to.</param>
|
||||
/// <param name="bitmapInterpolationMode">The bitmap interpolation mode.</param>
|
||||
void Draw(
|
||||
DrawingContext context,
|
||||
Rect sourceRect,
|
||||
Rect destRect,
|
||||
BitmapInterpolationMode bitmapInterpolationMode);
|
||||
Rect destRect);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,13 +39,5 @@ namespace Avalonia.Media
|
||||
/// Gets the brush's tile mode.
|
||||
/// </summary>
|
||||
TileMode TileMode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bitmap interpolation mode.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The bitmap interpolation mode.
|
||||
/// </value>
|
||||
BitmapInterpolationMode BitmapInterpolationMode { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,15 +224,13 @@ namespace Avalonia.Media.Imaging
|
||||
void IImage.Draw(
|
||||
DrawingContext context,
|
||||
Rect sourceRect,
|
||||
Rect destRect,
|
||||
BitmapInterpolationMode bitmapInterpolationMode)
|
||||
Rect destRect)
|
||||
{
|
||||
context.DrawBitmap(
|
||||
PlatformImpl,
|
||||
1,
|
||||
sourceRect,
|
||||
destRect,
|
||||
bitmapInterpolationMode);
|
||||
destRect);
|
||||
}
|
||||
|
||||
private static IPlatformRenderInterface GetFactory()
|
||||
|
||||
@@ -3,8 +3,10 @@ namespace Avalonia.Media.Imaging
|
||||
/// <summary>
|
||||
/// Controls the way the bitmaps are drawn together.
|
||||
/// </summary>
|
||||
public enum BitmapBlendingMode
|
||||
public enum BitmapBlendingMode : byte
|
||||
{
|
||||
Unspecified,
|
||||
|
||||
/// <summary>
|
||||
/// Source is placed over the destination.
|
||||
/// </summary>
|
||||
@@ -52,6 +54,6 @@ namespace Avalonia.Media.Imaging
|
||||
/// <summary>
|
||||
/// Display the sum of the source image and destination image.
|
||||
/// </summary>
|
||||
Plus,
|
||||
Plus
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
/// <summary>
|
||||
/// Controls the performance and quality of bitmap scaling.
|
||||
/// </summary>
|
||||
public enum BitmapInterpolationMode
|
||||
public enum BitmapInterpolationMode : byte
|
||||
{
|
||||
Unspecified,
|
||||
|
||||
/// <summary>
|
||||
/// Uses the default behavior of the underling render backend.
|
||||
/// Disable interpolation.
|
||||
/// </summary>
|
||||
Default,
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// The best performance but worst image quality.
|
||||
@@ -18,7 +20,7 @@
|
||||
/// <summary>
|
||||
/// Good performance and decent image quality.
|
||||
/// </summary>
|
||||
MediumQuality,
|
||||
MediumQuality,
|
||||
|
||||
/// <summary>
|
||||
/// Highest quality but worst performance.
|
||||
|
||||
@@ -83,12 +83,12 @@ namespace Avalonia.Media.Imaging
|
||||
}
|
||||
}
|
||||
|
||||
public void Draw(DrawingContext context, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode)
|
||||
public void Draw(DrawingContext context, Rect sourceRect, Rect destRect)
|
||||
{
|
||||
if (Source is not IBitmap bmp)
|
||||
return;
|
||||
var topLeft = SourceRect.TopLeft.ToPointWithDpi(bmp.Dpi);
|
||||
Source.Draw(context, sourceRect.Translate(new Vector(topLeft.X, topLeft.Y)), destRect, bitmapInterpolationMode);
|
||||
Source.Draw(context, sourceRect.Translate(new Vector(topLeft.X, topLeft.Y)), destRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,11 +79,10 @@ namespace Avalonia.Media
|
||||
/// <param name="source">The bitmap.</param>
|
||||
/// <param name="sourceRect">The rect in the image to draw.</param>
|
||||
/// <param name="destRect">The rect in the output to draw to.</param>
|
||||
/// <param name="bitmapInterpolationMode">The bitmap interpolation mode.</param>
|
||||
public void DrawBitmap(IBitmap source, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = default)
|
||||
public void DrawBitmap(IBitmap source, Rect sourceRect, Rect destRect)
|
||||
{
|
||||
_ = source ?? throw new ArgumentNullException(nameof(source));
|
||||
PlatformImpl.DrawBitmap(source.PlatformImpl, 1, sourceRect, destRect, bitmapInterpolationMode);
|
||||
PlatformImpl.DrawBitmap(source.PlatformImpl, 1, sourceRect, destRect);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -22,7 +22,6 @@ namespace Avalonia.Media.Immutable
|
||||
/// How the source rectangle will be stretched to fill the destination rect.
|
||||
/// </param>
|
||||
/// <param name="tileMode">The tile mode.</param>
|
||||
/// <param name="bitmapInterpolationMode">The bitmap interpolation mode.</param>
|
||||
public ImmutableImageBrush(
|
||||
IBitmap? source,
|
||||
AlignmentX alignmentX = AlignmentX.Center,
|
||||
@@ -33,8 +32,7 @@ namespace Avalonia.Media.Immutable
|
||||
RelativePoint transformOrigin = default,
|
||||
RelativeRect? sourceRect = null,
|
||||
Stretch stretch = Stretch.Uniform,
|
||||
TileMode tileMode = TileMode.None,
|
||||
BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default)
|
||||
TileMode tileMode = TileMode.None)
|
||||
: base(
|
||||
alignmentX,
|
||||
alignmentY,
|
||||
@@ -44,8 +42,7 @@ namespace Avalonia.Media.Immutable
|
||||
transformOrigin,
|
||||
sourceRect ?? RelativeRect.Fill,
|
||||
stretch,
|
||||
tileMode,
|
||||
bitmapInterpolationMode)
|
||||
tileMode)
|
||||
{
|
||||
Source = source;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ namespace Avalonia.Media.Immutable
|
||||
/// How the source rectangle will be stretched to fill the destination rect.
|
||||
/// </param>
|
||||
/// <param name="tileMode">The tile mode.</param>
|
||||
/// <param name="bitmapInterpolationMode">The bitmap interpolation mode.</param>
|
||||
protected ImmutableTileBrush(
|
||||
AlignmentX alignmentX,
|
||||
AlignmentY alignmentY,
|
||||
@@ -31,8 +30,7 @@ namespace Avalonia.Media.Immutable
|
||||
RelativePoint transformOrigin,
|
||||
RelativeRect sourceRect,
|
||||
Stretch stretch,
|
||||
TileMode tileMode,
|
||||
BitmapInterpolationMode bitmapInterpolationMode)
|
||||
TileMode tileMode)
|
||||
{
|
||||
AlignmentX = alignmentX;
|
||||
AlignmentY = alignmentY;
|
||||
@@ -43,7 +41,6 @@ namespace Avalonia.Media.Immutable
|
||||
SourceRect = sourceRect;
|
||||
Stretch = stretch;
|
||||
TileMode = tileMode;
|
||||
BitmapInterpolationMode = bitmapInterpolationMode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -60,8 +57,7 @@ namespace Avalonia.Media.Immutable
|
||||
source.TransformOrigin,
|
||||
source.SourceRect,
|
||||
source.Stretch,
|
||||
source.TileMode,
|
||||
source.BitmapInterpolationMode)
|
||||
source.TileMode)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -95,8 +91,5 @@ namespace Avalonia.Media.Immutable
|
||||
|
||||
/// <inheritdoc/>
|
||||
public TileMode TileMode { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public BitmapInterpolationMode BitmapInterpolationMode { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,12 @@ internal sealed class PlatformDrawingContext : DrawingContext, IDrawingContextWi
|
||||
_ownsImpl = ownsImpl;
|
||||
}
|
||||
|
||||
public RenderOptions RenderOptions
|
||||
{
|
||||
get => _impl.RenderOptions;
|
||||
set => _impl.RenderOptions = value;
|
||||
}
|
||||
|
||||
protected override void DrawLineCore(IPen pen, Point p1, Point p2) =>
|
||||
_impl.DrawLine(pen, p1, p2);
|
||||
|
||||
@@ -38,9 +44,8 @@ internal sealed class PlatformDrawingContext : DrawingContext, IDrawingContextWi
|
||||
|
||||
protected override void DrawEllipseCore(IBrush? brush, IPen? pen, Rect rect) => _impl.DrawEllipse(brush, pen, rect);
|
||||
|
||||
internal override void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect,
|
||||
BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default) =>
|
||||
_impl.DrawBitmap(source, opacity, sourceRect, destRect, bitmapInterpolationMode);
|
||||
internal override void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect) =>
|
||||
_impl.DrawBitmap(source, opacity, sourceRect, destRect);
|
||||
|
||||
public override void Custom(ICustomDrawOperation custom)
|
||||
{
|
||||
@@ -77,9 +82,6 @@ internal sealed class PlatformDrawingContext : DrawingContext, IDrawingContextWi
|
||||
protected override void PushOpacityMaskCore(IBrush mask, Rect bounds) =>
|
||||
_impl.PushOpacityMask(mask, bounds);
|
||||
|
||||
protected override void PushBitmapBlendModeCore(BitmapBlendingMode blendingMode) =>
|
||||
_impl.PushBitmapBlendMode(blendingMode);
|
||||
|
||||
protected override void PushTransformCore(Matrix matrix)
|
||||
{
|
||||
_transforms ??= TransformStackPool.Get();
|
||||
@@ -96,8 +98,6 @@ internal sealed class PlatformDrawingContext : DrawingContext, IDrawingContextWi
|
||||
|
||||
protected override void PopOpacityMaskCore() => _impl.PopOpacityMask();
|
||||
|
||||
protected override void PopBitmapBlendModeCore() => _impl.PopBitmapBlendMode();
|
||||
|
||||
protected override void PopTransformCore() =>
|
||||
_impl.Transform =
|
||||
(_transforms ?? throw new ObjectDisposedException(nameof(PlatformDrawingContext))).Pop();
|
||||
|
||||
@@ -1,36 +1,131 @@
|
||||
using Avalonia.Media.Imaging;
|
||||
|
||||
namespace Avalonia.Media
|
||||
{
|
||||
public class RenderOptions
|
||||
{
|
||||
public readonly record struct RenderOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the <see cref="BitmapInterpolationMode"/> property.
|
||||
/// </summary>
|
||||
public static readonly StyledProperty<BitmapInterpolationMode> BitmapInterpolationModeProperty =
|
||||
AvaloniaProperty.RegisterAttached<RenderOptions, AvaloniaObject, BitmapInterpolationMode>(
|
||||
"BitmapInterpolationMode",
|
||||
BitmapInterpolationMode.MediumQuality,
|
||||
inherits: true);
|
||||
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 control.
|
||||
/// Gets the value of the BitmapInterpolationMode 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 BitmapInterpolationMode GetBitmapInterpolationMode(Visual visual)
|
||||
{
|
||||
return element.GetValue(BitmapInterpolationModeProperty);
|
||||
return visual.RenderOptions.BitmapInterpolationMode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of the BitmapInterpolationMode attached property for a control.
|
||||
/// Sets the value of the BitmapInterpolationMode 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 SetBitmapInterpolationMode(Visual visual, BitmapInterpolationMode value)
|
||||
{
|
||||
element.SetValue(BitmapInterpolationModeProperty, value);
|
||||
visual.RenderOptions = visual.RenderOptions with { BitmapInterpolationMode = value };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the BitmapBlendingMode attached property for a visual.
|
||||
/// </summary>
|
||||
/// <param name="visual">The control.</param>
|
||||
/// <returns>The control's left coordinate.</returns>
|
||||
public static BitmapBlendingMode GetBitmapBlendingMode(Visual visual)
|
||||
{
|
||||
return visual.RenderOptions.BitmapBlendingMode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of the BitmapBlendingMode attached property for a visual.
|
||||
/// </summary>
|
||||
/// <param name="visual">The control.</param>
|
||||
/// <param name="value">The left value.</param>
|
||||
public static void SetBitmapBlendingMode(Visual visual, BitmapBlendingMode 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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using Avalonia.Collections;
|
||||
using Avalonia.Collections.Pooled;
|
||||
using Avalonia.Media.TextFormatting;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Utilities;
|
||||
|
||||
namespace Avalonia.Media
|
||||
{
|
||||
@@ -218,7 +214,7 @@ namespace Avalonia.Media
|
||||
{
|
||||
var offsetY = glyphRun.BaselineOrigin.Y - origin.Y;
|
||||
|
||||
var intersections = glyphRun.PlatformImpl.Item.GetIntersections((float)(thickness * 0.5d - offsetY), (float)(thickness * 1.5d - offsetY));
|
||||
var intersections = glyphRun.GetIntersections((float)(thickness * 0.5d - offsetY), (float)(thickness * 1.5d - offsetY));
|
||||
|
||||
if (intersections.Count > 0)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Avalonia.Media
|
||||
{
|
||||
public enum TextRenderingMode : byte
|
||||
{
|
||||
Unspecified,
|
||||
|
||||
SubpixelAntialias,
|
||||
Antialias,
|
||||
Alias
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,6 @@ namespace Avalonia.Media
|
||||
SourceRectProperty,
|
||||
StretchProperty,
|
||||
TileModeProperty);
|
||||
RenderOptions.BitmapInterpolationModeProperty.OverrideDefaultValue<TileBrush>(BitmapInterpolationMode.Default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -140,17 +139,5 @@ namespace Avalonia.Media
|
||||
get { return (TileMode)GetValue(TileModeProperty); }
|
||||
set { SetValue(TileModeProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the bitmap interpolation mode.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The bitmap interpolation mode.
|
||||
/// </value>
|
||||
public BitmapInterpolationMode BitmapInterpolationMode
|
||||
{
|
||||
get { return RenderOptions.GetBitmapInterpolationMode(this); }
|
||||
set { RenderOptions.SetBitmapInterpolationMode(this, value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Utilities;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Metadata;
|
||||
using Avalonia.Media.Imaging;
|
||||
|
||||
namespace Avalonia.Platform
|
||||
{
|
||||
@@ -12,6 +12,11 @@ namespace Avalonia.Platform
|
||||
[Unstable]
|
||||
public interface IDrawingContextImpl : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the current render options used to control the rendering behavior of drawing operations.
|
||||
/// </summary>
|
||||
RenderOptions RenderOptions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current transform of the drawing context.
|
||||
/// </summary>
|
||||
@@ -30,8 +35,7 @@ namespace Avalonia.Platform
|
||||
/// <param name="opacity">The opacity to draw with.</param>
|
||||
/// <param name="sourceRect">The rect in the image to draw.</param>
|
||||
/// <param name="destRect">The rect in the output to draw to.</param>
|
||||
/// <param name="bitmapInterpolationMode">The bitmap interpolation mode.</param>
|
||||
void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default);
|
||||
void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect);
|
||||
|
||||
/// <summary>
|
||||
/// Draws a bitmap image.
|
||||
@@ -157,15 +161,6 @@ namespace Avalonia.Platform
|
||||
void PopGeometryClip();
|
||||
|
||||
/// <summary>
|
||||
/// Pushes a bitmap blending value.
|
||||
/// </summary>
|
||||
/// <param name="blendingMode">The bitmap blending mode.</param>
|
||||
void PushBitmapBlendMode(BitmapBlendingMode blendingMode);
|
||||
|
||||
/// <summary>
|
||||
/// Pops the latest pushed bitmap blending value.
|
||||
/// </summary>
|
||||
void PopBitmapBlendMode();
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to get an optional feature from the drawing context implementation
|
||||
|
||||
@@ -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,25 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Metadata;
|
||||
|
||||
namespace Avalonia.Platform
|
||||
{
|
||||
/// <summary>
|
||||
/// Actual implementation of a glyph run that stores platform dependent resources.
|
||||
/// An immutable platform representation of a <see cref="GlyphRun"/>.
|
||||
/// </summary>
|
||||
[Unstable]
|
||||
public interface IGlyphRunImpl : IDisposable
|
||||
public interface IGlyphRunImpl : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the conservative bounding box of the glyph run./>.
|
||||
/// Gets the <see cref="IGlyphTypeface"/> for the <see cref="IGlyphRunImpl"/>.
|
||||
/// </summary>
|
||||
Rect Bounds { get; }
|
||||
IGlyphTypeface GlyphTypeface { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the em size used for rendering the <see cref="IGlyphRunImpl"/>.
|
||||
/// </summary>
|
||||
double FontRenderingEmSize { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the baseline origin of the glyph run./>.
|
||||
/// </summary>
|
||||
Point BaselineOrigin { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the conservative bounding box of the glyph run./>.
|
||||
/// </summary>
|
||||
Rect Bounds { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the intersections of specified upper and lower limit.
|
||||
/// </summary>
|
||||
|
||||
@@ -169,8 +169,9 @@ namespace Avalonia.Platform
|
||||
/// <param name="fontRenderingEmSize">The font rendering em size.</param>
|
||||
/// <param name="glyphInfos">The list of glyphs.</param>
|
||||
/// <param name="baselineOrigin">The baseline origin of the run. Can be null.</param>
|
||||
/// <param name="bounds">the conservative bounding box of the run</param>
|
||||
/// <returns>An <see cref="IGlyphRunImpl"/>.</returns>
|
||||
IGlyphRunImpl CreateGlyphRun(IGlyphTypeface glyphTypeface, double fontRenderingEmSize, IReadOnlyList<GlyphInfo> glyphInfos, Point baselineOrigin);
|
||||
IGlyphRunImpl CreateGlyphRun(IGlyphTypeface glyphTypeface, double fontRenderingEmSize, IReadOnlyList<GlyphInfo> glyphInfos, Point baselineOrigin, Rect bounds);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a backend-specific object using a low-level API graphics context
|
||||
|
||||
@@ -260,6 +260,8 @@ public class CompositingRenderer : IRendererWithCompositor
|
||||
if (!comp.Effect.EffectEquals(visual.Effect))
|
||||
comp.Effect = visual.Effect?.ToImmutable();
|
||||
|
||||
comp.RenderOptions = visual.RenderOptions;
|
||||
|
||||
var renderTransform = Matrix.Identity;
|
||||
|
||||
if (visual.HasMirrorTransform)
|
||||
@@ -272,8 +274,6 @@ public class CompositingRenderer : IRendererWithCompositor
|
||||
renderTransform *= (-offset) * visual.RenderTransform.Value * (offset);
|
||||
}
|
||||
|
||||
|
||||
|
||||
comp.TransformMatrix = MatrixUtils.ToMatrix4x4(renderTransform);
|
||||
|
||||
_recorder.BeginUpdate(comp.DrawList);
|
||||
|
||||
@@ -78,15 +78,14 @@ internal sealed class CompositionDrawingContext : DrawingContext, IDrawingContex
|
||||
}
|
||||
}
|
||||
|
||||
internal override void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect,
|
||||
BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default)
|
||||
internal override void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect)
|
||||
{
|
||||
var next = NextDrawAs<ImageNode>();
|
||||
|
||||
if (next == null ||
|
||||
!next.Item.Equals(Transform, source, opacity, sourceRect, destRect, bitmapInterpolationMode))
|
||||
!next.Item.Equals(Transform, source, opacity, sourceRect, destRect))
|
||||
{
|
||||
Add(new ImageNode(Transform, source, opacity, sourceRect, destRect, bitmapInterpolationMode));
|
||||
Add(new ImageNode(Transform, source, opacity, sourceRect, destRect));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -227,20 +226,6 @@ internal sealed class CompositionDrawingContext : DrawingContext, IDrawingContex
|
||||
}
|
||||
}
|
||||
|
||||
protected override void PopBitmapBlendModeCore()
|
||||
{
|
||||
var next = NextDrawAs<BitmapBlendModeNode>();
|
||||
|
||||
if (next == null || !next.Item.Equals(null))
|
||||
{
|
||||
Add(new BitmapBlendModeNode());
|
||||
}
|
||||
else
|
||||
{
|
||||
++_drawOperationIndex;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void PopOpacityCore()
|
||||
{
|
||||
var next = NextDrawAs<OpacityNode>();
|
||||
@@ -354,21 +339,6 @@ internal sealed class CompositionDrawingContext : DrawingContext, IDrawingContex
|
||||
_needsToPopOpacityMask.Push(needsToPop);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void PushBitmapBlendModeCore(BitmapBlendingMode blendingMode)
|
||||
{
|
||||
var next = NextDrawAs<BitmapBlendModeNode>();
|
||||
|
||||
if (next == null || !next.Item.Equals(blendingMode))
|
||||
{
|
||||
Add(new BitmapBlendModeNode(blendingMode));
|
||||
}
|
||||
else
|
||||
{
|
||||
++_drawOperationIndex;
|
||||
}
|
||||
}
|
||||
|
||||
private void Add<T>(T node) where T : class, IDrawOperation
|
||||
{
|
||||
if (_drawOperationIndex < _builder.Count)
|
||||
|
||||
@@ -42,15 +42,20 @@ internal class CompositorDrawingContextProxy : IDrawingContextImpl,
|
||||
set => _impl.Transform = (_transform = value) * PostTransform;
|
||||
}
|
||||
|
||||
public RenderOptions RenderOptions
|
||||
{
|
||||
get => _impl.RenderOptions;
|
||||
set => _impl.RenderOptions = value;
|
||||
}
|
||||
|
||||
public void Clear(Color color)
|
||||
{
|
||||
_impl.Clear(color);
|
||||
}
|
||||
|
||||
public void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect,
|
||||
BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default)
|
||||
public void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect)
|
||||
{
|
||||
_impl.DrawBitmap(source, opacity, sourceRect, destRect, bitmapInterpolationMode);
|
||||
_impl.DrawBitmap(source, opacity, sourceRect, destRect);
|
||||
}
|
||||
|
||||
public void DrawBitmap(IRef<IBitmapImpl> source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect)
|
||||
@@ -133,16 +138,6 @@ internal class CompositorDrawingContextProxy : IDrawingContextImpl,
|
||||
_impl.PopGeometryClip();
|
||||
}
|
||||
|
||||
public void PushBitmapBlendMode(BitmapBlendingMode blendingMode)
|
||||
{
|
||||
_impl.PushBitmapBlendMode(blendingMode);
|
||||
}
|
||||
|
||||
public void PopBitmapBlendMode()
|
||||
{
|
||||
_impl.PopBitmapBlendMode();
|
||||
}
|
||||
|
||||
public object? GetFeature(Type t) => _impl.GetFeature(t);
|
||||
|
||||
|
||||
|
||||
@@ -181,7 +181,7 @@ namespace Avalonia.Rendering.Composition.Server
|
||||
else
|
||||
targetContext.DrawBitmap(RefCountable.CreateUnownedNotClonable(_layer), 1,
|
||||
new Rect(_layerSize),
|
||||
new Rect(Size), BitmapInterpolationMode.LowQuality);
|
||||
new Rect(Size));
|
||||
|
||||
if (DebugOverlays != RendererDebugOverlays.None)
|
||||
{
|
||||
|
||||
@@ -66,6 +66,8 @@ namespace Avalonia.Rendering.Composition.Server
|
||||
if (OpacityMaskBrush != null)
|
||||
canvas.PushOpacityMask(OpacityMaskBrush, boundsRect);
|
||||
|
||||
canvas.RenderOptions = RenderOptions;
|
||||
|
||||
RenderCore(canvas, currentTransformedClip);
|
||||
|
||||
// Hack to force invalidation of SKMatrix
|
||||
@@ -122,6 +124,11 @@ namespace Avalonia.Rendering.Composition.Server
|
||||
|
||||
var wasVisible = IsVisibleInFrame;
|
||||
|
||||
if(Parent != null)
|
||||
{
|
||||
RenderOptions = RenderOptions.MergeWith(Parent.RenderOptions);
|
||||
}
|
||||
|
||||
// Calculate new parent-relative transform
|
||||
if (_combinedTransformDirty)
|
||||
{
|
||||
|
||||
@@ -44,79 +44,99 @@ namespace Avalonia.Rendering
|
||||
|
||||
public static void Render(DrawingContext context, Visual visual, Rect clipRect)
|
||||
{
|
||||
var opacity = visual.Opacity;
|
||||
var clipToBounds = visual.ClipToBounds;
|
||||
var bounds = new Rect(visual.Bounds.Size);
|
||||
var currentRenderOptions = default(RenderOptions);
|
||||
var platformContext = context as PlatformDrawingContext;
|
||||
|
||||
if (visual.IsVisible && opacity > 0)
|
||||
try
|
||||
{
|
||||
var m = Matrix.CreateTranslation(visual.Bounds.Position);
|
||||
|
||||
var renderTransform = Matrix.Identity;
|
||||
|
||||
// this should be calculated BEFORE renderTransform
|
||||
if (visual.HasMirrorTransform)
|
||||
if (platformContext != null)
|
||||
{
|
||||
var mirrorMatrix = new Matrix(-1.0, 0.0, 0.0, 1.0, visual.Bounds.Width, 0);
|
||||
renderTransform *= mirrorMatrix;
|
||||
currentRenderOptions = platformContext.RenderOptions;
|
||||
|
||||
platformContext.RenderOptions = visual.RenderOptions.MergeWith(platformContext.RenderOptions);
|
||||
}
|
||||
|
||||
if (visual.RenderTransform != null)
|
||||
{
|
||||
var origin = visual.RenderTransformOrigin.ToPixels(new Size(visual.Bounds.Width, visual.Bounds.Height));
|
||||
var offset = Matrix.CreateTranslation(origin);
|
||||
var finalTransform = (-offset) * visual.RenderTransform.Value * (offset);
|
||||
renderTransform *= finalTransform;
|
||||
}
|
||||
var opacity = visual.Opacity;
|
||||
var clipToBounds = visual.ClipToBounds;
|
||||
var bounds = new Rect(visual.Bounds.Size);
|
||||
|
||||
m = renderTransform * m;
|
||||
|
||||
if (clipToBounds)
|
||||
if (visual.IsVisible && opacity > 0)
|
||||
{
|
||||
var m = Matrix.CreateTranslation(visual.Bounds.Position);
|
||||
|
||||
var renderTransform = Matrix.Identity;
|
||||
|
||||
// this should be calculated BEFORE renderTransform
|
||||
if (visual.HasMirrorTransform)
|
||||
{
|
||||
var mirrorMatrix = new Matrix(-1.0, 0.0, 0.0, 1.0, visual.Bounds.Width, 0);
|
||||
renderTransform *= mirrorMatrix;
|
||||
}
|
||||
|
||||
if (visual.RenderTransform != null)
|
||||
{
|
||||
clipRect = new Rect(visual.Bounds.Size);
|
||||
var origin = visual.RenderTransformOrigin.ToPixels(new Size(visual.Bounds.Width, visual.Bounds.Height));
|
||||
var offset = Matrix.CreateTranslation(origin);
|
||||
var finalTransform = (-offset) * visual.RenderTransform.Value * (offset);
|
||||
renderTransform *= finalTransform;
|
||||
}
|
||||
else
|
||||
{
|
||||
clipRect = clipRect.Intersect(new Rect(visual.Bounds.Size));
|
||||
}
|
||||
}
|
||||
|
||||
using (context.PushTransform(m))
|
||||
using (context.PushOpacity(opacity, bounds))
|
||||
using (clipToBounds
|
||||
m = renderTransform * m;
|
||||
|
||||
if (clipToBounds)
|
||||
{
|
||||
if (visual.RenderTransform != null)
|
||||
{
|
||||
clipRect = new Rect(visual.Bounds.Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
clipRect = clipRect.Intersect(new Rect(visual.Bounds.Size));
|
||||
}
|
||||
}
|
||||
|
||||
using (context.PushTransform(m))
|
||||
using (context.PushOpacity(opacity, bounds))
|
||||
using (clipToBounds
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
? visual is IVisualWithRoundRectClip roundClipVisual
|
||||
? context.PushClip(new RoundedRect(bounds, roundClipVisual.ClipToBoundsRadius))
|
||||
: context.PushClip(bounds)
|
||||
: default)
|
||||
? visual is IVisualWithRoundRectClip roundClipVisual
|
||||
? context.PushClip(new RoundedRect(bounds, roundClipVisual.ClipToBoundsRadius))
|
||||
: context.PushClip(bounds)
|
||||
: default)
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
using (visual.Clip != null ? context.PushGeometryClip(visual.Clip) : default)
|
||||
using (visual.OpacityMask != null ? context.PushOpacityMask(visual.OpacityMask, bounds) : default)
|
||||
using (context.PushTransform(Matrix.Identity))
|
||||
{
|
||||
visual.Render(context);
|
||||
|
||||
var childrenEnumerable = visual.HasNonUniformZIndexChildren
|
||||
? visual.VisualChildren.OrderBy(x => x, ZIndexComparer.Instance)
|
||||
: (IEnumerable<Visual>)visual.VisualChildren;
|
||||
|
||||
foreach (var child in childrenEnumerable)
|
||||
using (visual.Clip != null ? context.PushGeometryClip(visual.Clip) : default)
|
||||
using (visual.OpacityMask != null ? context.PushOpacityMask(visual.OpacityMask, bounds) : default)
|
||||
using (context.PushTransform(Matrix.Identity))
|
||||
{
|
||||
var childBounds = GetTransformedBounds(child);
|
||||
visual.Render(context);
|
||||
|
||||
if (!child.ClipToBounds || clipRect.Intersects(childBounds))
|
||||
var childrenEnumerable = visual.HasNonUniformZIndexChildren
|
||||
? visual.VisualChildren.OrderBy(x => x, ZIndexComparer.Instance)
|
||||
: (IEnumerable<Visual>)visual.VisualChildren;
|
||||
|
||||
foreach (var child in childrenEnumerable)
|
||||
{
|
||||
var childClipRect = child.RenderTransform == null
|
||||
? clipRect.Translate(-childBounds.Position)
|
||||
: clipRect;
|
||||
Render(context, child, childClipRect);
|
||||
}
|
||||
var childBounds = GetTransformedBounds(child);
|
||||
|
||||
if (!child.ClipToBounds || clipRect.Intersects(childBounds))
|
||||
{
|
||||
var childClipRect = child.RenderTransform == null
|
||||
? clipRect.Translate(-childBounds.Position)
|
||||
: clipRect;
|
||||
Render(context, child, childClipRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (platformContext != null)
|
||||
{
|
||||
platformContext.RenderOptions = currentRenderOptions;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,5 +1,4 @@
|
||||
using System;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Utilities;
|
||||
|
||||
@@ -18,7 +17,7 @@ namespace Avalonia.Rendering.SceneGraph
|
||||
/// <param name="glyphRun">The glyph run to draw.</param>
|
||||
public GlyphRunNode(
|
||||
Matrix transform,
|
||||
IImmutableBrush foreground,
|
||||
IImmutableBrush? foreground,
|
||||
IRef<IGlyphRunImpl> glyphRun)
|
||||
: base(glyphRun.Item.Bounds, transform, foreground)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Utilities;
|
||||
using Avalonia.Media.Imaging;
|
||||
|
||||
namespace Avalonia.Rendering.SceneGraph
|
||||
{
|
||||
@@ -17,15 +16,13 @@ namespace Avalonia.Rendering.SceneGraph
|
||||
/// <param name="opacity">The draw opacity.</param>
|
||||
/// <param name="sourceRect">The source rect.</param>
|
||||
/// <param name="destRect">The destination rect.</param>
|
||||
/// <param name="bitmapInterpolationMode">The bitmap interpolation mode.</param>
|
||||
public ImageNode(Matrix transform, IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode)
|
||||
public ImageNode(Matrix transform, IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect)
|
||||
: base(destRect, transform)
|
||||
{
|
||||
Source = source.Clone();
|
||||
Opacity = opacity;
|
||||
SourceRect = sourceRect;
|
||||
DestRect = destRect;
|
||||
BitmapInterpolationMode = bitmapInterpolationMode;
|
||||
SourceVersion = Source.Item.Version;
|
||||
}
|
||||
|
||||
@@ -53,14 +50,6 @@ namespace Avalonia.Rendering.SceneGraph
|
||||
/// Gets the destination rect.
|
||||
/// </summary>
|
||||
public Rect DestRect { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bitmap interpolation mode.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The scaling mode.
|
||||
/// </value>
|
||||
public BitmapInterpolationMode BitmapInterpolationMode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if this draw operation equals another.
|
||||
@@ -70,27 +59,25 @@ namespace Avalonia.Rendering.SceneGraph
|
||||
/// <param name="opacity">The opacity of the other draw operation.</param>
|
||||
/// <param name="sourceRect">The source rect of the other draw operation.</param>
|
||||
/// <param name="destRect">The dest rect of the other draw operation.</param>
|
||||
/// <param name="bitmapInterpolationMode">The bitmap interpolation mode.</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(Matrix transform, IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode)
|
||||
public bool Equals(Matrix transform, IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect)
|
||||
{
|
||||
return transform == Transform &&
|
||||
Equals(source.Item, Source.Item) &&
|
||||
source.Item.Version == SourceVersion &&
|
||||
opacity == Opacity &&
|
||||
sourceRect == SourceRect &&
|
||||
destRect == DestRect &&
|
||||
bitmapInterpolationMode == BitmapInterpolationMode;
|
||||
destRect == DestRect;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Render(IDrawingContextImpl context)
|
||||
{
|
||||
context.DrawBitmap(Source, Opacity, SourceRect, DestRect, BitmapInterpolationMode);
|
||||
context.DrawBitmap(Source, Opacity, SourceRect, DestRect);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -331,6 +331,8 @@ public class DispatcherOperation<T> : DispatcherOperation
|
||||
|
||||
private TaskCompletionSource<T> TaskCompletionSource => (TaskCompletionSource<T>)TaskSource!;
|
||||
|
||||
public new TaskAwaiter<T> GetAwaiter() => GetTask().GetAwaiter();
|
||||
|
||||
public new Task<T> GetTask() => TaskCompletionSource!.Task;
|
||||
|
||||
protected override Task GetTaskCore() => GetTask();
|
||||
|
||||
@@ -318,7 +318,9 @@ namespace Avalonia
|
||||
|
||||
internal CompositionDrawListVisual? CompositionVisual { get; private set; }
|
||||
internal CompositionVisual? ChildCompositionVisual { get; set; }
|
||||
|
||||
|
||||
internal RenderOptions RenderOptions { get; set; }
|
||||
|
||||
public bool HasNonUniformZIndexChildren { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
<Property Name="AdornerIsClipped" Type="bool" Internal="true" />
|
||||
<Property Name="OpacityMaskBrush" Type="Avalonia.Media.IImmutableBrush?" Internal="true" />
|
||||
<Property Name="Effect" Type="Avalonia.Media.IImmutableEffect?" Internal="true" />
|
||||
<Property Name="RenderOptions" Type="Avalonia.Media.RenderOptions" />
|
||||
</Object>
|
||||
<Object Name="CompositionContainerVisual" Inherits="CompositionVisual"/>
|
||||
<Object Name="CompositionSolidColorVisual" Inherits="CompositionContainerVisual">
|
||||
|
||||
@@ -91,9 +91,7 @@ namespace Avalonia.Controls
|
||||
Rect sourceRect = new Rect(sourceSize)
|
||||
.CenterRect(new Rect(destRect.Size / scale));
|
||||
|
||||
var interpolationMode = RenderOptions.GetBitmapInterpolationMode(this);
|
||||
|
||||
context.DrawImage(source, sourceRect, destRect, interpolationMode);
|
||||
context.DrawImage(source, sourceRect, destRect);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Tmds.DBus.Protocol" Version="0.15.0" />
|
||||
<PackageReference Include="Tmds.DBus.SourceGenerator" Version="0.0.5" PrivateAssets="All" />
|
||||
<PackageReference Include="Tmds.DBus.SourceGenerator" Version="0.0.6" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -2,11 +2,9 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Rendering;
|
||||
using Avalonia.Rendering.SceneGraph;
|
||||
using Avalonia.Utilities;
|
||||
using Avalonia.Media.Imaging;
|
||||
@@ -127,7 +125,8 @@ namespace Avalonia.Headless
|
||||
IGlyphTypeface glyphTypeface,
|
||||
double fontRenderingEmSize,
|
||||
IReadOnlyList<GlyphInfo> glyphInfos,
|
||||
Point baselineOrigin)
|
||||
Point baselineOrigin,
|
||||
Rect bounds)
|
||||
{
|
||||
return new HeadlessGlyphRunStub();
|
||||
}
|
||||
@@ -138,6 +137,10 @@ namespace Avalonia.Headless
|
||||
|
||||
public Point BaselineOrigin => new Point(0, 8);
|
||||
|
||||
public IGlyphTypeface GlyphTypeface => new HeadlessGlyphTypefaceImpl();
|
||||
|
||||
public double FontRenderingEmSize => 12;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
@@ -374,6 +377,8 @@ namespace Avalonia.Headless
|
||||
|
||||
public Matrix Transform { get; set; }
|
||||
|
||||
public RenderOptions RenderOptions { get; set; }
|
||||
|
||||
public void Clear(Color color)
|
||||
{
|
||||
|
||||
@@ -451,7 +456,7 @@ namespace Avalonia.Headless
|
||||
{
|
||||
}
|
||||
|
||||
public void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default)
|
||||
public void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -24,10 +24,8 @@ namespace Avalonia.Skia
|
||||
private readonly Vector _dpi;
|
||||
private readonly Stack<PaintWrapper> _maskStack = new();
|
||||
private readonly Stack<double> _opacityStack = new();
|
||||
private readonly Stack<BitmapBlendingMode> _blendingModeStack = new();
|
||||
private readonly Matrix? _postTransform;
|
||||
private double _currentOpacity = 1.0f;
|
||||
private BitmapBlendingMode _currentBlendingMode = BitmapBlendingMode.SourceOver;
|
||||
private readonly bool _canTextUseLcdRendering;
|
||||
private Matrix _currentTransform;
|
||||
private bool _disposed;
|
||||
@@ -168,6 +166,8 @@ namespace Avalonia.Skia
|
||||
public SKCanvas Canvas { get; }
|
||||
public SKSurface? Surface { get; }
|
||||
|
||||
public RenderOptions RenderOptions { get; set; }
|
||||
|
||||
private void CheckLease()
|
||||
{
|
||||
if (_leased)
|
||||
@@ -182,7 +182,7 @@ namespace Avalonia.Skia
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode)
|
||||
public void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect)
|
||||
{
|
||||
CheckLease();
|
||||
var drawableImage = (IDrawableBitmapImpl)source.Item;
|
||||
@@ -191,8 +191,8 @@ namespace Avalonia.Skia
|
||||
|
||||
var paint = SKPaintCache.Shared.Get();
|
||||
paint.Color = new SKColor(255, 255, 255, (byte)(255 * opacity * (_useOpacitySaveLayer ? 1 : _currentOpacity)));
|
||||
paint.FilterQuality = bitmapInterpolationMode.ToSKFilterQuality();
|
||||
paint.BlendMode = _currentBlendingMode.ToSKBlendMode();
|
||||
paint.FilterQuality = RenderOptions.BitmapInterpolationMode.ToSKFilterQuality();
|
||||
paint.BlendMode = RenderOptions.BitmapBlendingMode.ToSKBlendMode();
|
||||
|
||||
drawableImage.Draw(this, s, d, paint);
|
||||
SKPaintCache.Shared.ReturnReset(paint);
|
||||
@@ -203,7 +203,7 @@ namespace Avalonia.Skia
|
||||
{
|
||||
CheckLease();
|
||||
PushOpacityMask(opacityMask, opacityMaskRect);
|
||||
DrawBitmap(source, 1, new Rect(0, 0, source.Item.PixelSize.Width, source.Item.PixelSize.Height), destRect, BitmapInterpolationMode.Default);
|
||||
DrawBitmap(source, 1, new Rect(0, 0, source.Item.PixelSize.Width, source.Item.PixelSize.Height), destRect);
|
||||
PopOpacityMask();
|
||||
}
|
||||
|
||||
@@ -519,7 +519,9 @@ namespace Avalonia.Skia
|
||||
{
|
||||
var glyphRunImpl = (GlyphRunImpl)glyphRun.Item;
|
||||
|
||||
Canvas.DrawText(glyphRunImpl.TextBlob, (float)glyphRun.Item.BaselineOrigin.X,
|
||||
var textBlob = glyphRunImpl.GetTextBlob(RenderOptions);
|
||||
|
||||
Canvas.DrawText(textBlob, (float)glyphRun.Item.BaselineOrigin.X,
|
||||
(float)glyphRun.Item.BaselineOrigin.Y, paintWrapper.Paint);
|
||||
}
|
||||
}
|
||||
@@ -649,21 +651,6 @@ namespace Avalonia.Skia
|
||||
Canvas.Restore();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void PushBitmapBlendMode(BitmapBlendingMode blendingMode)
|
||||
{
|
||||
CheckLease();
|
||||
_blendingModeStack.Push(_currentBlendingMode);
|
||||
_currentBlendingMode = blendingMode;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void PopBitmapBlendMode()
|
||||
{
|
||||
CheckLease();
|
||||
_currentBlendingMode = _blendingModeStack.Pop();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void PushOpacityMask(IBrush mask, Rect bounds)
|
||||
{
|
||||
@@ -905,12 +892,14 @@ namespace Avalonia.Skia
|
||||
context.Clear(Colors.Transparent);
|
||||
context.PushClip(calc.IntermediateClip);
|
||||
context.Transform = calc.IntermediateTransform;
|
||||
context.RenderOptions = RenderOptions;
|
||||
|
||||
context.DrawBitmap(
|
||||
RefCountable.CreateUnownedNotClonable(tileBrushImage),
|
||||
1,
|
||||
sourceRect,
|
||||
targetRect,
|
||||
tileBrush.BitmapInterpolationMode);
|
||||
targetRect);
|
||||
|
||||
context.PopClip();
|
||||
}
|
||||
|
||||
@@ -1143,7 +1132,7 @@ namespace Avalonia.Skia
|
||||
{
|
||||
var paintWrapper = new PaintWrapper(paint);
|
||||
|
||||
paint.IsAntialias = true;
|
||||
paint.IsAntialias = RenderOptions.EdgeMode != EdgeMode.Aliased;
|
||||
|
||||
double opacity = brush.Opacity * (_useOpacitySaveLayer ? 1 :_currentOpacity);
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Media.TextFormatting;
|
||||
using Avalonia.Platform;
|
||||
using SkiaSharp;
|
||||
|
||||
@@ -7,30 +9,122 @@ namespace Avalonia.Skia
|
||||
{
|
||||
internal class GlyphRunImpl : IGlyphRunImpl
|
||||
{
|
||||
public GlyphRunImpl(SKTextBlob textBlob, Size size, Point baselineOrigin)
|
||||
private readonly GlyphTypefaceImpl _glyphTypefaceImpl;
|
||||
private readonly ushort[] _glyphIndices;
|
||||
private readonly SKPoint[] _glyphPositions;
|
||||
|
||||
private readonly Dictionary<SKFontEdging, SKTextBlob> _textBlobCache = new(1);
|
||||
|
||||
public GlyphRunImpl(IGlyphTypeface glyphTypeface, double fontRenderingEmSize,
|
||||
IReadOnlyList<GlyphInfo> glyphInfos, Point baselineOrigin, Rect bounds)
|
||||
{
|
||||
TextBlob = textBlob ?? throw new ArgumentNullException(nameof(textBlob));
|
||||
if (glyphTypeface == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(glyphTypeface));
|
||||
}
|
||||
|
||||
Bounds = new Rect(new Point(baselineOrigin.X, 0), size);
|
||||
_glyphTypefaceImpl = (GlyphTypefaceImpl)glyphTypeface;
|
||||
|
||||
if (glyphInfos == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(glyphInfos));
|
||||
}
|
||||
|
||||
var count = glyphInfos.Count;
|
||||
_glyphIndices = new ushort[count];
|
||||
_glyphPositions = new SKPoint[count];
|
||||
|
||||
var currentX = 0.0;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var glyphInfo = glyphInfos[i];
|
||||
var offset = glyphInfo.GlyphOffset;
|
||||
|
||||
_glyphIndices[i] = glyphInfo.GlyphIndex;
|
||||
|
||||
_glyphPositions[i] = new SKPoint((float)(currentX + offset.X), (float)offset.Y);
|
||||
|
||||
currentX += glyphInfos[i].GlyphAdvance;
|
||||
}
|
||||
|
||||
FontRenderingEmSize = fontRenderingEmSize;
|
||||
BaselineOrigin = baselineOrigin;
|
||||
Bounds = bounds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the text blob to draw.
|
||||
/// </summary>
|
||||
public SKTextBlob TextBlob { get; }
|
||||
public IGlyphTypeface GlyphTypeface => _glyphTypefaceImpl;
|
||||
|
||||
public Rect Bounds { get; }
|
||||
public double FontRenderingEmSize { get; }
|
||||
|
||||
public Point BaselineOrigin { get; }
|
||||
|
||||
public IReadOnlyList<float> GetIntersections(float upperBound, float lowerBound) =>
|
||||
TextBlob.GetIntercepts(lowerBound, upperBound);
|
||||
public Rect Bounds { get; }
|
||||
|
||||
void IDisposable.Dispose()
|
||||
public SKTextBlob GetTextBlob(RenderOptions renderOptions)
|
||||
{
|
||||
TextBlob.Dispose();
|
||||
var edging = SKFontEdging.SubpixelAntialias;
|
||||
|
||||
switch (renderOptions.TextRenderingMode)
|
||||
{
|
||||
case TextRenderingMode.Alias:
|
||||
edging = SKFontEdging.Alias;
|
||||
break;
|
||||
case TextRenderingMode.Antialias:
|
||||
edging = SKFontEdging.Antialias;
|
||||
break;
|
||||
case TextRenderingMode.Unspecified:
|
||||
edging = renderOptions.EdgeMode == EdgeMode.Aliased ? SKFontEdging.Alias : SKFontEdging.SubpixelAntialias;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_textBlobCache.TryGetValue(edging, out var textBlob))
|
||||
{
|
||||
return textBlob;
|
||||
}
|
||||
|
||||
var font = SKFontCache.Shared.Get();
|
||||
|
||||
font.LinearMetrics = true;
|
||||
font.Subpixel = edging == SKFontEdging.SubpixelAntialias;
|
||||
font.Edging = edging;
|
||||
font.Hinting = SKFontHinting.Full;
|
||||
font.Size = (float)FontRenderingEmSize;
|
||||
font.Typeface = _glyphTypefaceImpl.Typeface;
|
||||
font.Embolden = (_glyphTypefaceImpl.FontSimulations & FontSimulations.Bold) != 0;
|
||||
font.SkewX = (_glyphTypefaceImpl.FontSimulations & FontSimulations.Oblique) != 0 ? -0.2f : 0;
|
||||
|
||||
var builder = SKTextBlobBuilderCache.Shared.Get();
|
||||
|
||||
var runBuffer = builder.AllocatePositionedRun(font, _glyphIndices.Length);
|
||||
|
||||
runBuffer.SetPositions(_glyphPositions);
|
||||
runBuffer.SetGlyphs(_glyphIndices);
|
||||
|
||||
SKFontCache.Shared.Return(font);
|
||||
|
||||
textBlob = builder.Build();
|
||||
|
||||
SKTextBlobBuilderCache.Shared.Return(builder);
|
||||
|
||||
_textBlobCache.Add(edging, textBlob);
|
||||
|
||||
return textBlob;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var pair in _textBlobCache)
|
||||
{
|
||||
pair.Value.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public IReadOnlyList<float> GetIntersections(float lowerLimit, float upperLimit)
|
||||
{
|
||||
var textBlob = GetTextBlob(default);
|
||||
|
||||
return textBlob.GetIntercepts(lowerLimit, upperLimit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Rendering;
|
||||
|
||||
namespace Avalonia.Skia
|
||||
{
|
||||
|
||||
@@ -5,8 +5,8 @@ using Avalonia.Media;
|
||||
using Avalonia.OpenGL;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Media.TextFormatting;
|
||||
using SkiaSharp;
|
||||
using Avalonia.Media.TextFormatting;
|
||||
|
||||
namespace Avalonia.Skia
|
||||
{
|
||||
@@ -209,67 +209,10 @@ namespace Avalonia.Skia
|
||||
return new WriteableBitmapImpl(size, dpi, format, alphaFormat);
|
||||
}
|
||||
|
||||
public IGlyphRunImpl CreateGlyphRun(
|
||||
IGlyphTypeface glyphTypeface,
|
||||
double fontRenderingEmSize,
|
||||
IReadOnlyList<GlyphInfo> glyphInfos,
|
||||
Point baselineOrigin)
|
||||
public IGlyphRunImpl CreateGlyphRun(IGlyphTypeface glyphTypeface, double fontRenderingEmSize,
|
||||
IReadOnlyList<GlyphInfo> glyphInfos, Point baselineOrigin, Rect bounds)
|
||||
{
|
||||
if (glyphTypeface == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(glyphTypeface));
|
||||
}
|
||||
|
||||
if (glyphInfos == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(glyphInfos));
|
||||
}
|
||||
|
||||
var glyphTypefaceImpl = (GlyphTypefaceImpl)glyphTypeface;
|
||||
|
||||
var font = SKFontCache.Shared.Get();
|
||||
|
||||
font.LinearMetrics = true;
|
||||
font.Subpixel = true;
|
||||
font.Edging = SKFontEdging.SubpixelAntialias;
|
||||
font.Hinting = SKFontHinting.Full;
|
||||
font.Size = (float)fontRenderingEmSize;
|
||||
font.Typeface = glyphTypefaceImpl.Typeface;
|
||||
font.Embolden = (glyphTypefaceImpl.FontSimulations & FontSimulations.Bold) != 0;
|
||||
font.SkewX = (glyphTypefaceImpl.FontSimulations & FontSimulations.Oblique) != 0 ? -0.2f : 0;
|
||||
|
||||
|
||||
var builder = SKTextBlobBuilderCache.Shared.Get();
|
||||
var count = glyphInfos.Count;
|
||||
|
||||
var runBuffer = builder.AllocatePositionedRun(font, count);
|
||||
|
||||
var glyphSpan = runBuffer.GetGlyphSpan();
|
||||
var positionSpan = runBuffer.GetPositionSpan();
|
||||
|
||||
SKFontCache.Shared.Return(font);
|
||||
|
||||
var width = 0.0;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var glyphInfo = glyphInfos[i];
|
||||
var offset = glyphInfo.GlyphOffset;
|
||||
|
||||
glyphSpan[i] = glyphInfo.GlyphIndex;
|
||||
|
||||
positionSpan[i] = new SKPoint((float)(width + offset.X), (float)offset.Y);
|
||||
|
||||
width += glyphInfo.GlyphAdvance;
|
||||
}
|
||||
|
||||
var scale = fontRenderingEmSize / glyphTypeface.Metrics.DesignEmHeight;
|
||||
var height = glyphTypeface.Metrics.LineSpacing * scale;
|
||||
var skTextBlob = builder.Build();
|
||||
|
||||
SKTextBlobBuilderCache.Shared.Return(builder);
|
||||
|
||||
return new GlyphRunImpl(skTextBlob, new Size(width, height), baselineOrigin);
|
||||
return new GlyphRunImpl(glyphTypeface, fontRenderingEmSize, glyphInfos, baselineOrigin, bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,8 @@ namespace Avalonia.Skia
|
||||
return SKFilterQuality.Medium;
|
||||
case BitmapInterpolationMode.HighQuality:
|
||||
return SKFilterQuality.High;
|
||||
case BitmapInterpolationMode.Default:
|
||||
case BitmapInterpolationMode.None:
|
||||
case BitmapInterpolationMode.Unspecified:
|
||||
return SKFilterQuality.None;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(interpolationMode), interpolationMode, null);
|
||||
@@ -30,6 +31,7 @@ namespace Avalonia.Skia
|
||||
{
|
||||
switch (blendingMode)
|
||||
{
|
||||
case BitmapBlendingMode.Unspecified:
|
||||
case BitmapBlendingMode.SourceOver:
|
||||
return SKBlendMode.SrcOver;
|
||||
case BitmapBlendingMode.Source:
|
||||
|
||||
@@ -160,59 +160,9 @@ namespace Avalonia.Direct2D1
|
||||
public IStreamGeometryImpl CreateStreamGeometry() => new StreamGeometryImpl();
|
||||
public IGeometryImpl CreateGeometryGroup(FillRule fillRule, IReadOnlyList<IGeometryImpl> children) => new GeometryGroupImpl(fillRule, children);
|
||||
public IGeometryImpl CreateCombinedGeometry(GeometryCombineMode combineMode, IGeometryImpl g1, IGeometryImpl g2) => new CombinedGeometryImpl(combineMode, g1, g2);
|
||||
|
||||
public IGlyphRunImpl CreateGlyphRun(IGlyphTypeface glyphTypeface, double fontRenderingEmSize,
|
||||
IReadOnlyList<GlyphInfo> glyphInfos, Point baselineOrigin)
|
||||
public IGlyphRunImpl CreateGlyphRun(IGlyphTypeface glyphTypeface, double fontRenderingEmSize, IReadOnlyList<GlyphInfo> glyphInfos, Point baselineOrigin, Rect bounds)
|
||||
{
|
||||
var glyphTypefaceImpl = (GlyphTypefaceImpl)glyphTypeface;
|
||||
|
||||
var glyphCount = glyphInfos.Count;
|
||||
|
||||
var run = new SharpDX.DirectWrite.GlyphRun
|
||||
{
|
||||
FontFace = glyphTypefaceImpl.FontFace,
|
||||
FontSize = (float)fontRenderingEmSize
|
||||
};
|
||||
|
||||
var indices = new short[glyphCount];
|
||||
|
||||
for (var i = 0; i < glyphCount; i++)
|
||||
{
|
||||
indices[i] = (short)glyphInfos[i].GlyphIndex;
|
||||
}
|
||||
|
||||
run.Indices = indices;
|
||||
|
||||
run.Advances = new float[glyphCount];
|
||||
|
||||
var width = 0.0;
|
||||
|
||||
for (var i = 0; i < glyphCount; i++)
|
||||
{
|
||||
var advance = glyphInfos[i].GlyphAdvance;
|
||||
|
||||
width += advance;
|
||||
|
||||
run.Advances[i] = (float)advance;
|
||||
}
|
||||
|
||||
run.Offsets = new GlyphOffset[glyphCount];
|
||||
|
||||
for (var i = 0; i < glyphCount; i++)
|
||||
{
|
||||
var (x, y) = glyphInfos[i].GlyphOffset;
|
||||
|
||||
run.Offsets[i] = new GlyphOffset
|
||||
{
|
||||
AdvanceOffset = (float)x,
|
||||
AscenderOffset = (float)y
|
||||
};
|
||||
}
|
||||
|
||||
var scale = fontRenderingEmSize / glyphTypeface.Metrics.DesignEmHeight;
|
||||
var height = glyphTypeface.Metrics.LineSpacing * scale;
|
||||
|
||||
return new GlyphRunImpl(run, new Size(width, height), baselineOrigin);
|
||||
return new GlyphRunImpl(glyphTypeface, fontRenderingEmSize, glyphInfos, baselineOrigin, bounds);
|
||||
}
|
||||
|
||||
class D2DApi : IPlatformRenderInterfaceContext
|
||||
|
||||
@@ -74,6 +74,16 @@ namespace Avalonia.Direct2D1.Media
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public RenderOptions RenderOptions
|
||||
{
|
||||
get => _renderOptions;
|
||||
set
|
||||
{
|
||||
_renderOptions = value;
|
||||
ApplyRenderOptions(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Clear(Color color)
|
||||
{
|
||||
@@ -117,15 +127,14 @@ namespace Avalonia.Direct2D1.Media
|
||||
/// <param name="opacity">The opacity to draw with.</param>
|
||||
/// <param name="sourceRect">The rect in the image to draw.</param>
|
||||
/// <param name="destRect">The rect in the output to draw to.</param>
|
||||
/// <param name="bitmapInterpolationMode">The bitmap interpolation mode.</param>
|
||||
public void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode)
|
||||
public void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect)
|
||||
{
|
||||
using (var d2d = ((BitmapImpl)source.Item).GetDirect2DBitmap(_deviceContext))
|
||||
{
|
||||
var interpolationMode = GetInterpolationMode(bitmapInterpolationMode);
|
||||
|
||||
var interpolationMode = GetInterpolationMode(RenderOptions.BitmapInterpolationMode);
|
||||
|
||||
// TODO: How to implement CompositeMode here?
|
||||
|
||||
|
||||
_deviceContext.DrawBitmap(
|
||||
d2d.Value,
|
||||
destRect.ToSharpDX(),
|
||||
@@ -141,13 +150,14 @@ namespace Avalonia.Direct2D1.Media
|
||||
switch (interpolationMode)
|
||||
{
|
||||
case BitmapInterpolationMode.LowQuality:
|
||||
return InterpolationMode.NearestNeighbor;
|
||||
case BitmapInterpolationMode.MediumQuality:
|
||||
return InterpolationMode.Linear;
|
||||
case BitmapInterpolationMode.MediumQuality:
|
||||
return InterpolationMode.MultiSampleLinear;
|
||||
case BitmapInterpolationMode.HighQuality:
|
||||
return InterpolationMode.HighQualityCubic;
|
||||
case BitmapInterpolationMode.Default:
|
||||
return InterpolationMode.Linear;
|
||||
case BitmapInterpolationMode.None:
|
||||
case BitmapInterpolationMode.Unspecified:
|
||||
return InterpolationMode.NearestNeighbor;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(interpolationMode), interpolationMode, null);
|
||||
}
|
||||
@@ -156,15 +166,16 @@ namespace Avalonia.Direct2D1.Media
|
||||
public static CompositeMode GetCompositeMode(BitmapBlendingMode blendingMode)
|
||||
{
|
||||
switch (blendingMode)
|
||||
{
|
||||
{
|
||||
case BitmapBlendingMode.SourceIn:
|
||||
return CompositeMode.SourceIn;
|
||||
case BitmapBlendingMode.SourceOut:
|
||||
return CompositeMode.SourceOut;
|
||||
case BitmapBlendingMode.Unspecified:
|
||||
case BitmapBlendingMode.SourceOver:
|
||||
return CompositeMode.SourceOver;
|
||||
case BitmapBlendingMode.SourceAtop:
|
||||
return CompositeMode.SourceAtop;
|
||||
return CompositeMode.SourceAtop;
|
||||
case BitmapBlendingMode.DestinationIn:
|
||||
return CompositeMode.DestinationIn;
|
||||
case BitmapBlendingMode.DestinationOut:
|
||||
@@ -191,8 +202,10 @@ namespace Avalonia.Direct2D1.Media
|
||||
/// <param name="destRect">The rect in the output to draw to.</param>
|
||||
public void DrawBitmap(IRef<IBitmapImpl> source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect)
|
||||
{
|
||||
var interpolationMode = GetInterpolationMode(RenderOptions.BitmapInterpolationMode);
|
||||
|
||||
using (var d2dSource = ((BitmapImpl)source.Item).GetDirect2DBitmap(_deviceContext))
|
||||
using (var sourceBrush = new BitmapBrush(_deviceContext, d2dSource.Value))
|
||||
using (var sourceBrush = new BitmapBrush1(_deviceContext, d2dSource.Value, new BitmapBrushProperties1 { InterpolationMode = interpolationMode }))
|
||||
using (var d2dOpacityMask = CreateBrush(opacityMask, opacityMaskRect.Size))
|
||||
using (var geometry = new SharpDX.Direct2D1.RectangleGeometry(Direct2D1Platform.Direct2D1Factory, destRect.ToDirect2D()))
|
||||
{
|
||||
@@ -386,9 +399,11 @@ namespace Avalonia.Direct2D1.Media
|
||||
{
|
||||
using (var brush = CreateBrush(foreground, glyphRun.Item.Bounds.Size))
|
||||
{
|
||||
var glyphRunImpl = (GlyphRunImpl)glyphRun.Item;
|
||||
var immutableGlyphRun = (GlyphRunImpl)glyphRun.Item;
|
||||
|
||||
_renderTarget.DrawGlyphRun(glyphRun.Item.BaselineOrigin.ToSharpDX(), glyphRunImpl.GlyphRun,
|
||||
var dxGlyphRun = immutableGlyphRun.GlyphRun;
|
||||
|
||||
_renderTarget.DrawGlyphRun(glyphRun.Item.BaselineOrigin.ToSharpDX(), dxGlyphRun,
|
||||
brush.PlatformBrush, MeasuringMode.Natural);
|
||||
}
|
||||
}
|
||||
@@ -431,6 +446,8 @@ namespace Avalonia.Direct2D1.Media
|
||||
|
||||
readonly Stack<Layer> _layers = new Stack<Layer>();
|
||||
private readonly Stack<Layer> _layerPool = new Stack<Layer>();
|
||||
private RenderOptions _renderOptions;
|
||||
|
||||
/// <summary>
|
||||
/// Pushes an opacity value.
|
||||
/// </summary>
|
||||
@@ -544,7 +561,7 @@ namespace Avalonia.Direct2D1.Media
|
||||
return new ImageBrushImpl(
|
||||
sceneBrushContent.Brush,
|
||||
_deviceContext,
|
||||
new D2DBitmapImpl(intermediate.Bitmap),
|
||||
new D2DBitmapImpl(intermediate.Bitmap.QueryInterface<Bitmap1>()),
|
||||
destinationSize);
|
||||
}
|
||||
|
||||
@@ -608,5 +625,25 @@ namespace Avalonia.Direct2D1.Media
|
||||
}
|
||||
|
||||
public object GetFeature(Type t) => null;
|
||||
|
||||
private void ApplyRenderOptions(RenderOptions renderOptions)
|
||||
{
|
||||
_deviceContext.AntialiasMode = renderOptions.EdgeMode != EdgeMode.Aliased ? AntialiasMode.PerPrimitive : AntialiasMode.Aliased;
|
||||
switch (renderOptions.TextRenderingMode)
|
||||
{
|
||||
case TextRenderingMode.Unspecified:
|
||||
_deviceContext.TextAntialiasMode = renderOptions.EdgeMode != EdgeMode.Aliased ? TextAntialiasMode.Default : TextAntialiasMode.Aliased;
|
||||
break;
|
||||
case TextRenderingMode.Alias:
|
||||
_deviceContext.TextAntialiasMode = TextAntialiasMode.Aliased;
|
||||
break;
|
||||
case TextRenderingMode.Antialias:
|
||||
_deviceContext.TextAntialiasMode = TextAntialiasMode.Grayscale;
|
||||
break;
|
||||
case TextRenderingMode.SubpixelAntialias:
|
||||
_deviceContext.TextAntialiasMode = TextAntialiasMode.Cleartype;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 Rect Bounds{ get; }
|
||||
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 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@ namespace Avalonia.Direct2D1.Media
|
||||
{
|
||||
internal sealed class ImageBrushImpl : BrushImpl
|
||||
{
|
||||
private readonly OptionalDispose<Bitmap> _bitmap;
|
||||
|
||||
private readonly Avalonia.Media.Imaging.BitmapInterpolationMode _bitmapInterpolationMode;
|
||||
private readonly OptionalDispose<Bitmap1> _bitmap;
|
||||
|
||||
public ImageBrushImpl(
|
||||
ITileBrush brush,
|
||||
@@ -40,8 +38,6 @@ namespace Avalonia.Direct2D1.Media
|
||||
GetBrushProperties(brush, calc.DestinationRect));
|
||||
}
|
||||
}
|
||||
|
||||
_bitmapInterpolationMode = brush.BitmapInterpolationMode;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
@@ -103,8 +99,7 @@ namespace Avalonia.Direct2D1.Media
|
||||
context.Clear(Colors.Transparent);
|
||||
context.PushClip(calc.IntermediateClip);
|
||||
context.Transform = calc.IntermediateTransform;
|
||||
|
||||
context.DrawBitmap(RefCountable.CreateUnownedNotClonable(bitmap), 1, rect, rect, _bitmapInterpolationMode);
|
||||
context.DrawBitmap(RefCountable.CreateUnownedNotClonable(bitmap), 1, rect, rect);
|
||||
context.PopClip();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Avalonia.Platform;
|
||||
using D2DBitmap = SharpDX.Direct2D1.Bitmap;
|
||||
using D2DBitmap = SharpDX.Direct2D1.Bitmap1;
|
||||
|
||||
namespace Avalonia.Direct2D1.Media
|
||||
{
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Avalonia.Metadata;
|
||||
using SharpDX.Direct2D1;
|
||||
using SharpDX.WIC;
|
||||
using Bitmap = SharpDX.Direct2D1.Bitmap;
|
||||
|
||||
namespace Avalonia.Direct2D1.Media
|
||||
{
|
||||
@@ -10,7 +11,7 @@ namespace Avalonia.Direct2D1.Media
|
||||
/// </summary>
|
||||
internal class D2DBitmapImpl : BitmapImpl
|
||||
{
|
||||
private readonly Bitmap _direct2DBitmap;
|
||||
private readonly Bitmap1 _direct2DBitmap;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the <see cref="BitmapImpl"/> class
|
||||
@@ -22,7 +23,7 @@ namespace Avalonia.Direct2D1.Media
|
||||
/// or if the render target is a <see cref="SharpDX.Direct2D1.DeviceContext"/>,
|
||||
/// the device associated with this context, to be renderable.
|
||||
/// </remarks>
|
||||
public D2DBitmapImpl(Bitmap d2DBitmap)
|
||||
public D2DBitmapImpl(Bitmap1 d2DBitmap)
|
||||
{
|
||||
_direct2DBitmap = d2DBitmap ?? throw new ArgumentNullException(nameof(d2DBitmap));
|
||||
}
|
||||
@@ -36,9 +37,9 @@ namespace Avalonia.Direct2D1.Media
|
||||
_direct2DBitmap.Dispose();
|
||||
}
|
||||
|
||||
public override OptionalDispose<Bitmap> GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget target)
|
||||
public override OptionalDispose<Bitmap1> GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget target)
|
||||
{
|
||||
return new OptionalDispose<Bitmap>(_direct2DBitmap, false);
|
||||
return new OptionalDispose<Bitmap1>(_direct2DBitmap, false);
|
||||
}
|
||||
|
||||
public override void Save(Stream stream, int? quality = null)
|
||||
|
||||
@@ -5,7 +5,7 @@ using Avalonia.Rendering;
|
||||
using Avalonia.Utilities;
|
||||
using SharpDX;
|
||||
using SharpDX.Direct2D1;
|
||||
using D2DBitmap = SharpDX.Direct2D1.Bitmap;
|
||||
using D2DBitmap = SharpDX.Direct2D1.Bitmap1;
|
||||
|
||||
namespace Avalonia.Direct2D1.Media.Imaging
|
||||
{
|
||||
@@ -14,7 +14,7 @@ namespace Avalonia.Direct2D1.Media.Imaging
|
||||
private readonly BitmapRenderTarget _renderTarget;
|
||||
|
||||
public D2DRenderTargetBitmapImpl(BitmapRenderTarget renderTarget)
|
||||
: base(renderTarget.Bitmap)
|
||||
: base(renderTarget.Bitmap.QueryInterface<Bitmap1>())
|
||||
{
|
||||
_renderTarget = renderTarget;
|
||||
}
|
||||
@@ -53,7 +53,7 @@ namespace Avalonia.Direct2D1.Media.Imaging
|
||||
|
||||
public override OptionalDispose<D2DBitmap> GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget target)
|
||||
{
|
||||
return new OptionalDispose<D2DBitmap>(_renderTarget.Bitmap, false);
|
||||
return new OptionalDispose<D2DBitmap>(_renderTarget.Bitmap.QueryInterface<Bitmap1>(), false);
|
||||
}
|
||||
|
||||
public override void Save(Stream stream, int? quality = null)
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Avalonia.Direct2D1.Media.Imaging;
|
||||
using Avalonia.Win32.Interop;
|
||||
using SharpDX.WIC;
|
||||
using APixelFormat = Avalonia.Platform.PixelFormat;
|
||||
using AlphaFormat = Avalonia.Platform.AlphaFormat;
|
||||
using D2DBitmap = SharpDX.Direct2D1.Bitmap;
|
||||
using D2DBitmap = SharpDX.Direct2D1.Bitmap1;
|
||||
using Avalonia.Platform;
|
||||
using PixelFormat = SharpDX.WIC.PixelFormat;
|
||||
|
||||
@@ -22,7 +21,7 @@ namespace Avalonia.Direct2D1.Media
|
||||
{
|
||||
switch (interpolationMode)
|
||||
{
|
||||
case Avalonia.Media.Imaging.BitmapInterpolationMode.Default:
|
||||
case Avalonia.Media.Imaging.BitmapInterpolationMode.Unspecified:
|
||||
return BitmapInterpolationMode.Fant;
|
||||
|
||||
case Avalonia.Media.Imaging.BitmapInterpolationMode.LowQuality:
|
||||
@@ -184,7 +183,10 @@ namespace Avalonia.Direct2D1.Media
|
||||
{
|
||||
using var converter = new FormatConverter(Direct2D1Platform.ImagingFactory);
|
||||
converter.Initialize(WicImpl, SharpDX.WIC.PixelFormat.Format32bppPBGRA);
|
||||
return new OptionalDispose<D2DBitmap>(D2DBitmap.FromWicBitmap(renderTarget, converter), true);
|
||||
|
||||
var d2dBitmap = D2DBitmap.FromWicBitmap(renderTarget, converter).QueryInterface<D2DBitmap>();
|
||||
|
||||
return new OptionalDispose<D2DBitmap>(d2dBitmap, true);
|
||||
}
|
||||
|
||||
public override void Save(Stream stream, int? quality = null)
|
||||
|
||||
@@ -51,8 +51,7 @@ namespace Avalonia.Base.UnitTests.Rendering.SceneGraph
|
||||
bitmap,
|
||||
1,
|
||||
new Rect(1, 1, 1, 1),
|
||||
new Rect(1, 1, 1, 1),
|
||||
BitmapInterpolationMode.Default);
|
||||
new Rect(1, 1, 1, 1));
|
||||
|
||||
Assert.Equal(2, bitmap.RefCount);
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace Avalonia.Base.UnitTests.VisualTree
|
||||
}
|
||||
|
||||
public IGlyphRunImpl CreateGlyphRun(IGlyphTypeface glyphTypeface, double fontRenderingEmSize,
|
||||
IReadOnlyList<GlyphInfo> glyphInfos, Point baselineOrigin)
|
||||
IReadOnlyList<GlyphInfo> glyphInfos, Point baselineOrigin, Rect bounds)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -15,12 +15,13 @@ namespace Avalonia.Benchmarks
|
||||
|
||||
public Matrix Transform { get; set; }
|
||||
|
||||
public RenderOptions RenderOptions { get; set; }
|
||||
|
||||
public void Clear(Color color)
|
||||
{
|
||||
}
|
||||
|
||||
public void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect,
|
||||
BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default)
|
||||
public void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,9 +124,9 @@ namespace Avalonia.Benchmarks
|
||||
}
|
||||
|
||||
public IGlyphRunImpl CreateGlyphRun(IGlyphTypeface glyphTypeface, double fontRenderingEmSize,
|
||||
IReadOnlyList<GlyphInfo> glyphInfos, Point baselineOrigin)
|
||||
IReadOnlyList<GlyphInfo> glyphInfos, Point baselineOrigin, Rect bounds)
|
||||
{
|
||||
return new MockGlyphRun(glyphInfos);
|
||||
return new MockGlyphRun(glyphTypeface, fontRenderingEmSize, baselineOrigin, bounds);
|
||||
}
|
||||
|
||||
public IPlatformRenderInterfaceContext CreateBackendContext(IPlatformGraphicsContext graphicsContext)
|
||||
|
||||
@@ -111,6 +111,29 @@ namespace Avalonia.Direct2D1.RenderTests.Media
|
||||
CompareImages();
|
||||
}
|
||||
|
||||
[Win32Fact("For consistent results")]
|
||||
public async Task Should_Render_GlyphRun_Aliased()
|
||||
{
|
||||
var control = new PositionedGlyphRunControl
|
||||
{
|
||||
[TextElement.ForegroundProperty] = new SolidColorBrush { Color = Colors.Black }
|
||||
};
|
||||
|
||||
RenderOptions.SetTextRenderingMode(control, TextRenderingMode.Alias);
|
||||
|
||||
Decorator target = new Decorator
|
||||
{
|
||||
Padding = new Thickness(8),
|
||||
Width = 190,
|
||||
Height = 120,
|
||||
Child = control
|
||||
};
|
||||
|
||||
await RenderToFile(target);
|
||||
|
||||
CompareImages();
|
||||
}
|
||||
|
||||
public class GlyphRunGeometryControl : Control
|
||||
{
|
||||
public GlyphRunGeometryControl()
|
||||
|
||||
@@ -35,5 +35,49 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
|
||||
await RenderToFile(target);
|
||||
CompareImages();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Should_Render_Circle_Aliased()
|
||||
{
|
||||
var target = new Border
|
||||
{
|
||||
Background = Brushes.White,
|
||||
Padding = new Thickness(8),
|
||||
Width = 200,
|
||||
Height = 200,
|
||||
Child = new Ellipse
|
||||
{
|
||||
Stroke = Brushes.Black,
|
||||
StrokeThickness = 3.5,
|
||||
}
|
||||
};
|
||||
|
||||
RenderOptions.SetEdgeMode(target, EdgeMode.Aliased);
|
||||
|
||||
await RenderToFile(target);
|
||||
CompareImages();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Should_Render_Circle_Antialiased()
|
||||
{
|
||||
var target = new Border
|
||||
{
|
||||
Background = Brushes.White,
|
||||
Padding = new Thickness(8),
|
||||
Width = 200,
|
||||
Height = 200,
|
||||
Child = new Ellipse
|
||||
{
|
||||
Stroke = Brushes.Black,
|
||||
StrokeThickness = 3.5,
|
||||
}
|
||||
};
|
||||
|
||||
RenderOptions.SetEdgeMode(target, EdgeMode.Antialias);
|
||||
|
||||
await RenderToFile(target);
|
||||
CompareImages();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
for (var i = 0; i < glyphInfos.Count; ++i)
|
||||
{
|
||||
width += glyphInfos[i].GlyphAdvance;
|
||||
}
|
||||
|
||||
Bounds = new Rect(new Size(width, 10));
|
||||
GlyphTypeface = glyphTypeface;
|
||||
FontRenderingEmSize = fontRenderingEmSize;
|
||||
BaselineOrigin = baselineOrigin;
|
||||
Bounds =bounds;
|
||||
}
|
||||
|
||||
public IGlyphTypeface GlyphTypeface { get; }
|
||||
|
||||
public double FontRenderingEmSize { get; }
|
||||
|
||||
public Point BaselineOrigin { get; }
|
||||
|
||||
public Rect Bounds { get; }
|
||||
|
||||
public Point BaselineOrigin => new Point(0, 8);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public IReadOnlyList<float> GetIntersections(float lowerBound, float upperBound)
|
||||
public IReadOnlyList<float> GetIntersections(float lowerLimit, float upperLimit)
|
||||
=> Array.Empty<float>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ using Avalonia.Media;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Media.TextFormatting;
|
||||
using Avalonia.Rendering;
|
||||
using Moq;
|
||||
|
||||
namespace Avalonia.UnitTests
|
||||
@@ -149,10 +148,9 @@ namespace Avalonia.UnitTests
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IGlyphRunImpl CreateGlyphRun(IGlyphTypeface glyphTypeface, double fontRenderingEmSize,
|
||||
IReadOnlyList<GlyphInfo> glyphInfos, Point baselineOrigin)
|
||||
public IGlyphRunImpl CreateGlyphRun(IGlyphTypeface glyphTypeface, double fontRenderingEmSize, IReadOnlyList<GlyphInfo> glyphInfos, Point baselineOrigin, Rect bounds)
|
||||
{
|
||||
return new MockGlyphRun(glyphInfos);
|
||||
return new MockGlyphRun(glyphTypeface, fontRenderingEmSize, baselineOrigin, bounds);
|
||||
}
|
||||
|
||||
public IPlatformRenderInterfaceContext CreateBackendContext(IPlatformGraphicsContext graphicsContext) => this;
|
||||
@@ -162,21 +160,6 @@ namespace Avalonia.UnitTests
|
||||
return Mock.Of<IGeometryImpl>();
|
||||
}
|
||||
|
||||
public IGlyphRunBuffer AllocateGlyphRun(IGlyphTypeface glyphTypeface, float fontRenderingEmSize, int length)
|
||||
{
|
||||
return Mock.Of<IGlyphRunBuffer>();
|
||||
}
|
||||
|
||||
public IHorizontalGlyphRunBuffer AllocateHorizontalGlyphRun(IGlyphTypeface glyphTypeface, float fontRenderingEmSize, int length)
|
||||
{
|
||||
return Mock.Of<IHorizontalGlyphRunBuffer>();
|
||||
}
|
||||
|
||||
public IPositionedGlyphRunBuffer AllocatePositionedGlyphRun(IGlyphTypeface glyphTypeface, float fontRenderingEmSize, int length)
|
||||
{
|
||||
return Mock.Of<IPositionedGlyphRunBuffer>();
|
||||
}
|
||||
|
||||
public bool SupportsIndividualRoundRects { get; set; }
|
||||
|
||||
public AlphaFormat DefaultAlphaFormat => AlphaFormat.Premul;
|
||||
|
||||
|
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 |