Browse Source

Simply ShapedBuffer GlyphInfos access

pull/10463/head
Benedikt Stebner 4 years ago
parent
commit
edbfd96b2d
  1. 11
      Avalonia.sln
  2. 6
      src/Avalonia.Base/Media/TextFormatting/InterWordJustification.cs
  3. 98
      src/Avalonia.Base/Media/TextFormatting/ShapedBuffer.cs
  4. 6
      src/Avalonia.Base/Media/TextFormatting/ShapedTextRun.cs
  5. 2
      src/Avalonia.Base/Media/TextFormatting/TextFormatterImpl.cs
  6. 4
      src/Skia/Avalonia.Skia/TextShaperImpl.cs
  7. 4
      src/Windows/Avalonia.Direct2D1/Media/TextShaperImpl.cs
  8. 4
      tests/Avalonia.Skia.UnitTests/Media/GlyphRunTests.cs
  9. 18
      tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs
  10. 14
      tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs
  11. 10
      tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextShaperTests.cs
  12. 4
      tests/Avalonia.UnitTests/HarfBuzzTextShaperImpl.cs
  13. 3
      tests/Avalonia.UnitTests/MockTextShaperImpl.cs

11
Avalonia.sln

@ -555,9 +555,14 @@ Global
{75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Debug|Any CPU.Build.0 = Debug|Any CPU {75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Release|Any CPU.ActiveCfg = Release|Any CPU {75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Release|Any CPU.Build.0 = Release|Any CPU {75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Release|Any CPU.Build.0 = Release|Any CPU
{C810060E-3809-4B74-A125-F11533AF9C1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C810060E-3809-4B74-A125-F11533AF9C1B}.Debug|Any CPU.Build.0 = Debug|Any CPU {C810060E-3809-4B74-A125-F11533AF9C1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C810060E-3809-4B74-A125-F11533AF9C1B}.Release|Any CPU.ActiveCfg = Release|Any CPU {C810060E-3809-4B74-A125-F11533AF9C1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C810060E-3809-4B74-A125-F11533AF9C1B}.Release|Any CPU.Build.0 = Release|Any CPU {C810060E-3809-4B74-A125-F11533AF9C1B}.Release|Any CPU.Build.0 = Release|Any CPU
{C692FE73-43DB-49CE-87FC-F03ED61F25C9}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{C692FE73-43DB-49CE-87FC-F03ED61F25C9}.Debug|Any CPU.Build.0 = Release|Any CPU
{C692FE73-43DB-49CE-87FC-F03ED61F25C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C692FE73-43DB-49CE-87FC-F03ED61F25C9}.Release|Any CPU.Build.0 = Release|Any CPU
{EE0F0DD4-A70D-472B-BD5D-B7D32D0E9386}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EE0F0DD4-A70D-472B-BD5D-B7D32D0E9386}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EE0F0DD4-A70D-472B-BD5D-B7D32D0E9386}.Debug|Any CPU.Build.0 = Debug|Any CPU {EE0F0DD4-A70D-472B-BD5D-B7D32D0E9386}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EE0F0DD4-A70D-472B-BD5D-B7D32D0E9386}.Release|Any CPU.ActiveCfg = Release|Any CPU {EE0F0DD4-A70D-472B-BD5D-B7D32D0E9386}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -566,10 +571,6 @@ Global
{F4E36AA8-814E-4704-BC07-291F70F45193}.Debug|Any CPU.Build.0 = Debug|Any CPU {F4E36AA8-814E-4704-BC07-291F70F45193}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F4E36AA8-814E-4704-BC07-291F70F45193}.Release|Any CPU.ActiveCfg = Release|Any CPU {F4E36AA8-814E-4704-BC07-291F70F45193}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F4E36AA8-814E-4704-BC07-291F70F45193}.Release|Any CPU.Build.0 = Release|Any CPU {F4E36AA8-814E-4704-BC07-291F70F45193}.Release|Any CPU.Build.0 = Release|Any CPU
{C692FE73-43DB-49CE-87FC-F03ED61F25C9}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{C692FE73-43DB-49CE-87FC-F03ED61F25C9}.Debug|Any CPU.Build.0 = Release|Any CPU
{C692FE73-43DB-49CE-87FC-F03ED61F25C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C692FE73-43DB-49CE-87FC-F03ED61F25C9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -635,8 +636,8 @@ Global
{90B08091-9BBD-4362-B712-E9F2CC62B218} = {9B9E3891-2366-4253-A952-D08BCEB71098} {90B08091-9BBD-4362-B712-E9F2CC62B218} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{75C47156-C5D8-44BC-A5A7-E8657C2248D6} = {9B9E3891-2366-4253-A952-D08BCEB71098} {75C47156-C5D8-44BC-A5A7-E8657C2248D6} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{C810060E-3809-4B74-A125-F11533AF9C1B} = {9B9E3891-2366-4253-A952-D08BCEB71098} {C810060E-3809-4B74-A125-F11533AF9C1B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{F4E36AA8-814E-4704-BC07-291F70F45193} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{C692FE73-43DB-49CE-87FC-F03ED61F25C9} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637} {C692FE73-43DB-49CE-87FC-F03ED61F25C9} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{F4E36AA8-814E-4704-BC07-291F70F45193} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A} SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}

6
src/Avalonia.Base/Media/TextFormatting/InterWordJustification.cs

@ -89,13 +89,13 @@ namespace Avalonia.Media.TextFormatting
var offset = Math.Max(0, currentPosition - glyphRun.Metrics.FirstCluster); var offset = Math.Max(0, currentPosition - glyphRun.Metrics.FirstCluster);
var glyphIndex = glyphRun.FindGlyphIndex(characterIndex - offset); var glyphIndex = glyphRun.FindGlyphIndex(characterIndex - offset);
var glyphInfo = shapedBuffer.GlyphInfos[glyphIndex]; var glyphInfo = shapedBuffer[glyphIndex];
shapedBuffer.GlyphInfos[glyphIndex] = new GlyphInfo(glyphInfo.GlyphIndex, shapedBuffer[glyphIndex] = new GlyphInfo(glyphInfo.GlyphIndex,
glyphInfo.GlyphCluster, glyphInfo.GlyphAdvance + spacing); glyphInfo.GlyphCluster, glyphInfo.GlyphAdvance + spacing);
} }
glyphRun.GlyphInfos = shapedBuffer.GlyphInfos; glyphRun.GlyphInfos = shapedBuffer;
} }
currentPosition += textRun.Length; currentPosition += textRun.Length;

98
src/Avalonia.Base/Media/TextFormatting/ShapedBuffer.cs

