SkiaSharp/binding/HarfBuzzSharp.Shared/Font.cs

364 строки
10 KiB
C#

using System;
using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
namespace HarfBuzzSharp
{
public unsafe class Font : NativeObject
{
internal const int NameBufferLength = 128;
public Font (Face face)
: base (IntPtr.Zero)
{
if (face == null)
throw new ArgumentNullException (nameof (face));
Handle = HarfBuzzApi.hb_font_create (face.Handle);
OpenTypeMetrics = new OpenTypeMetrics (this);
}
public Font (Font parent)
: base (IntPtr.Zero)
{
if (parent == null)
throw new ArgumentNullException (nameof (parent));
if (parent.Handle == IntPtr.Zero)
throw new ArgumentException (nameof (parent.Handle));
Parent = parent;
Handle = HarfBuzzApi.hb_font_create_sub_font (parent.Handle);
OpenTypeMetrics = new OpenTypeMetrics (this);
}
public Font Parent { get; }
public OpenTypeMetrics OpenTypeMetrics { get; }
public string[] SupportedShapers =>
PtrToStringArray ((IntPtr)HarfBuzzApi.hb_shape_list_shapers ()).ToArray ();
public void SetFontFunctions (FontFunctions fontFunctions) =>
SetFontFunctions (fontFunctions, null, null);
public void SetFontFunctions (FontFunctions fontFunctions, object fontData) =>
SetFontFunctions (fontFunctions, fontData, null);
public void SetFontFunctions (FontFunctions fontFunctions, object fontData, ReleaseDelegate destroy)
{
_ = fontFunctions ?? throw new ArgumentNullException (nameof (fontFunctions));
var container = new FontUserData (this, fontData);
var ctx = DelegateProxies.CreateMultiUserData (destroy, container);
HarfBuzzApi.hb_font_set_funcs (Handle, fontFunctions.Handle, (void*)ctx, DelegateProxies.ReleaseDelegateProxyForMulti);
}
public void GetScale (out int xScale, out int yScale)
{
fixed (int* x = &xScale)
fixed (int* y = &yScale) {
HarfBuzzApi.hb_font_get_scale (Handle, x, y);
}
}
public void SetScale (int xScale, int yScale) =>
HarfBuzzApi.hb_font_set_scale (Handle, xScale, yScale);
public bool TryGetHorizontalFontExtents (out FontExtents extents)
{
fixed (FontExtents* e = &extents) {
return HarfBuzzApi.hb_font_get_h_extents (Handle, e);
}
}
public bool TryGetVerticalFontExtents (out FontExtents extents)
{
fixed (FontExtents* e = &extents) {
return HarfBuzzApi.hb_font_get_v_extents (Handle, e);
}
}
public bool TryGetNominalGlyph (int unicode, out uint glyph) =>
TryGetNominalGlyph ((uint)unicode, out glyph);
public bool TryGetNominalGlyph (uint unicode, out uint glyph)
{
fixed (uint* g = &glyph) {
return HarfBuzzApi.hb_font_get_nominal_glyph (Handle, unicode, g);
}
}
public bool TryGetVariationGlyph (int unicode, out uint glyph) =>
TryGetVariationGlyph (unicode, 0, out glyph);
public bool TryGetVariationGlyph (uint unicode, out uint glyph)
{
fixed (uint* g = &glyph) {
return HarfBuzzApi.hb_font_get_variation_glyph (Handle, unicode, 0, g);
}
}
public bool TryGetVariationGlyph (int unicode, uint variationSelector, out uint glyph) =>
TryGetVariationGlyph ((uint)unicode, variationSelector, out glyph);
public bool TryGetVariationGlyph (uint unicode, uint variationSelector, out uint glyph)
{
fixed (uint* g = &glyph) {
return HarfBuzzApi.hb_font_get_variation_glyph (Handle, unicode, variationSelector, g);
}
}
public int GetHorizontalGlyphAdvance (uint glyph) =>
HarfBuzzApi.hb_font_get_glyph_h_advance (Handle, glyph);
public int GetVerticalGlyphAdvance (uint glyph) =>
HarfBuzzApi.hb_font_get_glyph_v_advance (Handle, glyph);
public unsafe int[] GetHorizontalGlyphAdvances (ReadOnlySpan<uint> glyphs)
{
fixed (uint* firstGlyph = glyphs) {
return GetHorizontalGlyphAdvances ((IntPtr)firstGlyph, glyphs.Length);
}
}
public unsafe int[] GetHorizontalGlyphAdvances (IntPtr firstGlyph, int count)
{
var advances = new int[count];
fixed (int* firstAdvance = advances) {
HarfBuzzApi.hb_font_get_glyph_h_advances (Handle, (uint)count, (uint*)firstGlyph, 4, firstAdvance, 4);
}
return advances;
}
public unsafe int[] GetVerticalGlyphAdvances (ReadOnlySpan<uint> glyphs)
{
fixed (uint* firstGlyph = glyphs) {
return GetVerticalGlyphAdvances ((IntPtr)firstGlyph, glyphs.Length);
}
}
public unsafe int[] GetVerticalGlyphAdvances (IntPtr firstGlyph, int count)
{
var advances = new int[count];
fixed (int* firstAdvance = advances) {
HarfBuzzApi.hb_font_get_glyph_v_advances (Handle, (uint)count, (uint*)firstGlyph, 4, firstAdvance, 4);
}
return advances;
}
public bool TryGetHorizontalGlyphOrigin (uint glyph, out int xOrigin, out int yOrigin)
{
fixed (int* x = &xOrigin)
fixed (int* y = &yOrigin) {
return HarfBuzzApi.hb_font_get_glyph_h_origin (Handle, glyph, x, y);
}
}
public bool TryGetVerticalGlyphOrigin (uint glyph, out int xOrigin, out int yOrigin)
{
fixed (int* x = &xOrigin)
fixed (int* y = &yOrigin) {
return HarfBuzzApi.hb_font_get_glyph_v_origin (Handle, glyph, x, y);
}
}
public int GetHorizontalGlyphKerning (uint leftGlyph, uint rightGlyph) =>
HarfBuzzApi.hb_font_get_glyph_h_kerning (Handle, leftGlyph, rightGlyph);
public bool TryGetGlyphExtents (uint glyph, out GlyphExtents extents)
{
fixed (GlyphExtents* e = &extents) {
return HarfBuzzApi.hb_font_get_glyph_extents (Handle, glyph, e);
}
}
public bool TryGetGlyphContourPoint (uint glyph, uint pointIndex, out int x, out int y)
{
fixed (int* xPtr = &x)
fixed (int* yPtr = &y) {
return HarfBuzzApi.hb_font_get_glyph_contour_point (Handle, glyph, pointIndex, xPtr, yPtr);
}
}
public unsafe bool TryGetGlyphName (uint glyph, out string name)
{
var pool = ArrayPool<byte>.Shared;
var buffer = pool.Rent (NameBufferLength);
try {
fixed (byte* first = buffer) {
if (!HarfBuzzApi.hb_font_get_glyph_name (Handle, glyph, first, (uint)buffer.Length)) {
name = string.Empty;
return false;
}
name = Marshal.PtrToStringAnsi ((IntPtr)first);
return true;
}
} finally {
pool.Return (buffer);
}
}
public bool TryGetGlyphFromName (string name, out uint glyph)
{
fixed (uint* g = &glyph) {
return HarfBuzzApi.hb_font_get_glyph_from_name (Handle, name, name.Length, g);
}
}
public bool TryGetGlyph (int unicode, out uint glyph) =>
TryGetGlyph ((uint)unicode, 0, out glyph);
public bool TryGetGlyph (uint unicode, out uint glyph) =>
TryGetGlyph (unicode, 0, out glyph);
public bool TryGetGlyph (int unicode, uint variationSelector, out uint glyph) =>
TryGetGlyph ((uint)unicode, variationSelector, out glyph);
public bool TryGetGlyph (uint unicode, uint variationSelector, out uint glyph)
{
fixed (uint* g = &glyph) {
return HarfBuzzApi.hb_font_get_glyph (Handle, unicode, variationSelector, g);
}
}
public FontExtents GetFontExtentsForDirection (Direction direction)
{
FontExtents extents;
HarfBuzzApi.hb_font_get_extents_for_direction (Handle, direction, &extents);
return extents;
}
public void GetGlyphAdvanceForDirection (uint glyph, Direction direction, out int x, out int y)
{
fixed (int* xPtr = &x)
fixed (int* yPtr = &y) {
HarfBuzzApi.hb_font_get_glyph_advance_for_direction (Handle, glyph, direction, xPtr, yPtr);
}
}
public unsafe int[] GetGlyphAdvancesForDirection (ReadOnlySpan<uint> glyphs, Direction direction)
{
fixed (uint* firstGlyph = glyphs) {
return GetGlyphAdvancesForDirection ((IntPtr)firstGlyph, glyphs.Length, direction);
}
}
public unsafe int[] GetGlyphAdvancesForDirection (IntPtr firstGlyph, int count, Direction direction)
{
var advances = new int[count];
fixed (int* firstAdvance = advances) {
HarfBuzzApi.hb_font_get_glyph_advances_for_direction (Handle, direction, (uint)count, (uint*)firstGlyph, 4, firstAdvance, 4);
}
return advances;
}
public bool TryGetGlyphContourPointForOrigin (uint glyph, uint pointIndex, Direction direction, out int x, out int y)
{
fixed (int* xPtr = &x)
fixed (int* yPtr = &y) {
return HarfBuzzApi.hb_font_get_glyph_contour_point_for_origin (Handle, glyph, pointIndex, direction, xPtr, yPtr);
}
}
public unsafe string GlyphToString (uint glyph)
{
var pool = ArrayPool<byte>.Shared;
var buffer = pool.Rent (NameBufferLength);
try {
fixed (byte* first = buffer) {
HarfBuzzApi.hb_font_glyph_to_string (Handle, glyph, first, (uint)buffer.Length);
return Marshal.PtrToStringAnsi ((IntPtr)first);
}
} finally {
pool.Return (buffer);
}
}
public bool TryGetGlyphFromString (string s, out uint glyph)
{
fixed (uint* g = &glyph) {
return HarfBuzzApi.hb_font_glyph_from_string (Handle, s, -1, g);
}
}
public void SetFunctionsOpenType () =>
HarfBuzzApi.hb_ot_font_set_funcs (Handle);
public void Shape (Buffer buffer, params Feature[] features) =>
Shape (buffer, features, null);
public void Shape (Buffer buffer, IReadOnlyList<Feature> features, IReadOnlyList<string> shapers)
{
if (buffer == null)
throw new ArgumentNullException (nameof (buffer));
if (buffer.Direction == Direction.Invalid)
throw new InvalidOperationException ("Buffer's Direction must be valid.");
if (buffer.ContentType != ContentType.Unicode) {
throw new InvalidOperationException ("Buffer's ContentType must of type Unicode.");
}
void*[] shapersPtrs = null;
if (shapers?.Count > 0) {
shapersPtrs = new void*[shapers.Count + 1];
int i;
for (i = 0; i < shapers.Count; i++) {
shapersPtrs[i] = (void*)Marshal.StringToHGlobalAnsi (shapers[i]);
}
shapersPtrs[i] = null;
}
var featuresArray = features?.ToArray ();
fixed (Feature* fPtr = featuresArray)
fixed (void** sPtr = shapersPtrs) {
HarfBuzzApi.hb_shape_full (
Handle,
buffer.Handle,
fPtr,
(uint)(features?.Count ?? 0),
sPtr);
}
if (shapersPtrs != null) {
for (var i = 0; i < shapersPtrs.Length; i++) {
if (shapersPtrs[i] != null)
Marshal.FreeHGlobal ((IntPtr)shapersPtrs[i]);
}
}
}
protected override void Dispose (bool disposing) =>
base.Dispose (disposing);
protected override void DisposeHandler ()
{
if (Handle != IntPtr.Zero) {
HarfBuzzApi.hb_font_destroy (Handle);
}
}
}
internal class FontUserData
{
public FontUserData (Font font, object fontData)
{
Font = font;
FontData = fontData;
}
public Font Font { get; }
public object FontData { get; }
}
}