Browse Source

Merge branch 'master' into feature/txtBlockInlines

pull/9245/head
Benedikt Stebner 4 years ago
committed by GitHub
parent
commit
8528775990
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      Avalonia.sln
  2. 2
      src/Avalonia.Base/Avalonia.Base.csproj
  3. 27
      src/Avalonia.Base/Media/FontSimulations.cs
  4. 24
      src/Avalonia.Base/Media/GlyphMetrics.cs
  5. 15
      src/Avalonia.Base/Media/IGlyphTypeface.cs
  6. 29
      src/Avalonia.Base/Media/TextFormatting/TextFormatterImpl.cs
  7. 13
      src/Avalonia.Headless/HeadlessPlatformStubs.cs
  8. 5
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  9. 2
      src/Shared/StringCompatibilityExtensions.cs
  10. 16
      src/Skia/Avalonia.Skia/FontManagerImpl.cs
  11. 28
      src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs
  12. 25
      src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs
  13. 1
      src/iOS/Avalonia.iOS/AvaloniaView.cs
  14. 2
      tests/Avalonia.Skia.UnitTests/Media/CustomFontManagerImpl.cs
  15. 32
      tests/Avalonia.UnitTests/HarfBuzzGlyphTypefaceImpl.cs
  16. 13
      tests/Avalonia.UnitTests/MockGlyphTypeface.cs

1
Avalonia.sln

@ -41,6 +41,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A689DE
src\Shared\IsExternalInit.cs = src\Shared\IsExternalInit.cs
src\Shared\ModuleInitializer.cs = src\Shared\ModuleInitializer.cs
src\Shared\SourceGeneratorAttributes.cs = src\Shared\SourceGeneratorAttributes.cs
src\Avalonia.Base\Compatibility\StringCompatibilityExtensions.cs = src\Avalonia.Base\Compatibility\StringCompatibilityExtensions.cs
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.ReactiveUI", "src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj", "{6417B24E-49C2-4985-8DB2-3AB9D898EC91}"

2
src/Avalonia.Base/Avalonia.Base.csproj

@ -23,6 +23,7 @@
<Import Project="..\..\build\SourceGenerators.props" />
<ItemGroup>
<Compile Include="..\Shared\IsExternalInit.cs" Link="IsExternalInit.cs" />
<Compile Include="..\Shared\StringCompatibilityExtensions.cs" Link="Compatibility\StringCompatibilityExtensions.cs" />
</ItemGroup>
<ItemGroup Label="InternalsVisibleTo">
@ -46,6 +47,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Compatibility\" />
<Folder Include="Rendering\Composition\Utils" />
</ItemGroup>
</Project>

27
src/Avalonia.Base/Media/FontSimulations.cs

@ -0,0 +1,27 @@
using System;
namespace Avalonia.Media
{
/// <summary>
/// Specifies algorithmic style simulations to be applied to the typeface.
/// Bold and oblique simulations can be combined via bitwise OR operation.
/// </summary>
[Flags]
public enum FontSimulations : byte
{
/// <summary>
/// No simulations are performed.
/// </summary>
None = 0x0000,
/// <summary>
/// Algorithmic emboldening is performed.
/// </summary>
Bold = 0x0001,
/// <summary>
/// Algorithmic italicization is performed.
/// </summary>
Oblique = 0x0002
}
}

24
src/Avalonia.Base/Media/GlyphMetrics.cs

@ -0,0 +1,24 @@
namespace Avalonia.Media;
public readonly struct GlyphMetrics
{
/// <summary>
/// Distance from the x-origin to the left extremum of the glyph.
/// </summary>
public int XBearing { get; init; }
/// <summary>
/// Distance from the top extremum of the glyph to the y-origin.
/// </summary>
public int YBearing{ get; init; }
/// <summary>
/// Distance from the left extremum of the glyph to the right extremum.
/// </summary>
public int Width{ get; init; }
/// <summary>
/// Distance from the top extremum of the glyph to the bottom extremum.
/// </summary>
public int Height{ get; init; }
}

15
src/Avalonia.Base/Media/IGlyphTypeface.cs

@ -19,6 +19,21 @@ namespace Avalonia.Media
/// </returns>
FontMetrics Metrics { get; }
/// <summary>
/// Gets the algorithmic style simulations applied to this glyph typeface.
/// </summary>
FontSimulations FontSimulations { get; }
/// <summary>
/// Tries to get a glyph's metrics in em units.
/// </summary>
/// <param name="glyph">The glyph id.</param>
/// <param name="metrics">The glyph metrics.</param>
/// <returns>
/// <c>true</c> if an glyph's metrics was found, <c>false</c> otherwise.
/// </returns>
bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics);
/// <summary>
/// Returns an glyph index for the specified codepoint.
/// </summary>

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