@ -2,6 +2,7 @@
using System.Buffers; using System.Buffers;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Avalonia.Utilities; using Avalonia.Utilities;
namespace Avalonia.Media.TextFormatting namespace Avalonia.Media.TextFormatting
@ -9,12 +10,13 @@ namespace Avalonia.Media.TextFormatting
public sealed class ShapedBuffer : IReadOnlyList<GlyphInfo>, IDisposable public sealed class ShapedBuffer : IReadOnlyList<GlyphInfo>, IDisposable
{ {
private GlyphInfo[]? _rentedBuffer; private GlyphInfo[]? _rentedBuffer;
private ArraySlice<GlyphInfo> _glyphInfos;
public ShapedBuffer(ReadOnlyMemory<char> text, int bufferLength, IGlyphTypeface glyphTypeface, double fontRenderingEmSize, sbyte bidiLevel) public ShapedBuffer(ReadOnlyMemory<char> text, int bufferLength, IGlyphTypeface glyphTypeface, double fontRenderingEmSize, sbyte bidiLevel)
{ {
_rentedBuffer = ArrayPool<GlyphInfo>.Shared.Rent(bufferLength);
Text = text; Text = text;
GlyphInfos = new ArraySlice<GlyphInfo>(_rentedBuffer, 0, bufferLength); _rentedBuffer = ArrayPool<GlyphInfo>.Shared.Rent(bufferLength);
_glyphInfos = new ArraySlice<GlyphInfo>(_rentedBuffer, 0, bufferLength);
GlyphTypeface = glyphTypeface; GlyphTypeface = glyphTypeface;
FontRenderingEmSize = fontRenderingEmSize; FontRenderingEmSize = fontRenderingEmSize;
BidiLevel = bidiLevel; BidiLevel = bidiLevel;
@ -23,27 +25,70 @@ namespace Avalonia.Media.TextFormatting
internal ShapedBuffer(ReadOnlyMemory<char> text, ArraySlice<GlyphInfo> glyphInfos, IGlyphTypeface glyphTypeface, double fontRenderingEmSize, sbyte bidiLevel) internal ShapedBuffer(ReadOnlyMemory<char> text, ArraySlice<GlyphInfo> glyphInfos, IGlyphTypeface glyphTypeface, double fontRenderingEmSize, sbyte bidiLevel)
{ {
Text = text; Text = text;
GlyphInfos = glyphInfos; _glyphInfos = glyphInfos;
GlyphTypeface = glyphTypeface; GlyphTypeface = glyphTypeface;
FontRenderingEmSize = fontRenderingEmSize; FontRenderingEmSize = fontRenderingEmSize;
BidiLevel = bidiLevel; BidiLevel = bidiLevel;
} }
internal ArraySlice<GlyphInfo> GlyphInfos { get; private set; } /// <summary>
/// The buffer's length.
public int Length /// </summary>
=> GlyphInfos.Length; public int Length => _glyphInfos.Length;
/// <summary>
/// The buffer's glyph typeface.
/// </summary>
public IGlyphTypeface GlyphTypeface { get; } public IGlyphTypeface GlyphTypeface { get; }
/// <summary>
/// The buffers font rendering em size.
/// </summary>
public double FontRenderingEmSize { get; } public double FontRenderingEmSize { get; }
/// <summary>
/// The buffer's bidi level.
/// </summary>
public sbyte BidiLevel { get; } public sbyte BidiLevel { get; }
/// <summary>
/// The buffer's reading direction.
/// </summary>
public bool IsLeftToRight => (BidiLevel & 1) == 0; public bool IsLeftToRight => (BidiLevel & 1) == 0;
/// <summary>
/// The text that is represended by this buffer.
/// </summary>
public ReadOnlyMemory<char> Text { get; } public ReadOnlyMemory<char> Text { get; }
/// <summary>
/// Reverses the buffer.
/// </summary>
public void Reverse()
{
_glyphInfos.Span.Reverse();
}
public void Dispose()
{
if (_rentedBuffer is not null)
{
ArrayPool<GlyphInfo>.Shared.Return(_rentedBuffer);
_rentedBuffer = null;
_glyphInfos = ArraySlice<GlyphInfo>.Empty; // ensure we don't misuse the returned array
}
}
public GlyphInfo this[int index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _glyphInfos[index];
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _glyphInfos[index] = value;
}
public IEnumerator<GlyphInfo> GetEnumerator() => _glyphInfos.GetEnumerator();
/// <summary> /// <summary>
/// Finds a glyph index for given character index. /// Finds a glyph index for given character index.
/// </summary> /// </summary>
@ -53,20 +98,19 @@ namespace Avalonia.Media.TextFormatting
/// </returns> /// </returns>
private int FindGlyphIndex(int characterIndex) private int FindGlyphIndex(int characterIndex)
{ {
if (characterIndex < GlyphInfos[0].GlyphCluster) if (characterIndex < _glyphInfos[0].GlyphCluster)
{ {
return 0; return 0;
} }
if (characterIndex > GlyphInfos[GlyphInfos.Length - 1].GlyphCluster) if (characterIndex > _glyphInfos[_glyphInfos.Length - 1].GlyphCluster)
{ {
return GlyphInfos.Length - 1; return _glyphInfos.Length - 1;
} }
var comparer = GlyphInfo.ClusterAscendingComparer; var comparer = GlyphInfo.ClusterAscendingComparer;
var glyphInfos = GlyphInfos.Span; var glyphInfos = _glyphInfos.Span;
var searchValue = new GlyphInfo(default, characterIndex, default); var searchValue = new GlyphInfo(default, characterIndex, default);
@ -109,42 +153,24 @@ namespace Avalonia.Media.TextFormatting
return new SplitResult<ShapedBuffer>(this, null); return new SplitResult<ShapedBuffer>(this, null);
} }
var firstCluster = GlyphInfos[0].GlyphCluster; var firstCluster = _glyphInfos[0].GlyphCluster;
var lastCluster = GlyphInfos[GlyphInfos.Length - 1].GlyphCluster; var lastCluster = _glyphInfos[_glyphInfos.Length - 1].GlyphCluster;
var start = firstCluster < lastCluster ? firstCluster : lastCluster; var start = firstCluster < lastCluster ? firstCluster : lastCluster;
var glyphCount = FindGlyphIndex(start + length); var glyphCount = FindGlyphIndex(start + length);
var first = new ShapedBuffer(Text.Slice(0, length), var first = new ShapedBuffer(Text.Slice(0, length),
GlyphInfos.Take(glyphCount), GlyphTypeface, FontRenderingEmSize, BidiLevel); _glyphInfos.Take(glyphCount), GlyphTypeface, FontRenderingEmSize, BidiLevel);
var second = new ShapedBuffer(Text.Slice(length), var second = new ShapedBuffer(Text.Slice(length),
GlyphInfos.Skip(glyphCount), GlyphTypeface, FontRenderingEmSize, BidiLevel); _glyphInfos.Skip(glyphCount), GlyphTypeface, FontRenderingEmSize, BidiLevel);
return new SplitResult<ShapedBuffer>(first, second); return new SplitResult<ShapedBuffer>(first, second);
} }
int IReadOnlyCollection<GlyphInfo>.Count => GlyphInfos.Length; int IReadOnlyCollection<GlyphInfo>.Count => _glyphInfos.Length;
public GlyphInfo this[int index]
{
get => GlyphInfos[index];
set => GlyphInfos[index] = value;
}
public IEnumerator<GlyphInfo> GetEnumerator() => GlyphInfos.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public void Dispose()
{
if (_rentedBuffer is not null)
{
ArrayPool<GlyphInfo>.Shared.Return(_rentedBuffer);
_rentedBuffer = null;
GlyphInfos = ArraySlice<GlyphInfo>.Empty; // ensure we don't misuse the returned array
}
}
} }
} }

