csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
234 lines
7.4 KiB
234 lines
7.4 KiB
using System.Runtime.CompilerServices;
|
|
using Avalonia.Utilities;
|
|
|
|
namespace Avalonia.Media.TextFormatting.Unicode
|
|
{
|
|
public readonly struct Codepoint
|
|
{
|
|
private readonly uint _value;
|
|
|
|
/// <summary>
|
|
/// The replacement codepoint that is used for non supported values.
|
|
/// </summary>
|
|
public static readonly Codepoint ReplacementCodepoint = new Codepoint('\uFFFD');
|
|
|
|
public Codepoint(uint value)
|
|
{
|
|
_value = value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the codepoint's value.
|
|
/// </summary>
|
|
public uint Value => _value;
|
|
|
|
/// <summary>
|
|
/// Gets the <see cref="Unicode.GeneralCategory"/>.
|
|
/// </summary>
|
|
public GeneralCategory GeneralCategory => UnicodeData.GetGeneralCategory(_value);
|
|
|
|
/// <summary>
|
|
/// Gets the <see cref="Unicode.Script"/>.
|
|
/// </summary>
|
|
public Script Script => UnicodeData.GetScript(_value);
|
|
|
|
/// <summary>
|
|
/// Gets the <see cref="Unicode.BidiClass"/>.
|
|
/// </summary>
|
|
public BidiClass BiDiClass => UnicodeData.GetBiDiClass(_value);
|
|
|
|
/// <summary>
|
|
/// Gets the <see cref="Unicode.BidiPairedBracketType"/>.
|
|
/// </summary>
|
|
public BidiPairedBracketType PairedBracketType => UnicodeData.GetBiDiPairedBracketType(_value);
|
|
|
|
/// <summary>
|
|
/// Gets the <see cref="Unicode.LineBreakClass"/>.
|
|
/// </summary>
|
|
public LineBreakClass LineBreakClass => UnicodeData.GetLineBreakClass(_value);
|
|
|
|
/// <summary>
|
|
/// Gets the <see cref="GraphemeBreakClass"/>.
|
|
/// </summary>
|
|
public GraphemeBreakClass GraphemeBreakClass => UnicodeData.GetGraphemeClusterBreak(_value);
|
|
|
|
/// <summary>
|
|
/// Determines whether this <see cref="Codepoint"/> is a break char.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// <c>true</c> if [is break character]; otherwise, <c>false</c>.
|
|
/// </returns>
|
|
public bool IsBreakChar
|
|
{
|
|
get
|
|
{
|
|
switch (_value)
|
|
{
|
|
case '\u000A':
|
|
case '\u000B':
|
|
case '\u000C':
|
|
case '\u000D':
|
|
case '\u0085':
|
|
case '\u2028':
|
|
case '\u2029':
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether this <see cref="Codepoint"/> is white space.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// <c>true</c> if [is whitespace]; otherwise, <c>false</c>.
|
|
/// </returns>
|
|
public bool IsWhiteSpace
|
|
{
|
|
get
|
|
{
|
|
switch (GeneralCategory)
|
|
{
|
|
case GeneralCategory.Control:
|
|
case GeneralCategory.NonspacingMark:
|
|
case GeneralCategory.Format:
|
|
case GeneralCategory.SpaceSeparator:
|
|
case GeneralCategory.SpacingMark:
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the canonical representation of a given codepoint.
|
|
/// <see href="http://www.unicode.org/L2/L2013/13123-norm-and-bpa.pdf"/>
|
|
/// </summary>
|
|
/// <param name="codePoint">The code point to be mapped.</param>
|
|
/// <returns>The mapped canonical code point, or the passed <paramref name="codePoint"/>.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
internal static Codepoint GetCanonicalType(Codepoint codePoint)
|
|
{
|
|
if (codePoint._value == 0x3008)
|
|
{
|
|
return new Codepoint(0x2329);
|
|
}
|
|
|
|
if (codePoint._value == 0x3009)
|
|
{
|
|
return new Codepoint(0x232A);
|
|
}
|
|
|
|
return codePoint;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the codepoint representing the bracket pairing for this instance.
|
|
/// </summary>
|
|
/// <param name="codepoint">
|
|
/// When this method returns, contains the codepoint representing the bracket pairing for this instance;
|
|
/// otherwise, the default value for the type of the <paramref name="codepoint"/> parameter.
|
|
/// This parameter is passed uninitialized.
|
|
/// .</param>
|
|
/// <returns><see langword="true"/> if this instance has a bracket pairing; otherwise, <see langword="false"/></returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public bool TryGetPairedBracket(out Codepoint codepoint)
|
|
{
|
|
if (PairedBracketType == BidiPairedBracketType.None)
|
|
{
|
|
codepoint = default;
|
|
|
|
return false;
|
|
}
|
|
|
|
codepoint = UnicodeData.GetBiDiPairedBracket(_value);
|
|
|
|
return true;
|
|
}
|
|
|
|
public static implicit operator int(Codepoint codepoint)
|
|
{
|
|
return (int)codepoint._value;
|
|
}
|
|
|
|
public static implicit operator uint(Codepoint codepoint)
|
|
{
|
|
return codepoint._value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads the <see cref="Codepoint"/> at specified position.
|
|
/// </summary>
|
|
/// <param name="text">The buffer to read from.</param>
|
|
/// <param name="index">The index to read at.</param>
|
|
/// <param name="count">The count of character that were read.</param>
|
|
/// <returns></returns>
|
|
public static Codepoint ReadAt(ReadOnlySlice<char> text, int index, out int count)
|
|
{
|
|
count = 1;
|
|
|
|
if (index >= text.Length)
|
|
{
|
|
return ReplacementCodepoint;
|
|
}
|
|
|
|
var code = text[index];
|
|
|
|
ushort hi, low;
|
|
|
|
//# High surrogate
|
|
if (0xD800 <= code && code <= 0xDBFF)
|
|
{
|
|
hi = code;
|
|
|
|
if (index + 1 == text.Length)
|
|
{
|
|
return ReplacementCodepoint;
|
|
}
|
|
|
|
low = text[index + 1];
|
|
|
|
if (0xDC00 <= low && low <= 0xDFFF)
|
|
{
|
|
count = 2;
|
|
return new Codepoint((uint)((hi - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000));
|
|
}
|
|
|
|
return ReplacementCodepoint;
|
|
}
|
|
|
|
//# Low surrogate
|
|
if (0xDC00 <= code && code <= 0xDFFF)
|
|
{
|
|
if (index == 0)
|
|
{
|
|
return ReplacementCodepoint;
|
|
}
|
|
|
|
hi = text[index - 1];
|
|
|
|
low = code;
|
|
|
|
if (0xD800 <= hi && hi <= 0xDBFF)
|
|
{
|
|
count = 2;
|
|
return new Codepoint((uint)((hi - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000));
|
|
}
|
|
|
|
return ReplacementCodepoint;
|
|
}
|
|
|
|
return new Codepoint(code);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns <see langword="true"/> if <paramref name="cp"/> is between
|
|
/// <paramref name="lowerBound"/> and <paramref name="upperBound"/>, inclusive.
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static bool IsInRangeInclusive(Codepoint cp, uint lowerBound, uint upperBound)
|
|
=> (cp._value - lowerBound) <= (upperBound - lowerBound);
|
|
}
|
|
}
|
|
|