зеркало из https://github.com/mono/SkiaSharp.git
371 строка
12 KiB
C#
371 строка
12 KiB
C#
using System;
|
|
using System.Buffers;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
|
|
namespace HarfBuzzSharp
|
|
{
|
|
public unsafe class Buffer : NativeObject
|
|
{
|
|
public const int DefaultReplacementCodepoint = '\uFFFD';
|
|
|
|
internal Buffer (IntPtr handle)
|
|
: base (handle)
|
|
{
|
|
}
|
|
|
|
public Buffer ()
|
|
: this (HarfBuzzApi.hb_buffer_create ())
|
|
{
|
|
}
|
|
|
|
public ContentType ContentType {
|
|
get => HarfBuzzApi.hb_buffer_get_content_type (Handle);
|
|
set => HarfBuzzApi.hb_buffer_set_content_type (Handle, value);
|
|
}
|
|
|
|
public Direction Direction {
|
|
get => HarfBuzzApi.hb_buffer_get_direction (Handle);
|
|
set => HarfBuzzApi.hb_buffer_set_direction (Handle, value);
|
|
}
|
|
|
|
public Language Language {
|
|
get => new Language (HarfBuzzApi.hb_buffer_get_language (Handle));
|
|
set => HarfBuzzApi.hb_buffer_set_language (Handle, value.Handle);
|
|
}
|
|
|
|
public BufferFlags Flags {
|
|
get => HarfBuzzApi.hb_buffer_get_flags (Handle);
|
|
set => HarfBuzzApi.hb_buffer_set_flags (Handle, value);
|
|
}
|
|
|
|
public ClusterLevel ClusterLevel {
|
|
get => HarfBuzzApi.hb_buffer_get_cluster_level (Handle);
|
|
set => HarfBuzzApi.hb_buffer_set_cluster_level (Handle, value);
|
|
}
|
|
|
|
public uint ReplacementCodepoint {
|
|
get => HarfBuzzApi.hb_buffer_get_replacement_codepoint (Handle);
|
|
set => HarfBuzzApi.hb_buffer_set_replacement_codepoint (Handle, value);
|
|
}
|
|
|
|
public uint InvisibleGlyph {
|
|
get => HarfBuzzApi.hb_buffer_get_invisible_glyph (Handle);
|
|
set => HarfBuzzApi.hb_buffer_set_invisible_glyph (Handle, value);
|
|
}
|
|
|
|
public Script Script {
|
|
get => HarfBuzzApi.hb_buffer_get_script (Handle);
|
|
set => HarfBuzzApi.hb_buffer_set_script (Handle, value);
|
|
}
|
|
|
|
public int Length {
|
|
get => (int)HarfBuzzApi.hb_buffer_get_length (Handle);
|
|
set => HarfBuzzApi.hb_buffer_set_length (Handle, (uint)value);
|
|
}
|
|
|
|
public UnicodeFunctions UnicodeFunctions {
|
|
get => new UnicodeFunctions (HarfBuzzApi.hb_buffer_get_unicode_funcs (Handle));
|
|
set => HarfBuzzApi.hb_buffer_set_unicode_funcs (Handle, value.Handle);
|
|
}
|
|
|
|
public GlyphInfo[] GlyphInfos {
|
|
get {
|
|
var array = GetGlyphInfoSpan ().ToArray ();
|
|
GC.KeepAlive (this);
|
|
return array;
|
|
}
|
|
}
|
|
|
|
public GlyphPosition[] GlyphPositions {
|
|
get {
|
|
var array = GetGlyphPositionSpan ().ToArray ();
|
|
GC.KeepAlive (this);
|
|
return array;
|
|
}
|
|
}
|
|
|
|
public void Add (int codepoint, int cluster) => Add ((uint)codepoint, (uint)cluster);
|
|
|
|
public void Add (uint codepoint, uint cluster)
|
|
{
|
|
if (Length != 0 && ContentType != ContentType.Unicode)
|
|
throw new InvalidOperationException ("Non empty buffer's ContentType must be of type Unicode.");
|
|
if (ContentType == ContentType.Glyphs)
|
|
throw new InvalidOperationException ("ContentType must not be of type Glyphs");
|
|
|
|
HarfBuzzApi.hb_buffer_add (Handle, codepoint, cluster);
|
|
}
|
|
|
|
public void AddUtf8 (string utf8text) => AddUtf8 (Encoding.UTF8.GetBytes (utf8text), 0, -1);
|
|
|
|
public void AddUtf8 (byte[] bytes) => AddUtf8 (new ReadOnlySpan<byte> (bytes));
|
|
|
|
public void AddUtf8 (ReadOnlySpan<byte> text) => AddUtf8 (text, 0, -1);
|
|
|
|
public unsafe void AddUtf8 (ReadOnlySpan<byte> text, int itemOffset, int itemLength)
|
|
{
|
|
fixed (byte* bytes = text) {
|
|
AddUtf8 ((IntPtr)bytes, text.Length, itemOffset, itemLength);
|
|
}
|
|
}
|
|
|
|
public void AddUtf8 (IntPtr text, int textLength) => AddUtf8 (text, textLength, 0, -1);
|
|
|
|
public void AddUtf8 (IntPtr text, int textLength, int itemOffset, int itemLength)
|
|
{
|
|
if (itemOffset < 0)
|
|
throw new ArgumentOutOfRangeException (nameof (itemOffset), "ItemOffset must be non negative.");
|
|
if (Length != 0 && ContentType != ContentType.Unicode)
|
|
throw new InvalidOperationException ("Non empty buffer's ContentType must be of type Unicode.");
|
|
if (ContentType == ContentType.Glyphs)
|
|
throw new InvalidOperationException ("ContentType must not be Glyphs");
|
|
|
|
HarfBuzzApi.hb_buffer_add_utf8 (Handle, (void*)text, textLength, (uint)itemOffset, itemLength);
|
|
}
|
|
|
|
public void AddUtf16 (string text) => AddUtf16 (text, 0, -1);
|
|
|
|
public unsafe void AddUtf16 (string text, int itemOffset, int itemLength)
|
|
{
|
|
fixed (char* chars = text) {
|
|
AddUtf16 ((IntPtr)chars, text.Length, itemOffset, itemLength);
|
|
}
|
|
}
|
|
|
|
public unsafe void AddUtf16 (ReadOnlySpan<byte> text)
|
|
{
|
|
fixed (byte* bytes = text) {
|
|
AddUtf16 ((IntPtr)bytes, text.Length / 2);
|
|
}
|
|
}
|
|
|
|
public void AddUtf16 (ReadOnlySpan<char> text) => AddUtf16 (text, 0, -1);
|
|
|
|
public unsafe void AddUtf16 (ReadOnlySpan<char> text, int itemOffset, int itemLength)
|
|
{
|
|
fixed (char* chars = text) {
|
|
AddUtf16 ((IntPtr)chars, text.Length, itemOffset, itemLength);
|
|
}
|
|
}
|
|
|
|
public void AddUtf16 (IntPtr text, int textLength) =>
|
|
AddUtf16 (text, textLength, 0, -1);
|
|
|
|
public void AddUtf16 (IntPtr text, int textLength, int itemOffset, int itemLength)
|
|
{
|
|
if (itemOffset < 0)
|
|
throw new ArgumentOutOfRangeException (nameof (itemOffset), "ItemOffset must be non negative.");
|
|
if (Length != 0 && ContentType != ContentType.Unicode)
|
|
throw new InvalidOperationException ("Non empty buffer's ContentType must be of type Unicode.");
|
|
if (ContentType == ContentType.Glyphs)
|
|
throw new InvalidOperationException ("ContentType must not be of type Glyphs");
|
|
|
|
HarfBuzzApi.hb_buffer_add_utf16 (Handle, (ushort*)text, textLength, (uint)itemOffset, itemLength);
|
|
}
|
|
|
|
public void AddUtf32 (string text) => AddUtf32 (Encoding.UTF32.GetBytes (text));
|
|
|
|
public unsafe void AddUtf32 (ReadOnlySpan<byte> text)
|
|
{
|
|
fixed (byte* bytes = text) {
|
|
AddUtf32 ((IntPtr)bytes, text.Length / 4);
|
|
}
|
|
}
|
|
|
|
public void AddUtf32 (ReadOnlySpan<uint> text) => AddUtf32 (text, 0, -1);
|
|
|
|
public unsafe void AddUtf32 (ReadOnlySpan<uint> text, int itemOffset, int itemLength)
|
|
{
|
|
fixed (uint* integers = text) {
|
|
AddUtf32 ((IntPtr)integers, text.Length, itemOffset, itemLength);
|
|
}
|
|
}
|
|
|
|
public void AddUtf32 (ReadOnlySpan<int> text) => AddUtf32 (text, 0, -1);
|
|
|
|
public unsafe void AddUtf32 (ReadOnlySpan<int> text, int itemOffset, int itemLength)
|
|
{
|
|
fixed (int* integers = text) {
|
|
AddUtf32 ((IntPtr)integers, text.Length, itemOffset, itemLength);
|
|
}
|
|
}
|
|
|
|
public void AddUtf32 (IntPtr text, int textLength) =>
|
|
AddUtf32 (text, textLength, 0, -1);
|
|
|
|
public void AddUtf32 (IntPtr text, int textLength, int itemOffset, int itemLength)
|
|
{
|
|
if (itemOffset < 0)
|
|
throw new ArgumentOutOfRangeException (nameof (itemOffset), "ItemOffset must be non negative.");
|
|
if (Length != 0 && ContentType != ContentType.Unicode)
|
|
throw new InvalidOperationException ("Non empty buffer's ContentType must be of type Unicode.");
|
|
if (ContentType == ContentType.Glyphs)
|
|
throw new InvalidOperationException ("ContentType must not be of type Glyphs");
|
|
|
|
HarfBuzzApi.hb_buffer_add_utf32 (Handle, (uint*)text, textLength, (uint)itemOffset, itemLength);
|
|
}
|
|
|
|
public void AddCodepoints (ReadOnlySpan<uint> text) => AddCodepoints (text, 0, -1);
|
|
|
|
public unsafe void AddCodepoints (ReadOnlySpan<uint> text, int itemOffset, int itemLength)
|
|
{
|
|
fixed (uint* codepoints = text) {
|
|
AddCodepoints ((IntPtr)codepoints, text.Length, itemOffset, itemLength);
|
|
}
|
|
}
|
|
|
|
public void AddCodepoints (ReadOnlySpan<int> text) => AddCodepoints (text, 0, -1);
|
|
|
|
public unsafe void AddCodepoints (ReadOnlySpan<int> text, int itemOffset, int itemLength)
|
|
{
|
|
fixed (int* codepoints = text) {
|
|
AddCodepoints ((IntPtr)codepoints, text.Length, itemOffset, itemLength);
|
|
}
|
|
}
|
|
|
|
public void AddCodepoints (IntPtr text, int textLength) => AddCodepoints (text, textLength, 0, -1);
|
|
|
|
public void AddCodepoints (IntPtr text, int textLength, int itemOffset, int itemLength)
|
|
{
|
|
if (itemOffset < 0)
|
|
throw new ArgumentOutOfRangeException (nameof (itemOffset), "ItemOffset must be non negative.");
|
|
if (Length != 0 && ContentType != ContentType.Unicode)
|
|
throw new InvalidOperationException ("Non empty buffer's ContentType must be of type Unicode.");
|
|
if (ContentType == ContentType.Glyphs)
|
|
throw new InvalidOperationException ("ContentType must not be of type Glyphs");
|
|
|
|
HarfBuzzApi.hb_buffer_add_codepoints (Handle, (uint*)text, textLength, (uint)itemOffset, itemLength);
|
|
}
|
|
|
|
public unsafe ReadOnlySpan<GlyphInfo> GetGlyphInfoSpan ()
|
|
{
|
|
uint length;
|
|
var infoPtrs = HarfBuzzApi.hb_buffer_get_glyph_infos (Handle, &length);
|
|
return new ReadOnlySpan<GlyphInfo> (infoPtrs, (int)length);
|
|
}
|
|
|
|
public unsafe ReadOnlySpan<GlyphPosition> GetGlyphPositionSpan ()
|
|
{
|
|
uint length;
|
|
var infoPtrs = HarfBuzzApi.hb_buffer_get_glyph_positions (Handle, &length);
|
|
return new ReadOnlySpan<GlyphPosition> (infoPtrs, (int)length);
|
|
}
|
|
|
|
public void GuessSegmentProperties ()
|
|
{
|
|
if (ContentType != ContentType.Unicode)
|
|
throw new InvalidOperationException ("ContentType must be of type Unicode.");
|
|
|
|
HarfBuzzApi.hb_buffer_guess_segment_properties (Handle);
|
|
}
|
|
|
|
public void ClearContents () => HarfBuzzApi.hb_buffer_clear_contents (Handle);
|
|
|
|
public void Reset () => HarfBuzzApi.hb_buffer_reset (Handle);
|
|
|
|
public void Append (Buffer buffer) => Append (buffer, 0, -1);
|
|
|
|
public void Append (Buffer buffer, int start, int end)
|
|
{
|
|
if (buffer.Length == 0)
|
|
throw new ArgumentException ("Buffer must be non empty.", nameof (buffer));
|
|
if (buffer.ContentType != ContentType)
|
|
throw new InvalidOperationException ("ContentType must be of same type.");
|
|
|
|
HarfBuzzApi.hb_buffer_append (Handle, buffer.Handle, (uint)start, (uint)(end == -1 ? buffer.Length : end));
|
|
}
|
|
|
|
public void NormalizeGlyphs ()
|
|
{
|
|
if (ContentType != ContentType.Glyphs)
|
|
throw new InvalidOperationException ("ContentType must be of type Glyphs.");
|
|
if (GlyphPositions.Length == 0)
|
|
throw new InvalidOperationException ("GlyphPositions can't be empty.");
|
|
|
|
HarfBuzzApi.hb_buffer_normalize_glyphs (Handle);
|
|
}
|
|
|
|
public void Reverse () => HarfBuzzApi.hb_buffer_reverse (Handle);
|
|
|
|
public void ReverseRange (int start, int end) =>
|
|
HarfBuzzApi.hb_buffer_reverse_range (Handle, (uint)start, (uint)(end == -1 ? Length : end));
|
|
|
|
public void ReverseClusters () => HarfBuzzApi.hb_buffer_reverse_clusters (Handle);
|
|
|
|
public string SerializeGlyphs () =>
|
|
SerializeGlyphs (0, -1, null, SerializeFormat.Text, SerializeFlag.Default);
|
|
|
|
public string SerializeGlyphs (int start, int end) =>
|
|
SerializeGlyphs (start, end, null, SerializeFormat.Text, SerializeFlag.Default);
|
|
|
|
public string SerializeGlyphs (Font font) =>
|
|
SerializeGlyphs (0, -1, font, SerializeFormat.Text, SerializeFlag.Default);
|
|
|
|
public string SerializeGlyphs (Font font, SerializeFormat format, SerializeFlag flags) =>
|
|
SerializeGlyphs (0, -1, font, format, flags);
|
|
|
|
public unsafe string SerializeGlyphs (int start, int end, Font font, SerializeFormat format, SerializeFlag flags)
|
|
{
|
|
if (Length == 0)
|
|
throw new InvalidOperationException ("Buffer should not be empty.");
|
|
if (ContentType != ContentType.Glyphs)
|
|
throw new InvalidOperationException ("ContentType should be of type Glyphs.");
|
|
|
|
if (end == -1)
|
|
end = Length;
|
|
|
|
using (var buffer = MemoryPool<byte>.Shared.Rent ())
|
|
using (var pinned = buffer.Memory.Pin ()) {
|
|
var bufferSize = buffer.Memory.Length;
|
|
var currentPosition = (uint)start;
|
|
var builder = new StringBuilder (bufferSize);
|
|
|
|
while (currentPosition < end) {
|
|
uint consumed;
|
|
currentPosition += HarfBuzzApi.hb_buffer_serialize_glyphs (
|
|
Handle,
|
|
(uint)currentPosition,
|
|
(uint)end,
|
|
pinned.Pointer,
|
|
(uint)bufferSize,
|
|
&consumed,
|
|
font?.Handle ?? IntPtr.Zero,
|
|
format,
|
|
flags);
|
|
|
|
builder.Append (Marshal.PtrToStringAnsi ((IntPtr)pinned.Pointer, (int)consumed));
|
|
}
|
|
|
|
return builder.ToString ();
|
|
}
|
|
}
|
|
|
|
public void DeserializeGlyphs (string data) =>
|
|
DeserializeGlyphs (data, null, SerializeFormat.Text);
|
|
|
|
public void DeserializeGlyphs (string data, Font font) =>
|
|
DeserializeGlyphs (data, font, SerializeFormat.Text);
|
|
|
|
public void DeserializeGlyphs (string data, Font font, SerializeFormat format)
|
|
{
|
|
if (Length != 0)
|
|
throw new InvalidOperationException ("Buffer must be empty.");
|
|
if (ContentType == ContentType.Glyphs)
|
|
throw new InvalidOperationException ("ContentType must not be Glyphs.");
|
|
|
|
HarfBuzzApi.hb_buffer_deserialize_glyphs (Handle, data, -1, null, font?.Handle ?? IntPtr.Zero, format);
|
|
}
|
|
|
|
protected override void Dispose (bool disposing) =>
|
|
base.Dispose (disposing);
|
|
|
|
protected override void DisposeHandler ()
|
|
{
|
|
if (Handle != IntPtr.Zero) {
|
|
HarfBuzzApi.hb_buffer_destroy (Handle);
|
|
}
|
|
}
|
|
}
|
|
}
|