6
src/Avalonia.Base/Media/TextFormatting/ShapedTextRun.cs

@ -85,7 +85,7 @@ namespace Avalonia.Media.TextFormatting
{ {
_glyphRun = null; _glyphRun = null;
ShapedBuffer.GlyphInfos.Span.Reverse(); ShapedBuffer.Reverse();
IsReversed = !IsReversed; IsReversed = !IsReversed;
} }
@ -106,7 +106,7 @@ namespace Avalonia.Media.TextFormatting
for (var i = 0; i < ShapedBuffer.Length; i++) for (var i = 0; i < ShapedBuffer.Length; i++)
{ {
var advance = ShapedBuffer.GlyphInfos[i].GlyphAdvance; var advance = ShapedBuffer[i].GlyphAdvance;
if (currentWidth + advance > availableWidth) if (currentWidth + advance > availableWidth)
{ {
@ -130,7 +130,7 @@ namespace Avalonia.Media.TextFormatting
for (var i = ShapedBuffer.Length - 1; i >= 0; i--) for (var i = ShapedBuffer.Length - 1; i >= 0; i--)
{ {
var advance = ShapedBuffer.GlyphInfos[i].GlyphAdvance; var advance = ShapedBuffer[i].GlyphAdvance;
if (width + advance > availableWidth) if (width + advance > availableWidth)
{ {

2
src/Avalonia.Base/Media/TextFormatting/TextFormatterImpl.cs

@ -583,7 +583,7 @@ namespace Avalonia.Media.TextFormatting
{ {
if (shapedTextCharacters.ShapedBuffer.Length > 0) if (shapedTextCharacters.ShapedBuffer.Length > 0)
{ {
var firstCluster = shapedTextCharacters.ShapedBuffer.GlyphInfos[0].GlyphCluster; var firstCluster = shapedTextCharacters.ShapedBuffer[0].GlyphCluster;
var lastCluster = firstCluster; var lastCluster = firstCluster;
for (var j = 0; j < shapedTextCharacters.ShapedBuffer.Length; j++) for (var j = 0; j < shapedTextCharacters.ShapedBuffer.Length; j++)

4
src/Skia/Avalonia.Skia/TextShaperImpl.cs

@ -56,8 +56,6 @@ namespace Avalonia.Skia
var shapedBuffer = new ShapedBuffer(text, bufferLength, typeface, fontRenderingEmSize, bidiLevel); var shapedBuffer = new ShapedBuffer(text, bufferLength, typeface, fontRenderingEmSize, bidiLevel);
var targetInfos = shapedBuffer.GlyphInfos;
var glyphInfos = buffer.GetGlyphInfoSpan(); var glyphInfos = buffer.GetGlyphInfoSpan();
var glyphPositions = buffer.GetGlyphPositionSpan(); var glyphPositions = buffer.GetGlyphPositionSpan();
@ -83,7 +81,7 @@ namespace Avalonia.Skia
4 * typeface.GetGlyphAdvance(glyphIndex) * textScale; 4 * typeface.GetGlyphAdvance(glyphIndex) * textScale;
} }
targetInfos[i] = new Media.TextFormatting.GlyphInfo(glyphIndex, glyphCluster, glyphAdvance, glyphOffset); shapedBuffer[i] = new Media.TextFormatting.GlyphInfo(glyphIndex, glyphCluster, glyphAdvance, glyphOffset);
} }
return shapedBuffer; return shapedBuffer;

4
src/Windows/Avalonia.Direct2D1/Media/TextShaperImpl.cs

@ -52,8 +52,6 @@ namespace Avalonia.Direct2D1.Media
var shapedBuffer = new ShapedBuffer(text, bufferLength, typeface, fontRenderingEmSize, bidiLevel); var shapedBuffer = new ShapedBuffer(text, bufferLength, typeface, fontRenderingEmSize, bidiLevel);
var targetInfos = shapedBuffer.GlyphInfos;
var glyphInfos = buffer.GetGlyphInfoSpan(); var glyphInfos = buffer.GetGlyphInfoSpan();
var glyphPositions = buffer.GetGlyphPositionSpan(); var glyphPositions = buffer.GetGlyphPositionSpan();
@ -79,7 +77,7 @@ namespace Avalonia.Direct2D1.Media
4 * typeface.GetGlyphAdvance(glyphIndex) * textScale; 4 * typeface.GetGlyphAdvance(glyphIndex) * textScale;
} }
targetInfos[i] = new Avalonia.Media.TextFormatting.GlyphInfo(glyphIndex, glyphCluster, glyphAdvance, glyphOffset); shapedBuffer[i] = new Avalonia.Media.TextFormatting.GlyphInfo(glyphIndex, glyphCluster, glyphAdvance, glyphOffset);
} }
return shapedBuffer; return shapedBuffer;

4
tests/Avalonia.Skia.UnitTests/Media/GlyphRunTests.cs

@ -216,12 +216,12 @@ namespace Avalonia.Skia.UnitTests.Media
shapedBuffer.GlyphTypeface, shapedBuffer.GlyphTypeface,
shapedBuffer.FontRenderingEmSize, shapedBuffer.FontRenderingEmSize,
shapedBuffer.Text, shapedBuffer.Text,
shapedBuffer.GlyphInfos, shapedBuffer,
biDiLevel: shapedBuffer.BidiLevel); biDiLevel: shapedBuffer.BidiLevel);
if(shapedBuffer.BidiLevel == 1) if(shapedBuffer.BidiLevel == 1)
{ {
shapedBuffer.GlyphInfos.Span.Reverse(); shapedBuffer.Reverse();
} }
return glyphRun; return glyphRun;

18
tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLayoutTests.cs

@ -199,7 +199,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
=> textLayout.TextLines => textLayout.TextLines
.Select(line => string.Join('|', line.TextRuns .Select(line => string.Join('|', line.TextRuns
.Cast<ShapedTextRun>() .Cast<ShapedTextRun>()
.SelectMany(run => run.ShapedBuffer.GlyphInfos, (_, glyph) => glyph.GlyphIndex))) .SelectMany(run => run.ShapedBuffer, (_, glyph) => glyph.GlyphIndex)))
.ToList(); .ToList();
} }
@ -489,7 +489,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
{ {
var shapedRun = (ShapedTextRun)textRun; var shapedRun = (ShapedTextRun)textRun;
var glyphClusters = shapedRun.ShapedBuffer.GlyphInfos.Select(glyph => glyph.GlyphCluster).ToArray(); var glyphClusters = shapedRun.ShapedBuffer.Select(glyph => glyph.GlyphCluster).ToArray();
var expected = clusters.Skip(index).Take(glyphClusters.Length).ToArray(); var expected = clusters.Skip(index).Take(glyphClusters.Length).ToArray();
@ -522,11 +522,11 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
Assert.Equal(expectedLength, ((ShapedTextRun)layout.TextLines[0].TextRuns[0]).GlyphRun.GlyphInfos.Count); Assert.Equal(expectedLength, ((ShapedTextRun)layout.TextLines[0].TextRuns[0]).GlyphRun.GlyphInfos.Count);
Assert.Equal(5, ((ShapedTextRun)layout.TextLines[0].TextRuns[0]).ShapedBuffer.GlyphInfos[5].GlyphCluster); Assert.Equal(5, ((ShapedTextRun)layout.TextLines[0].TextRuns[0]).ShapedBuffer[5].GlyphCluster);
if (expectedLength == 7) if (expectedLength == 7)
{ {
Assert.Equal(5, ((ShapedTextRun)layout.TextLines[0].TextRuns[0]).ShapedBuffer.GlyphInfos[6].GlyphCluster); Assert.Equal(5, ((ShapedTextRun)layout.TextLines[0].TextRuns[0]).ShapedBuffer[6].GlyphCluster);
} }
} }
} }
@ -783,7 +783,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var rects = layout.TextLines var rects = layout.TextLines
.SelectMany(x => x.TextRuns.Cast<ShapedTextRun>()) .SelectMany(x => x.TextRuns.Cast<ShapedTextRun>())
.SelectMany(x => x.ShapedBuffer.GlyphInfos, (_, glyph) => glyph.GlyphAdvance) .SelectMany(x => x.ShapedBuffer, (_, glyph) => glyph.GlyphAdvance)
.ToArray(); .ToArray();
for (var i = 0; i < SingleLineText.Length; i++) for (var i = 0; i < SingleLineText.Length; i++)
@ -939,7 +939,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var firstRun = (ShapedTextRun)textLine.TextRuns[0]; var firstRun = (ShapedTextRun)textLine.TextRuns[0];
var firstCluster = firstRun.ShapedBuffer.GlyphInfos[0].GlyphCluster; var firstCluster = firstRun.ShapedBuffer[0].GlyphCluster;
var characterHit = textLine.GetCharacterHitFromDistance(0); var characterHit = textLine.GetCharacterHitFromDistance(0);
@ -953,7 +953,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
distance = textLine.GetDistanceFromCharacterHit(new CharacterHit(characterHit.FirstCharacterIndex)); distance = textLine.GetDistanceFromCharacterHit(new CharacterHit(characterHit.FirstCharacterIndex));
var firstAdvance = firstRun.ShapedBuffer.GlyphInfos[0].GlyphAdvance; var firstAdvance = firstRun.ShapedBuffer[0].GlyphAdvance;
Assert.Equal(firstAdvance, distance, 5); Assert.Equal(firstAdvance, distance, 5);
@ -996,9 +996,9 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var shapedRuns = textLine.TextRuns.Cast<ShapedTextRun>().ToList(); var shapedRuns = textLine.TextRuns.Cast<ShapedTextRun>().ToList();
var clusters = shapedRuns.SelectMany(x => x.ShapedBuffer.GlyphInfos, (_, glyph) => glyph.GlyphCluster).ToList(); var clusters = shapedRuns.SelectMany(x => x.ShapedBuffer, (_, glyph) => glyph.GlyphCluster).ToList();
var glyphAdvances = shapedRuns.SelectMany(x => x.ShapedBuffer.GlyphInfos, (_, glyph) => glyph.GlyphAdvance).ToList(); var glyphAdvances = shapedRuns.SelectMany(x => x.ShapedBuffer, (_, glyph) => glyph.GlyphAdvance).ToList();
var currentX = 0.0; var currentX = 0.0;

14
tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs

@ -95,7 +95,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
{ {
var shapedRun = (ShapedTextRun)textRun; var shapedRun = (ShapedTextRun)textRun;
var runClusters = shapedRun.ShapedBuffer.GlyphInfos.Select(glyph => glyph.GlyphCluster); var runClusters = shapedRun.ShapedBuffer.Select(glyph => glyph.GlyphCluster);
clusters.AddRange(shapedRun.IsReversed ? runClusters.Reverse() : runClusters); clusters.AddRange(shapedRun.IsReversed ? runClusters.Reverse() : runClusters);
} }
@ -142,7 +142,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
{ {
var shapedRun = (ShapedTextRun)textRun; var shapedRun = (ShapedTextRun)textRun;
var runClusters = shapedRun.ShapedBuffer.GlyphInfos.Select(glyph => glyph.GlyphCluster); var runClusters = shapedRun.ShapedBuffer.Select(glyph => glyph.GlyphCluster);
clusters.AddRange(shapedRun.IsReversed ? runClusters.Reverse() : runClusters); clusters.AddRange(shapedRun.IsReversed ? runClusters.Reverse() : runClusters);
} }
@ -249,7 +249,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var clusters = textLine.TextRuns var clusters = textLine.TextRuns
.Cast<ShapedTextRun>() .Cast<ShapedTextRun>()
.SelectMany(x => x.ShapedBuffer.GlyphInfos, (_, glyph) => glyph.GlyphCluster) .SelectMany(x => x.ShapedBuffer, (_, glyph) => glyph.GlyphCluster)
.ToArray(); .ToArray();
var previousCharacterHit = new CharacterHit(text.Length); var previousCharacterHit = new CharacterHit(text.Length);
@ -752,7 +752,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
{ {
var shapedBuffer = textRun.ShapedBuffer; var shapedBuffer = textRun.ShapedBuffer;
var currentClusters = shapedBuffer.GlyphInfos.Select(glyph => glyph.GlyphCluster).ToList(); var currentClusters = shapedBuffer.Select(glyph => glyph.GlyphCluster).ToList();
foreach (var currentCluster in currentClusters) foreach (var currentCluster in currentClusters)
{ {
@ -785,11 +785,11 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
{ {
var shapedBuffer = textRun.ShapedBuffer; var shapedBuffer = textRun.ShapedBuffer;
for (var index = 0; index < shapedBuffer.GlyphInfos.Length; index++) for (var index = 0; index < shapedBuffer.Length; index++)
{ {
var currentCluster = shapedBuffer.GlyphInfos[index].GlyphCluster; var currentCluster = shapedBuffer[index].GlyphCluster;
var advance = shapedBuffer.GlyphInfos[index].GlyphAdvance; var advance = shapedBuffer[index].GlyphAdvance;
if (lastCluster != currentCluster) if (lastCluster != currentCluster)
{ {

10
tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextShaperTests.cs

@ -19,10 +19,10 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var shapedBuffer = TextShaper.Current.ShapeText(text, options); var shapedBuffer = TextShaper.Current.ShapeText(text, options);
Assert.Equal(shapedBuffer.Length, text.Length); Assert.Equal(shapedBuffer.Length, text.Length);
Assert.Equal(shapedBuffer.GlyphInfos.Length, text.Length); Assert.Equal(shapedBuffer.Length, text.Length);
Assert.Equal(0, shapedBuffer.GlyphInfos[0].GlyphCluster); Assert.Equal(0, shapedBuffer[0].GlyphCluster);
Assert.Equal(1, shapedBuffer.GlyphInfos[1].GlyphCluster); Assert.Equal(1, shapedBuffer[1].GlyphCluster);
Assert.Equal(1, shapedBuffer.GlyphInfos[2].GlyphCluster); Assert.Equal(1, shapedBuffer[2].GlyphCluster);
} }
} }
@ -36,7 +36,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var shapedBuffer = TextShaper.Current.ShapeText(text, options); var shapedBuffer = TextShaper.Current.ShapeText(text, options);
Assert.Equal(shapedBuffer.Length, text.Length); Assert.Equal(shapedBuffer.Length, text.Length);
Assert.Equal(100, shapedBuffer.GlyphInfos[0].GlyphAdvance); Assert.Equal(100, shapedBuffer[0].GlyphAdvance);
} }
} }

4
tests/Avalonia.UnitTests/HarfBuzzTextShaperImpl.cs

@ -52,8 +52,6 @@ namespace Avalonia.UnitTests
var shapedBuffer = new ShapedBuffer(text, bufferLength, typeface, fontRenderingEmSize, bidiLevel); var shapedBuffer = new ShapedBuffer(text, bufferLength, typeface, fontRenderingEmSize, bidiLevel);
var targetInfos = shapedBuffer.GlyphInfos;
var glyphInfos = buffer.GetGlyphInfoSpan(); var glyphInfos = buffer.GetGlyphInfoSpan();
var glyphPositions = buffer.GetGlyphPositionSpan(); var glyphPositions = buffer.GetGlyphPositionSpan();
@ -79,7 +77,7 @@ namespace Avalonia.UnitTests
4 * typeface.GetGlyphAdvance(glyphIndex) * textScale; 4 * typeface.GetGlyphAdvance(glyphIndex) * textScale;
} }
targetInfos[i] = new Media.TextFormatting.GlyphInfo(glyphIndex, glyphCluster, glyphAdvance, glyphOffset); shapedBuffer[i] = new Media.TextFormatting.GlyphInfo(glyphIndex, glyphCluster, glyphAdvance, glyphOffset);
} }
return shapedBuffer; return shapedBuffer;

3
tests/Avalonia.UnitTests/MockTextShaperImpl.cs

@ -13,7 +13,6 @@ namespace Avalonia.UnitTests
var fontRenderingEmSize = options.FontRenderingEmSize; var fontRenderingEmSize = options.FontRenderingEmSize;
var bidiLevel = options.BidiLevel; var bidiLevel = options.BidiLevel;
var shapedBuffer = new ShapedBuffer(text, text.Length, typeface, fontRenderingEmSize, bidiLevel); var shapedBuffer = new ShapedBuffer(text, text.Length, typeface, fontRenderingEmSize, bidiLevel);
var targetInfos = shapedBuffer.GlyphInfos;
var textSpan = text.Span; var textSpan = text.Span;
var textStartIndex = TextTestHelper.GetStartCharIndex(text); var textStartIndex = TextTestHelper.GetStartCharIndex(text);
@ -27,7 +26,7 @@ namespace Avalonia.UnitTests
for (var j = 0; j < count; ++j) for (var j = 0; j < count; ++j)
{ {
targetInfos[i + j] = new GlyphInfo(glyphIndex, glyphCluster, 10); shapedBuffer[i + j] = new GlyphInfo(glyphIndex, glyphCluster, 10);
} }
i += count; i += count;

Loading…
Cancel
Save