@ -477,25 +477,28 @@ namespace Avalonia.Media.TextFormatting
{
case ShapedTextCharacters shapedTextCharacters:
{
var firstCluster = shapedTextCharacters.ShapedBuffer.GlyphClusters[0];
var lastCluster = firstCluster;
for (var i = 0; i < shapedTextCharacters.ShapedBuffer.Length; i++)
if(shapedTextCharacters.ShapedBuffer.Length > 0)
{
var glyphInfo = shapedTextCharacters.ShapedBuffer[i];
var firstCluster = shapedTextCharacters.ShapedBuffer.GlyphClusters[0];
var lastCluster = firstCluster;
if (currentWidth + glyphInfo.GlyphAdvance > paragraphWidth)
for (var i = 0; i < shapedTextCharacters.ShapedBuffer.Length; i++)
{
measuredLength += Math.Max(0, lastCluster - firstCluster);
var glyphInfo = shapedTextCharacters.ShapedBuffer[i];
goto found;
}
if (currentWidth + glyphInfo.GlyphAdvance > paragraphWidth)
{
measuredLength += Math.Max(0, lastCluster - firstCluster);
lastCluster = glyphInfo.GlyphCluster;
currentWidth += glyphInfo.GlyphAdvance;
}
goto found;
}
measuredLength += currentRun.TextSourceLength;
lastCluster = glyphInfo.GlyphCluster;
currentWidth += glyphInfo.GlyphAdvance;
}
measuredLength += currentRun.TextSourceLength;
}
break;
}

13
src/Avalonia.Headless/HeadlessPlatformStubs.cs

@ -102,6 +102,8 @@ namespace Avalonia.Headless
public int GlyphCount => 1337;
public FontSimulations FontSimulations { get; }
public void Dispose()
{
}
@ -138,6 +140,17 @@ namespace Avalonia.Headless
table = null;
return false;
}
public bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics)
{
metrics = new GlyphMetrics
{
Height = 10,
Width = 10
};
return true;
}
}
class HeadlessTextShaperStub : ITextShaperImpl

5
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@ -9,6 +9,7 @@
<NoWarn>CS1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\Shared\StringCompatibilityExtensions.cs" Link="Compatibility\StringCompatibilityExtensions.cs" />
<Compile Include="AvaloniaXamlLoader.cs" />
<Compile Include="Converters\AvaloniaUriTypeConverter.cs" />
<Compile Include="Converters\ColorToBrushConverter.cs" />
@ -68,4 +69,8 @@
<ItemGroup Label="InternalsVisibleTo">
<InternalsVisibleTo Include="Avalonia.Markup.Xaml.UnitTests, PublicKey=$(AvaloniaPublicKey)" />
</ItemGroup>
<ItemGroup>
<Folder Include="Compatibility\" />
</ItemGroup>
</Project>

2
src/Avalonia.Base/Compatibility/StringCompatibilityExtensions.cs → src/Shared/StringCompatibilityExtensions.cs

@ -3,7 +3,7 @@
namespace System;
#if !NET6_0_OR_GREATER
public static class StringCompatibilityExtensions
internal static class StringCompatibilityExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Contains(this string str, char search) =>

16
src/Skia/Avalonia.Skia/FontManagerImpl.cs

@ -148,11 +148,19 @@ namespace Avalonia.Skia
$"Could not create glyph typeface for: {typeface.FontFamily.Name}.");
}
var isFakeBold = (int)typeface.Weight >= 600 && !skTypeface.IsBold;
var fontSimulations = FontSimulations.None;
var isFakeItalic = typeface.Style == FontStyle.Italic && !skTypeface.IsItalic;
return new GlyphTypefaceImpl(skTypeface, isFakeBold, isFakeItalic);
if((int)typeface.Weight >= 600 && !skTypeface.IsBold)
{
fontSimulations |= FontSimulations.Bold;
}
if(typeface.Style == FontStyle.Italic && !skTypeface.IsItalic)
{
fontSimulations |= FontSimulations.Oblique;
}
return new GlyphTypefaceImpl(skTypeface, fontSimulations);
}
}
}

28
src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs

@ -12,7 +12,7 @@ namespace Avalonia.Skia
{
private bool _isDisposed;
public GlyphTypefaceImpl(SKTypeface typeface, bool isFakeBold = false, bool isFakeItalic = false)
public GlyphTypefaceImpl(SKTypeface typeface, FontSimulations fontSimulations)
{
Typeface = typeface ?? throw new ArgumentNullException(nameof(typeface));
@ -52,9 +52,7 @@ namespace Avalonia.Skia
GlyphCount = Typeface.GlyphCount;
IsFakeBold = isFakeBold;
IsFakeItalic = isFakeItalic;
FontSimulations = fontSimulations;
}
public Face Face { get; }
@ -63,6 +61,8 @@ namespace Avalonia.Skia
public SKTypeface Typeface { get; }
public FontSimulations FontSimulations { get; }
public int ReplacementCodepoint { get; }
public FontMetrics Metrics { get; }
@ -73,6 +73,26 @@ namespace Avalonia.Skia
public bool IsFakeItalic { get; }
public bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics)
{
metrics = default;
if (!Font.TryGetGlyphExtents(glyph, out var extents))
{
return false;
}
metrics = new GlyphMetrics
{
XBearing = extents.XBearing,
YBearing = extents.YBearing,
Width = extents.Width,
Height = extents.Height
};
return true;
}
/// <inheritdoc cref="IGlyphTypeface"/>
public ushort GetGlyph(uint codepoint)
{

25
src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs

@ -1,10 +1,11 @@
using System;
using System.Drawing.Drawing2D;
using Avalonia.Media;
using Avalonia.Metadata;
using HarfBuzzSharp;
using SharpDX.DirectWrite;
using FontMetrics = Avalonia.Media.FontMetrics;
using FontSimulations = Avalonia.Media.FontSimulations;
using GlyphMetrics = Avalonia.Media.GlyphMetrics;
namespace Avalonia.Direct2D1.Media
{
@ -82,6 +83,8 @@ namespace Avalonia.Direct2D1.Media
public int GlyphCount { get; set; }
public FontSimulations FontSimulations => FontSimulations.None;
/// <inheritdoc cref="IGlyphTypeface"/>
public ushort GetGlyph(uint codepoint)
{
@ -135,6 +138,26 @@ namespace Avalonia.Direct2D1.Media
return Font.GetHorizontalGlyphAdvances(glyphIndices);
}
public bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics)
{
metrics = default;
if (!Font.TryGetGlyphExtents(glyph, out var extents))
{
return false;
}
metrics = new GlyphMetrics
{
XBearing = extents.XBearing,
YBearing = extents.YBearing,
Width = extents.Width,
Height = extents.Height
};
return true;
}
private void Dispose(bool disposing)
{
if (_isDisposed)

1
src/iOS/Avalonia.iOS/AvaloniaView.cs

@ -46,7 +46,6 @@ namespace Avalonia.iOS
);
_topLevelImpl.Surfaces = new[] { new EaglLayerSurface(l) };
MultipleTouchEnabled = true;
AddSubviews(new UIView[] { new UIKit.UIButton(UIButtonType.InfoDark) });
}
public override bool CanBecomeFirstResponder => true;

2
tests/Avalonia.Skia.UnitTests/Media/CustomFontManagerImpl.cs

@ -103,7 +103,7 @@ namespace Avalonia.Skia.UnitTests.Media
}
}
return new GlyphTypefaceImpl(skTypeface);
return new GlyphTypefaceImpl(skTypeface, FontSimulations.None);
}
}
}

32
tests/Avalonia.UnitTests/HarfBuzzGlyphTypefaceImpl.cs

@ -10,7 +10,7 @@ namespace Avalonia.UnitTests
private bool _isDisposed;
private Blob _blob;
public HarfBuzzGlyphTypefaceImpl(Stream data, bool isFakeBold = false, bool isFakeItalic = false)
public HarfBuzzGlyphTypefaceImpl(Stream data)
{
_blob = Blob.FromStream(data);
@ -45,10 +45,6 @@ namespace Avalonia.UnitTests
};
GlyphCount = Face.GlyphCount;
IsFakeBold = isFakeBold;
IsFakeItalic = isFakeItalic;
}
public FontMetrics Metrics { get; }
@ -58,10 +54,8 @@ namespace Avalonia.UnitTests
public Font Font { get; }
public int GlyphCount { get; set; }
public bool IsFakeBold { get; }
public bool IsFakeItalic { get; }
public FontSimulations FontSimulations { get; }
/// <inheritdoc cref="IGlyphTypeface"/>
public ushort GetGlyph(uint codepoint)
@ -162,5 +156,25 @@ namespace Avalonia.UnitTests
Dispose(true);
GC.SuppressFinalize(this);
}
public bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics)
{
metrics = default;
if (!Font.TryGetGlyphExtents(glyph, out var extents))
{
return false;
}
metrics = new GlyphMetrics
{
XBearing = extents.XBearing,
YBearing = extents.YBearing,
Width = extents.Width,
Height = extents.Height
};
return true;
}
}
}

13
tests/Avalonia.UnitTests/MockGlyphTypeface.cs

@ -15,6 +15,8 @@ namespace Avalonia.UnitTests
public int GlyphCount => 1337;
public FontSimulations FontSimulations => throw new NotImplementedException();
public ushort GetGlyph(uint codepoint)
{
return (ushort)codepoint;
@ -56,5 +58,16 @@ namespace Avalonia.UnitTests
table = null;
return false;
}
public bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics)
{
metrics = new GlyphMetrics
{
Width = 10,
Height = 10
};
return true;
}
}
}

Loading…
Cancel
Save