Fixes for SkiaSharp 2.8 (font fallback not working) + don't use deprecated functions
This commit is contained in:
Родитель
403b3591db
Коммит
8ff2b6d298
|
@ -96,7 +96,7 @@
|
|||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SkiaSharp" Version="1.68.0" />
|
||||
<PackageReference Include="SkiaSharp" Version="2.80.1" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
|
@ -35,7 +35,7 @@
|
|||
this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BackColor = System.Drawing.Color.White;
|
||||
this.ClientSize = new System.Drawing.Size(1402, 724);
|
||||
this.ClientSize = new System.Drawing.Size(1576, 1025);
|
||||
this.Name = "Form1";
|
||||
this.Text = "RichTextKit Sandbox";
|
||||
this.Load += new System.EventHandler(this.Form1_Load);
|
||||
|
|
|
@ -100,7 +100,7 @@
|
|||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SkiaSharp" Version="1.68.0" />
|
||||
<PackageReference Include="SkiaSharp" Version="2.80.1" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
|
@ -110,9 +110,6 @@ namespace SandboxDriver
|
|||
break;
|
||||
|
||||
case 1:
|
||||
_textBlock.AddText("\n\n", styleNormal);
|
||||
//_textBlock.AddEllipsis();
|
||||
/*
|
||||
_textBlock.AddText("Hello Wor", styleNormal);
|
||||
_textBlock.AddText("ld", styleRed);
|
||||
_textBlock.AddText(". This is normal 18px. These are emojis: 🌐 🍪 🍕 🚀 🏴☠️", styleNormal);
|
||||
|
@ -129,7 +126,6 @@ namespace SandboxDriver
|
|||
_textBlock.AddText("हालाँकि प्रचलित रूप पूज", styleNormal);
|
||||
_textBlock.AddText(", Han: ", styleNormal);
|
||||
_textBlock.AddText("緳 踥踕", styleNormal);
|
||||
*/
|
||||
break;
|
||||
|
||||
case 2:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netcoreapp2.0;net45</TargetFrameworks>
|
||||
<TargetFrameworks>net462</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -13,7 +13,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SkiaSharp" Version="1.68.0" />
|
||||
<PackageReference Include="SkiaSharp" Version="2.80.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -8,10 +8,13 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
||||
<PackageReference Include="SkiaSharp" Version="1.68.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="SkiaSharp" Version="2.80.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29728.190
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Topten.RichTextKit", "Topten.RichTextKit\Topten.RichTextKit.csproj", "{6472D685-FD75-4475-8DE2-53917B0BA189}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sandbox", "Sandbox\Sandbox.csproj", "{A8440E53-0D1E-477B-81B3-7916ECAF2EF2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SandboxDriver", "SandboxDriver\SandboxDriver.csproj", "{76AE34F1-D8B7-4593-A9FA-A82CDB438A5C}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Topten.RichTextKit.Test", "Topten.RichTextKit.Test\Topten.RichTextKit.Test.csproj", "{44AE4B31-855E-41C5-8AAE-B7E6227EE3E6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestBench", "TestBench\TestBench.csproj", "{79AC4303-DC30-480E-969B-E9320DD4A8CF}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RichStringSandbox", "RichStringSandbox\RichStringSandbox.csproj", "{B11CCB1B-9DEA-44DE-BFFD-B12092C36500}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{6472D685-FD75-4475-8DE2-53917B0BA189}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6472D685-FD75-4475-8DE2-53917B0BA189}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6472D685-FD75-4475-8DE2-53917B0BA189}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6472D685-FD75-4475-8DE2-53917B0BA189}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A8440E53-0D1E-477B-81B3-7916ECAF2EF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A8440E53-0D1E-477B-81B3-7916ECAF2EF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A8440E53-0D1E-477B-81B3-7916ECAF2EF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A8440E53-0D1E-477B-81B3-7916ECAF2EF2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{76AE34F1-D8B7-4593-A9FA-A82CDB438A5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{76AE34F1-D8B7-4593-A9FA-A82CDB438A5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{76AE34F1-D8B7-4593-A9FA-A82CDB438A5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{76AE34F1-D8B7-4593-A9FA-A82CDB438A5C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{44AE4B31-855E-41C5-8AAE-B7E6227EE3E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{44AE4B31-855E-41C5-8AAE-B7E6227EE3E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{44AE4B31-855E-41C5-8AAE-B7E6227EE3E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{44AE4B31-855E-41C5-8AAE-B7E6227EE3E6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{79AC4303-DC30-480E-969B-E9320DD4A8CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{79AC4303-DC30-480E-969B-E9320DD4A8CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{79AC4303-DC30-480E-969B-E9320DD4A8CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{79AC4303-DC30-480E-969B-E9320DD4A8CF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B11CCB1B-9DEA-44DE-BFFD-B12092C36500}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B11CCB1B-9DEA-44DE-BFFD-B12092C36500}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B11CCB1B-9DEA-44DE-BFFD-B12092C36500}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B11CCB1B-9DEA-44DE-BFFD-B12092C36500}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {45C5DB84-4136-4F76-ADA4-9BC87F3C6A95}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -36,95 +36,96 @@ namespace Topten.RichTextKit
|
|||
|
||||
public static IEnumerable<Run> GetFontRuns(Slice<int> codePoints, SKTypeface typeface)
|
||||
{
|
||||
// Get the font manager - we'll use this to select font fallbacks
|
||||
var fontManager = SKFontManager.Default;
|
||||
|
||||
int currentRunPos = 0;
|
||||
SKTypeface currentRunTypeface = null;
|
||||
int pos = 0;
|
||||
List<Run> runs = new List<Run>();
|
||||
// Get glyphs using the top-level typeface
|
||||
var glyphs = new ushort[codePoints.Length];
|
||||
var font = new SKFont(typeface);
|
||||
font.GetGlyphs(codePoints.AsSpan(), glyphs);
|
||||
|
||||
unsafe
|
||||
// Look for subspans that need font fallback (where glyphs are zero)
|
||||
int runStart = 0;
|
||||
for (int i = 0; i < codePoints.Length; i++)
|
||||
{
|
||||
fixed (int* pCodePoints = codePoints.Underlying)
|
||||
// Do we need fallback for this character?
|
||||
if (glyphs[i] == 0)
|
||||
{
|
||||
int* pch = pCodePoints + codePoints.Start;
|
||||
int length = codePoints.Length;
|
||||
while (pos < length)
|
||||
// Check if there's a fallback available, if not, might as well continue with the current top-level typeface
|
||||
var subSpanTypeface = fontManager.MatchCharacter(typeface.FamilyName, typeface.FontWeight, typeface.FontWidth, typeface.FontSlant, null, codePoints[i]);
|
||||
if (subSpanTypeface == null)
|
||||
continue;
|
||||
|
||||
// We can do font fallback...
|
||||
|
||||
// Flush the current top-level run
|
||||
if (i > runStart)
|
||||
{
|
||||
var RunFace = typeface;
|
||||
|
||||
int count = 0;
|
||||
if (pch[pos] <= 32)
|
||||
yield return new Run()
|
||||
{
|
||||
// Control characters and space always map to current typeface
|
||||
count = 1;
|
||||
RunFace = currentRunTypeface ?? typeface;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Consume as many characters as possible using the requested type face
|
||||
count = typeface.GetGlyphs((IntPtr)(pch + pos), length - pos, SKEncoding.Utf32, out var glyphs);
|
||||
}
|
||||
|
||||
// Couldn't be mapped to current font, try to find a replacement
|
||||
if (count == 0)
|
||||
{
|
||||
// Find fallback font
|
||||
RunFace = fontManager.MatchCharacter(typeface.FamilyName, typeface.FontWeight, typeface.FontWidth, typeface.FontSlant, null, pch[pos]);
|
||||
count = 1;
|
||||
if (RunFace == null)
|
||||
{
|
||||
RunFace = typeface;
|
||||
count = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Consume as many as possible
|
||||
count = RunFace.GetGlyphs((IntPtr)(pch + pos), length - pos, SKEncoding.Utf32, out var glyphs);
|
||||
|
||||
// But don't take control characters or spaces...
|
||||
for (int i = 1; i < count; i++)
|
||||
{
|
||||
if (pch[pos] <= 32)
|
||||
{
|
||||
count = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do we need to start a new Run?
|
||||
if (currentRunTypeface != RunFace)
|
||||
{
|
||||
flushCurrentRun();
|
||||
currentRunTypeface = RunFace;
|
||||
currentRunPos = pos;
|
||||
}
|
||||
|
||||
// Move on
|
||||
pos += count;
|
||||
Start = runStart,
|
||||
Length = i - runStart,
|
||||
Typeface = typeface,
|
||||
};
|
||||
}
|
||||
|
||||
// Count how many unmatched characters
|
||||
var unmatchedStart = i;
|
||||
var unmatchedEnd = i + 1;
|
||||
while (unmatchedEnd < codePoints.Length && glyphs[unmatchedEnd] == 0)
|
||||
unmatchedEnd++;
|
||||
var unmatchedLength = unmatchedEnd - unmatchedStart;
|
||||
|
||||
// Match the missing characters
|
||||
while (unmatchedLength > 0)
|
||||
{
|
||||
// Find the font fallback using the first character
|
||||
subSpanTypeface = fontManager.MatchCharacter(typeface.FamilyName, typeface.FontWeight, typeface.FontWidth, typeface.FontSlant, null, codePoints[unmatchedStart]);
|
||||
if (subSpanTypeface == null)
|
||||
{
|
||||
unmatchedEnd = unmatchedStart;
|
||||
break;
|
||||
}
|
||||
var subSpanFont = new SKFont(subSpanTypeface);
|
||||
|
||||
// Get the glyphs over the current unmatched range
|
||||
subSpanFont.GetGlyphs(codePoints.SubSlice(unmatchedStart, unmatchedLength).AsSpan(), new Span<ushort>(glyphs, unmatchedStart, unmatchedLength));
|
||||
|
||||
// Count how many characters were matched
|
||||
var fallbackStart = unmatchedStart;
|
||||
var fallbackEnd = unmatchedStart + 1;
|
||||
while (fallbackEnd < unmatchedEnd && glyphs[fallbackEnd] != 0)
|
||||
fallbackEnd++;
|
||||
var fallbackLength = fallbackEnd - fallbackStart;
|
||||
|
||||
// Yield this font fallback run
|
||||
yield return new Run()
|
||||
{
|
||||
Start = fallbackStart,
|
||||
Length = fallbackLength,
|
||||
Typeface = subSpanTypeface,
|
||||
};
|
||||
|
||||
// Continue selecting font fallbacks until the entire unmatched ranges has been matched
|
||||
unmatchedStart += fallbackLength;
|
||||
unmatchedLength -= fallbackLength;
|
||||
}
|
||||
|
||||
// Move onto the next top level span
|
||||
i = unmatchedEnd - 1; // account for i++ on for loop
|
||||
runStart = unmatchedEnd;
|
||||
}
|
||||
}
|
||||
|
||||
// Flush the final Run
|
||||
flushCurrentRun();
|
||||
|
||||
// Done
|
||||
return runs;
|
||||
|
||||
void flushCurrentRun()
|
||||
// Flush find run
|
||||
if (codePoints.Length > runStart)
|
||||
{
|
||||
if (currentRunTypeface != null)
|
||||
yield return new Run()
|
||||
{
|
||||
runs.Add(new Run()
|
||||
{
|
||||
Start = currentRunPos,
|
||||
Length = pos - currentRunPos,
|
||||
Typeface = currentRunTypeface,
|
||||
});
|
||||
}
|
||||
Start = runStart,
|
||||
Length = codePoints.Length - runStart,
|
||||
Typeface = typeface,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// RichTextKit
|
||||
#define USE_SKTEXTBLOB
|
||||
// RichTextKit
|
||||
// Copyright © 2019-2020 Topten Software. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
|
@ -13,6 +14,7 @@
|
|||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
using HarfBuzzSharp;
|
||||
using SkiaSharp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -209,6 +211,8 @@ namespace Topten.RichTextKit
|
|||
GlyphPositions[i].X += dx;
|
||||
GlyphPositions[i].Y += dy;
|
||||
}
|
||||
_textBlob?.Dispose();
|
||||
_textBlob = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -362,6 +366,8 @@ namespace Topten.RichTextKit
|
|||
this.Clusters = this.Clusters.SubSlice(0, glyphSplitPos);
|
||||
this.Width = sliceLeftWidth;
|
||||
this.Length = codePointSplitPos;
|
||||
this._textBlob?.Dispose();
|
||||
this._textBlob = null;
|
||||
|
||||
// Return the new run
|
||||
return newRun;
|
||||
|
@ -419,6 +425,8 @@ namespace Topten.RichTextKit
|
|||
this.Clusters = this.Clusters.SubSlice(glyphSplitPos);
|
||||
this.Width = sliceRightWidth;
|
||||
this.Length = codePointSplitPos;
|
||||
this._textBlob?.Dispose();
|
||||
this._textBlob = null;
|
||||
|
||||
// Adjust code point positions
|
||||
for (int i = 0; i < this.RelativeCodePointXCoords.Length; i++)
|
||||
|
@ -555,10 +563,6 @@ namespace Topten.RichTextKit
|
|||
|
||||
// Setup SKPaint
|
||||
paint.Color = Style.TextColor;
|
||||
paint.TextEncoding = SKTextEncoding.GlyphId;
|
||||
paint.Typeface = Typeface;
|
||||
paint.TextSize = Style.FontSize * glyphScale;
|
||||
paint.SubpixelText = true;
|
||||
paint.IsAntialias = ctx.Options.IsAntialias;
|
||||
paint.LcdRenderText = ctx.Options.LcdRenderText;
|
||||
|
||||
|
@ -569,22 +573,35 @@ namespace Topten.RichTextKit
|
|||
// Get glyph positions
|
||||
var glyphPositions = GlyphPositions.ToArray();
|
||||
|
||||
// Create the font
|
||||
if (_font == null)
|
||||
{
|
||||
_font = new SKFont(this.Typeface, this.Style.FontSize * glyphScale);
|
||||
_font.Subpixel = true;
|
||||
}
|
||||
|
||||
// Create the SKTextBlob (if necessary)
|
||||
if (_textBlob == null)
|
||||
{
|
||||
_textBlob = SKTextBlob.CreatePositioned(
|
||||
(IntPtr)(pGlyphs + Glyphs.Start),
|
||||
Glyphs.Length * sizeof(ushort),
|
||||
SKTextEncoding.GlyphId,
|
||||
_font,
|
||||
GlyphPositions.AsSpan());
|
||||
}
|
||||
|
||||
// Paint underline
|
||||
if (Style.Underline != UnderlineStyle.None && RunKind == FontRunKind.Normal)
|
||||
{
|
||||
// Work out underline metrics
|
||||
paint.TextSize = Style.FontSize;
|
||||
float underlineYPos = Line.YCoord + Line.BaseLine + (paint.FontMetrics.UnderlinePosition ?? 0);
|
||||
paint.StrokeWidth = paint.FontMetrics.UnderlineThickness ?? 0;
|
||||
paint.TextSize = Style.FontSize * glyphScale;
|
||||
float underlineYPos = Line.YCoord + Line.BaseLine + (_font.Metrics.UnderlinePosition ?? 0);
|
||||
paint.StrokeWidth = _font.Metrics.UnderlineThickness ?? 0;
|
||||
|
||||
if (Style.Underline == UnderlineStyle.Gapped)
|
||||
{
|
||||
// Get intercept positions
|
||||
var interceptPositions = paint.GetPositionedTextIntercepts(
|
||||
(IntPtr)(pGlyphs + Glyphs.Start),
|
||||
Glyphs.Length * sizeof(ushort),
|
||||
glyphPositions, underlineYPos - paint.StrokeWidth / 2, underlineYPos + paint.StrokeWidth);
|
||||
var interceptPositions = _textBlob.GetIntercepts(underlineYPos - paint.StrokeWidth / 2, underlineYPos + paint.StrokeWidth);
|
||||
|
||||
// Paint gapped underlinline
|
||||
float x = XCoord;
|
||||
|
@ -609,31 +626,38 @@ namespace Topten.RichTextKit
|
|||
}
|
||||
}
|
||||
|
||||
// Draw the text
|
||||
ctx.Canvas.DrawPositionedText((IntPtr)(pGlyphs + Glyphs.Start), Glyphs.Length * sizeof(ushort), glyphPositions, paint);
|
||||
|
||||
ctx.Canvas.DrawText(_textBlob, 0, 0, paint);
|
||||
}
|
||||
}
|
||||
|
||||
// Paint strikethrough
|
||||
if (Style.StrikeThrough != StrikeThroughStyle.None && RunKind == FontRunKind.Normal)
|
||||
{
|
||||
paint.StrokeWidth = paint.FontMetrics.StrikeoutThickness ?? 0;
|
||||
paint.StrokeWidth = _font.Metrics.StrikeoutThickness ?? 0;
|
||||
float strikeYPos = Line.YCoord + Line.BaseLine + (paint.FontMetrics.StrikeoutPosition ?? 0) + glyphVOffset;
|
||||
ctx.Canvas.DrawLine(new SKPoint(XCoord, strikeYPos), new SKPoint(XCoord + Width, strikeYPos), paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SKTextBlob _textBlob;
|
||||
SKFont _font;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
RunKind = FontRunKind.Normal;
|
||||
CodePointBuffer = null;
|
||||
Style = null;
|
||||
Typeface = null;
|
||||
Line = null;
|
||||
_textBlob = null;
|
||||
_font = null;
|
||||
}
|
||||
|
||||
internal static ThreadLocal<ObjectPool<FontRun>> Pool = new ThreadLocal<ObjectPool<FontRun>>(() => new ObjectPool<FontRun>()
|
||||
{
|
||||
Cleaner = (r) =>
|
||||
{
|
||||
r.RunKind = FontRunKind.Normal;
|
||||
r.CodePointBuffer = null;
|
||||
r.Style = null;
|
||||
r.Typeface = null;
|
||||
r.Line = null;
|
||||
}
|
||||
Cleaner = (r) => r.Reset()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -247,7 +247,7 @@ namespace Topten.RichTextKit
|
|||
using (var buffer = new HarfBuzzSharp.Buffer())
|
||||
{
|
||||
// Setup buffer
|
||||
buffer.AddUtf32(new ReadOnlySpan<int>(codePoints.Underlying, codePoints.Start, codePoints.Length), 0, -1);
|
||||
buffer.AddUtf32(codePoints.AsSpan(), 0, -1);
|
||||
|
||||
// Setup directionality (if supplied)
|
||||
switch (direction)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<Import Project="../buildtools/Topten.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;netcoreapp2.0;net45</TargetFrameworks>
|
||||
<TargetFrameworks>netstandard2.0;netcoreapp2.0;net462</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
|
@ -22,8 +22,8 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SkiaSharp" Version="1.68.0" />
|
||||
<PackageReference Include="HarfBuzzSharp" Version="2.6.1" />
|
||||
<PackageReference Include="SkiaSharp" Version="2.80.1" />
|
||||
<PackageReference Include="HarfBuzzSharp" Version="2.6.1.6" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -182,5 +182,11 @@ namespace Topten.RichTextKit.Utils
|
|||
/// A shared empty slice of type T
|
||||
/// </summary>
|
||||
public static Slice<T> Empty => new Slice<T>();
|
||||
|
||||
/// <summary>
|
||||
/// Get the slice as a Span
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Span<T> AsSpan() => new Span<T>(_array, _start, _length);
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче