Skip to content

Commit

Permalink
[ENH] DirectWrite: GlyphRun improvements and example for AdvancedText…
Browse files Browse the repository at this point in the history
… rendering.
  • Loading branch information
amerkoleci committed Jun 1, 2021
1 parent ee0505a commit a624505
Show file tree
Hide file tree
Showing 11 changed files with 280 additions and 84 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Release: 1.9.77 (May 2021)
- [ENH] Dxc: Update to April 2021.
- [ENH] General: Move to standard types for Point, PointF, Size, SizeF, Rectangle and RectangleF.
- [ENH] Direct2D1: Improve mappings.
- [ENH] DirectWrite: GlyphRun improvements and example for AdvancedText rendering.

-----------------------------------------------
Release: 1.9.45 (April 2021)
Expand Down
131 changes: 64 additions & 67 deletions src/Vortice.Direct2D1/DirectWrite/GlyphRun.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Distributed under the MIT license. See the LICENSE file in the project root for more information.

using System;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SharpGen.Runtime;
Expand All @@ -11,14 +12,17 @@ namespace Vortice.DirectWrite
public partial class GlyphRun : IDisposable
{
public IDWriteFontFace? FontFace { set; get; }
public ushort[]? GlyphIndices { get; set; }
public float[]? GlyphAdvances { get; set; }
public GlyphOffset[]? GlyphOffsets { get; set; }
public ushort[]? Indices { get; set; }
public float[]? Advances { get; set; }
public GlyphOffset[]? Offsets { get; set; }

public void Dispose()
{
FontFace?.Dispose();
FontFace = null;
if (FontFace != null)
{
FontFace.Dispose();
FontFace = null;
}
}

#region Marshal
Expand Down Expand Up @@ -53,104 +57,97 @@ internal unsafe void __MarshalFree(ref __Native @ref)
internal unsafe void __MarshalFrom(ref __Native @ref)
{
FontFace = (@ref.FontFace == IntPtr.Zero) ? null : new IDWriteFontFace(@ref.FontFace);
FontFace?.AddRef();
if (FontFace != null)
((IUnknown)FontFace).AddRef();

FontEmSize = @ref.FontEmSize;
FontSize = @ref.FontEmSize;
GlyphCount = @ref.GlyphCount;
GlyphCount = @ref.GlyphCount;
GlyphIndices = null;
GlyphAdvances = null;
GlyphOffsets = null;
IsSideways = @ref.IsSideways;
BidiLevel = @ref.BidiLevel;

if (@ref.GlyphIndices != IntPtr.Zero)
{
GlyphIndices = new ushort[@ref.GlyphCount];
if (@ref.GlyphCount > 0)
fixed (void* indicesPtr = &GlyphIndices[0])
{
Unsafe.CopyBlock(indicesPtr, @ref.GlyphIndices.ToPointer(),
(uint)(sizeof(ushort) * @ref.GlyphCount));
}
Indices = new ushort[GlyphCount];
if (GlyphCount > 0)
UnsafeUtilities.Read(@ref.GlyphIndices, Indices, GlyphCount);
}

if (@ref.GlyphAdvances != IntPtr.Zero)
{
GlyphAdvances = new float[@ref.GlyphCount];
if (@ref.GlyphCount > 0)
fixed (void* advancesPtr = &GlyphAdvances[0])
{
Unsafe.CopyBlock(
advancesPtr,
@ref.GlyphAdvances.ToPointer(),
(uint)(sizeof(float) * @ref.GlyphCount));
}
Advances = new float[GlyphCount];
if (GlyphCount > 0)
UnsafeUtilities.Read(@ref.GlyphAdvances, Advances, GlyphCount);
}

if (@ref.GlyphOffsets != IntPtr.Zero)
{
GlyphOffsets = new GlyphOffset[@ref.GlyphCount];
if (@ref.GlyphCount > 0)
fixed (void* offsetsPtr = &GlyphOffsets[0])
{
Unsafe.CopyBlock(offsetsPtr, @ref.GlyphOffsets.ToPointer(), (uint)(sizeof(GlyphOffset) * @ref.GlyphCount));
}
Offsets = new GlyphOffset[GlyphCount];
if (GlyphCount > 0)
UnsafeUtilities.Read(@ref.GlyphOffsets, Offsets, GlyphCount);
}

IsSideways = @ref.IsSideways;
BidiLevel = @ref.BidiLevel;
}

internal unsafe void __MarshalTo(ref __Native @ref)
{
@ref.FontFace = FontFace == null ? IntPtr.Zero : FontFace.NativePointer;
@ref.FontEmSize = FontEmSize;
@ref.GlyphCount = GlyphCount;
@ref.FontEmSize = FontSize;
@ref.GlyphCount = -1;
@ref.GlyphIndices = IntPtr.Zero;
@ref.GlyphAdvances = IntPtr.Zero;
@ref.GlyphOffsets = IntPtr.Zero;
@ref.IsSideways = IsSideways;
@ref.BidiLevel = BidiLevel;

if (GlyphIndices != null)
if (Indices != null)
{
@ref.GlyphIndices = Marshal.AllocHGlobal(GlyphIndices.Length * sizeof(ushort));
if (GlyphCount > 0)
@ref.GlyphCount = Indices.Length;

@ref.GlyphIndices = Marshal.AllocHGlobal(Indices.Length * sizeof(ushort));
if (Indices.Length > 0)
{
fixed (void* glyphIndicesPtr = &GlyphIndices[0])
{
Unsafe.CopyBlock(@ref.GlyphIndices.ToPointer(),
glyphIndicesPtr,
(uint)(sizeof(ushort) * GlyphCount));
}
UnsafeUtilities.Write(@ref.GlyphIndices, Indices, 0, Indices.Length);
}

}

if (GlyphAdvances != null)
if (Advances != null)
{
@ref.GlyphAdvances = Marshal.AllocHGlobal(GlyphAdvances.Length * sizeof(float));
if (GlyphCount > 0)
if (@ref.GlyphCount >= 0 && @ref.GlyphCount != Advances.Length)
{
fixed (void* glyphAdvancesPtr = &GlyphAdvances[0])
{
Unsafe.CopyBlock(@ref.GlyphAdvances.ToPointer(),
glyphAdvancesPtr,
(uint)(sizeof(float) * GlyphCount));
}
throw new InvalidOperationException(
$"Invalid length for array Advances [{Advances.Length}] and Indices [{@ref.GlyphCount}]. Indices, Advances and Offsets array must have same size - or may be null"
);
}

@ref.GlyphCount = Advances.Length;
@ref.GlyphAdvances = Marshal.AllocHGlobal(Advances.Length * sizeof(float));
if (Advances.Length > 0)
{
UnsafeUtilities.Write(@ref.GlyphAdvances, Advances, 0, Advances.Length);
}
}

if (GlyphOffsets != null)
if (Offsets != null)
{
@ref.GlyphOffsets = Marshal.AllocHGlobal(GlyphOffsets.Length * sizeof(GlyphOffset));
if (GlyphCount > 0)
if (@ref.GlyphCount >= 0 && @ref.GlyphCount != Offsets.Length)
{
fixed (void* offsetsPtr = &GlyphOffsets[0])
{
Unsafe.CopyBlock(@ref.GlyphOffsets.ToPointer(),
offsetsPtr,
(uint)(sizeof(GlyphOffset) * GlyphCount));
}
throw new InvalidOperationException($"Invalid length for array Offsets [{Offsets.Length}]. Indices, Advances and Offsets array must have same size (Current is [{@ref.GlyphCount}]- or may be null");
}

@ref.GlyphCount = this.Offsets.Length;
@ref.GlyphOffsets = Marshal.AllocHGlobal(this.Offsets.Length * sizeof(GlyphOffset));
if (this.Offsets.Length > 0)
{
UnsafeUtilities.Write(@ref.GlyphOffsets, Offsets, 0, this.Offsets.Length);
}
}

if (@ref.GlyphCount < 0)
@ref.GlyphCount = 0;

// Update GlyphCount only for debug purpose
GlyphCount = @ref.GlyphCount;

@ref.IsSideways = this.IsSideways;
@ref.BidiLevel = this.BidiLevel;
}
#endregion Marshal
}
Expand Down
57 changes: 57 additions & 0 deletions src/Vortice.Direct2D1/DirectWrite/GlyphRunDescription.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (c) Amer Koleci and contributors.
// Distributed under the MIT license. See the LICENSE file in the project root for more information.

using System;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SharpGen.Runtime;

namespace Vortice.DirectWrite
{
public partial class GlyphRunDescription
{
#region Marshal
[StructLayout(LayoutKind.Sequential, Pack = 0)]
internal partial struct __Native
{
public IntPtr LocaleName;
public IntPtr Text;
public int TextLength;
public IntPtr ClusterMap;
public int TextPosition;

internal unsafe void __MarshalFree()
{
if (LocaleName != IntPtr.Zero)
Marshal.FreeHGlobal(LocaleName);
if (Text != IntPtr.Zero)
Marshal.FreeHGlobal(Text);
}
}

internal unsafe void __MarshalFree(ref __Native @ref)
{
@ref.__MarshalFree();
}

internal unsafe void __MarshalFrom(ref __Native @ref)
{
LocaleName = (@ref.LocaleName == IntPtr.Zero) ? null : Marshal.PtrToStringUni(@ref.LocaleName);
Text = (@ref.Text == IntPtr.Zero) ? null : Marshal.PtrToStringUni(@ref.Text, @ref.TextLength);
TextLength = @ref.TextLength;
ClusterMap = @ref.ClusterMap;
TextPosition = @ref.TextPosition;
}

internal unsafe void __MarshalTo(ref __Native @ref)
{
@ref.LocaleName = string.IsNullOrEmpty(LocaleName) ? IntPtr.Zero : Marshal.StringToHGlobalUni(LocaleName);
@ref.Text = string.IsNullOrEmpty(Text) ? IntPtr.Zero : Marshal.StringToHGlobalUni(Text);
@ref.TextLength = string.IsNullOrEmpty(Text) ? 0 : Text.Length;
@ref.ClusterMap = ClusterMap;
@ref.TextPosition = TextPosition;
}
#endregion Marshal
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) Amer Koleci and contributors.
// Distributed under the MIT license. See the LICENSE file in the project root for more information.

using System;
using System.Numerics;
using Vortice.DCommon;
using Vortice.Direct2D1;

namespace Vortice.DirectWrite
{
public partial class IDWriteColorGlyphRunEnumerator
{
public ColorGlyphRun CurrentRun => GetCurrentRun();

internal unsafe ColorGlyphRun GetCurrentRun()
{
ColorGlyphRun colorGlyphRun = default;
ColorGlyphRun.__Native* colorGlyphRun_ = (ColorGlyphRun.__Native*)GetCurrentRun_();
colorGlyphRun.__MarshalFrom(ref *colorGlyphRun_);
return colorGlyphRun;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) Amer Koleci and contributors.
// Distributed under the MIT license. See the LICENSE file in the project root for more information.

using System;
using System.Numerics;
using Vortice.DCommon;
using Vortice.Direct2D1;

namespace Vortice.DirectWrite
{
public partial class IDWriteColorGlyphRunEnumerator1
{
public new ColorGlyphRun1 CurrentRun => GetCurrentRun();

internal new unsafe ColorGlyphRun1 GetCurrentRun()
{
ColorGlyphRun1 colorGlyphRun = default;
ColorGlyphRun1.__Native* colorGlyphRun_ = (ColorGlyphRun1.__Native*)GetCurrentRun_();
colorGlyphRun.__MarshalFrom(ref *colorGlyphRun_);
return colorGlyphRun;
}
}
}
54 changes: 50 additions & 4 deletions src/Vortice.Direct2D1/DirectWrite/IDWriteFactory2.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
// Copyright (c) Amer Koleci and contributors.
// Distributed under the MIT license. See the LICENSE file in the project root for more information.

using System;
using System.Numerics;
using System.Drawing;
using SharpGen.Runtime;
using Vortice.DCommon;
using Vortice.Direct2D1;

namespace Vortice.DirectWrite
{
Expand All @@ -14,6 +13,38 @@ public IDWriteColorGlyphRunEnumerator TranslateColorGlyphRun(
float baselineOriginX,
float baselineOriginY,
GlyphRun glyphRun)
{
TranslateColorGlyphRun(
baselineOriginX,
baselineOriginY,
glyphRun,
null,
MeasuringMode.Natural,
null,
0,
out IDWriteColorGlyphRunEnumerator colorLayers).CheckError();
return colorLayers;
}

public IDWriteColorGlyphRunEnumerator TranslateColorGlyphRun(in PointF baselineOrigin, GlyphRun glyphRun)
{
TranslateColorGlyphRun(
baselineOrigin.X,
baselineOrigin.Y,
glyphRun,
null,
MeasuringMode.Natural,
null,
0,
out IDWriteColorGlyphRunEnumerator colorLayers).CheckError();
return colorLayers;
}

public Result TranslateColorGlyphRun(
float baselineOriginX,
float baselineOriginY,
GlyphRun glyphRun,
out IDWriteColorGlyphRunEnumerator colorLayers)
{
return TranslateColorGlyphRun(
baselineOriginX,
Expand All @@ -22,7 +53,22 @@ public IDWriteColorGlyphRunEnumerator TranslateColorGlyphRun(
null,
MeasuringMode.Natural,
null,
0);
0,
out colorLayers);
}

public Result TranslateColorGlyphRun(in PointF baselineOrigin, GlyphRun glyphRun,
out IDWriteColorGlyphRunEnumerator colorLayers)
{
return TranslateColorGlyphRun(
baselineOrigin.X,
baselineOrigin.Y,
glyphRun,
null,
MeasuringMode.Natural,
null,
0,
out colorLayers);
}
}
}
Loading

0 comments on commit a624505

Please sign in to comment.