Skip to content

Commit a624505

Browse files
committed
[ENH] DirectWrite: GlyphRun improvements and example for AdvancedText rendering.
1 parent ee0505a commit a624505

11 files changed

+280
-84
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Release: 1.9.77 (May 2021)
1313
- [ENH] Dxc: Update to April 2021.
1414
- [ENH] General: Move to standard types for Point, PointF, Size, SizeF, Rectangle and RectangleF.
1515
- [ENH] Direct2D1: Improve mappings.
16+
- [ENH] DirectWrite: GlyphRun improvements and example for AdvancedText rendering.
1617

1718
-----------------------------------------------
1819
Release: 1.9.45 (April 2021)

src/Vortice.Direct2D1/DirectWrite/GlyphRun.cs

+64-67
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Distributed under the MIT license. See the LICENSE file in the project root for more information.
33

44
using System;
5+
using System.Globalization;
56
using System.Runtime.CompilerServices;
67
using System.Runtime.InteropServices;
78
using SharpGen.Runtime;
@@ -11,14 +12,17 @@ namespace Vortice.DirectWrite
1112
public partial class GlyphRun : IDisposable
1213
{
1314
public IDWriteFontFace? FontFace { set; get; }
14-
public ushort[]? GlyphIndices { get; set; }
15-
public float[]? GlyphAdvances { get; set; }
16-
public GlyphOffset[]? GlyphOffsets { get; set; }
15+
public ushort[]? Indices { get; set; }
16+
public float[]? Advances { get; set; }
17+
public GlyphOffset[]? Offsets { get; set; }
1718

1819
public void Dispose()
1920
{
20-
FontFace?.Dispose();
21-
FontFace = null;
21+
if (FontFace != null)
22+
{
23+
FontFace.Dispose();
24+
FontFace = null;
25+
}
2226
}
2327

2428
#region Marshal
@@ -53,104 +57,97 @@ internal unsafe void __MarshalFree(ref __Native @ref)
5357
internal unsafe void __MarshalFrom(ref __Native @ref)
5458
{
5559
FontFace = (@ref.FontFace == IntPtr.Zero) ? null : new IDWriteFontFace(@ref.FontFace);
56-
FontFace?.AddRef();
60+
if (FontFace != null)
61+
((IUnknown)FontFace).AddRef();
5762

58-
FontEmSize = @ref.FontEmSize;
63+
FontSize = @ref.FontEmSize;
64+
GlyphCount = @ref.GlyphCount;
5965
GlyphCount = @ref.GlyphCount;
60-
GlyphIndices = null;
61-
GlyphAdvances = null;
62-
GlyphOffsets = null;
63-
IsSideways = @ref.IsSideways;
64-
BidiLevel = @ref.BidiLevel;
65-
6666
if (@ref.GlyphIndices != IntPtr.Zero)
6767
{
68-
GlyphIndices = new ushort[@ref.GlyphCount];
69-
if (@ref.GlyphCount > 0)
70-
fixed (void* indicesPtr = &GlyphIndices[0])
71-
{
72-
Unsafe.CopyBlock(indicesPtr, @ref.GlyphIndices.ToPointer(),
73-
(uint)(sizeof(ushort) * @ref.GlyphCount));
74-
}
68+
Indices = new ushort[GlyphCount];
69+
if (GlyphCount > 0)
70+
UnsafeUtilities.Read(@ref.GlyphIndices, Indices, GlyphCount);
7571
}
7672

7773
if (@ref.GlyphAdvances != IntPtr.Zero)
7874
{
79-
GlyphAdvances = new float[@ref.GlyphCount];
80-
if (@ref.GlyphCount > 0)
81-
fixed (void* advancesPtr = &GlyphAdvances[0])
82-
{
83-
Unsafe.CopyBlock(
84-
advancesPtr,
85-
@ref.GlyphAdvances.ToPointer(),
86-
(uint)(sizeof(float) * @ref.GlyphCount));
87-
}
75+
Advances = new float[GlyphCount];
76+
if (GlyphCount > 0)
77+
UnsafeUtilities.Read(@ref.GlyphAdvances, Advances, GlyphCount);
8878
}
8979

9080
if (@ref.GlyphOffsets != IntPtr.Zero)
9181
{
92-
GlyphOffsets = new GlyphOffset[@ref.GlyphCount];
93-
if (@ref.GlyphCount > 0)
94-
fixed (void* offsetsPtr = &GlyphOffsets[0])
95-
{
96-
Unsafe.CopyBlock(offsetsPtr, @ref.GlyphOffsets.ToPointer(), (uint)(sizeof(GlyphOffset) * @ref.GlyphCount));
97-
}
82+
Offsets = new GlyphOffset[GlyphCount];
83+
if (GlyphCount > 0)
84+
UnsafeUtilities.Read(@ref.GlyphOffsets, Offsets, GlyphCount);
9885
}
86+
87+
IsSideways = @ref.IsSideways;
88+
BidiLevel = @ref.BidiLevel;
9989
}
10090

10191
internal unsafe void __MarshalTo(ref __Native @ref)
10292
{
10393
@ref.FontFace = FontFace == null ? IntPtr.Zero : FontFace.NativePointer;
104-
@ref.FontEmSize = FontEmSize;
105-
@ref.GlyphCount = GlyphCount;
94+
@ref.FontEmSize = FontSize;
95+
@ref.GlyphCount = -1;
10696
@ref.GlyphIndices = IntPtr.Zero;
10797
@ref.GlyphAdvances = IntPtr.Zero;
10898
@ref.GlyphOffsets = IntPtr.Zero;
109-
@ref.IsSideways = IsSideways;
110-
@ref.BidiLevel = BidiLevel;
11199

112-
if (GlyphIndices != null)
100+
if (Indices != null)
113101
{
114-
@ref.GlyphIndices = Marshal.AllocHGlobal(GlyphIndices.Length * sizeof(ushort));
115-
if (GlyphCount > 0)
102+
@ref.GlyphCount = Indices.Length;
103+
104+
@ref.GlyphIndices = Marshal.AllocHGlobal(Indices.Length * sizeof(ushort));
105+
if (Indices.Length > 0)
116106
{
117-
fixed (void* glyphIndicesPtr = &GlyphIndices[0])
118-
{
119-
Unsafe.CopyBlock(@ref.GlyphIndices.ToPointer(),
120-
glyphIndicesPtr,
121-
(uint)(sizeof(ushort) * GlyphCount));
122-
}
107+
UnsafeUtilities.Write(@ref.GlyphIndices, Indices, 0, Indices.Length);
123108
}
124-
125109
}
126110

127-
if (GlyphAdvances != null)
111+
if (Advances != null)
128112
{
129-
@ref.GlyphAdvances = Marshal.AllocHGlobal(GlyphAdvances.Length * sizeof(float));
130-
if (GlyphCount > 0)
113+
if (@ref.GlyphCount >= 0 && @ref.GlyphCount != Advances.Length)
131114
{
132-
fixed (void* glyphAdvancesPtr = &GlyphAdvances[0])
133-
{
134-
Unsafe.CopyBlock(@ref.GlyphAdvances.ToPointer(),
135-
glyphAdvancesPtr,
136-
(uint)(sizeof(float) * GlyphCount));
137-
}
115+
throw new InvalidOperationException(
116+
$"Invalid length for array Advances [{Advances.Length}] and Indices [{@ref.GlyphCount}]. Indices, Advances and Offsets array must have same size - or may be null"
117+
);
118+
}
119+
120+
@ref.GlyphCount = Advances.Length;
121+
@ref.GlyphAdvances = Marshal.AllocHGlobal(Advances.Length * sizeof(float));
122+
if (Advances.Length > 0)
123+
{
124+
UnsafeUtilities.Write(@ref.GlyphAdvances, Advances, 0, Advances.Length);
138125
}
139126
}
140127

141-
if (GlyphOffsets != null)
128+
if (Offsets != null)
142129
{
143-
@ref.GlyphOffsets = Marshal.AllocHGlobal(GlyphOffsets.Length * sizeof(GlyphOffset));
144-
if (GlyphCount > 0)
130+
if (@ref.GlyphCount >= 0 && @ref.GlyphCount != Offsets.Length)
145131
{
146-
fixed (void* offsetsPtr = &GlyphOffsets[0])
147-
{
148-
Unsafe.CopyBlock(@ref.GlyphOffsets.ToPointer(),
149-
offsetsPtr,
150-
(uint)(sizeof(GlyphOffset) * GlyphCount));
151-
}
132+
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");
133+
}
134+
135+
@ref.GlyphCount = this.Offsets.Length;
136+
@ref.GlyphOffsets = Marshal.AllocHGlobal(this.Offsets.Length * sizeof(GlyphOffset));
137+
if (this.Offsets.Length > 0)
138+
{
139+
UnsafeUtilities.Write(@ref.GlyphOffsets, Offsets, 0, this.Offsets.Length);
152140
}
153141
}
142+
143+
if (@ref.GlyphCount < 0)
144+
@ref.GlyphCount = 0;
145+
146+
// Update GlyphCount only for debug purpose
147+
GlyphCount = @ref.GlyphCount;
148+
149+
@ref.IsSideways = this.IsSideways;
150+
@ref.BidiLevel = this.BidiLevel;
154151
}
155152
#endregion Marshal
156153
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright (c) Amer Koleci and contributors.
2+
// Distributed under the MIT license. See the LICENSE file in the project root for more information.
3+
4+
using System;
5+
using System.Globalization;
6+
using System.Runtime.CompilerServices;
7+
using System.Runtime.InteropServices;
8+
using SharpGen.Runtime;
9+
10+
namespace Vortice.DirectWrite
11+
{
12+
public partial class GlyphRunDescription
13+
{
14+
#region Marshal
15+
[StructLayout(LayoutKind.Sequential, Pack = 0)]
16+
internal partial struct __Native
17+
{
18+
public IntPtr LocaleName;
19+
public IntPtr Text;
20+
public int TextLength;
21+
public IntPtr ClusterMap;
22+
public int TextPosition;
23+
24+
internal unsafe void __MarshalFree()
25+
{
26+
if (LocaleName != IntPtr.Zero)
27+
Marshal.FreeHGlobal(LocaleName);
28+
if (Text != IntPtr.Zero)
29+
Marshal.FreeHGlobal(Text);
30+
}
31+
}
32+
33+
internal unsafe void __MarshalFree(ref __Native @ref)
34+
{
35+
@ref.__MarshalFree();
36+
}
37+
38+
internal unsafe void __MarshalFrom(ref __Native @ref)
39+
{
40+
LocaleName = (@ref.LocaleName == IntPtr.Zero) ? null : Marshal.PtrToStringUni(@ref.LocaleName);
41+
Text = (@ref.Text == IntPtr.Zero) ? null : Marshal.PtrToStringUni(@ref.Text, @ref.TextLength);
42+
TextLength = @ref.TextLength;
43+
ClusterMap = @ref.ClusterMap;
44+
TextPosition = @ref.TextPosition;
45+
}
46+
47+
internal unsafe void __MarshalTo(ref __Native @ref)
48+
{
49+
@ref.LocaleName = string.IsNullOrEmpty(LocaleName) ? IntPtr.Zero : Marshal.StringToHGlobalUni(LocaleName);
50+
@ref.Text = string.IsNullOrEmpty(Text) ? IntPtr.Zero : Marshal.StringToHGlobalUni(Text);
51+
@ref.TextLength = string.IsNullOrEmpty(Text) ? 0 : Text.Length;
52+
@ref.ClusterMap = ClusterMap;
53+
@ref.TextPosition = TextPosition;
54+
}
55+
#endregion Marshal
56+
}
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright (c) Amer Koleci and contributors.
2+
// Distributed under the MIT license. See the LICENSE file in the project root for more information.
3+
4+
using System;
5+
using System.Numerics;
6+
using Vortice.DCommon;
7+
using Vortice.Direct2D1;
8+
9+
namespace Vortice.DirectWrite
10+
{
11+
public partial class IDWriteColorGlyphRunEnumerator
12+
{
13+
public ColorGlyphRun CurrentRun => GetCurrentRun();
14+
15+
internal unsafe ColorGlyphRun GetCurrentRun()
16+
{
17+
ColorGlyphRun colorGlyphRun = default;
18+
ColorGlyphRun.__Native* colorGlyphRun_ = (ColorGlyphRun.__Native*)GetCurrentRun_();
19+
colorGlyphRun.__MarshalFrom(ref *colorGlyphRun_);
20+
return colorGlyphRun;
21+
}
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright (c) Amer Koleci and contributors.
2+
// Distributed under the MIT license. See the LICENSE file in the project root for more information.
3+
4+
using System;
5+
using System.Numerics;
6+
using Vortice.DCommon;
7+
using Vortice.Direct2D1;
8+
9+
namespace Vortice.DirectWrite
10+
{
11+
public partial class IDWriteColorGlyphRunEnumerator1
12+
{
13+
public new ColorGlyphRun1 CurrentRun => GetCurrentRun();
14+
15+
internal new unsafe ColorGlyphRun1 GetCurrentRun()
16+
{
17+
ColorGlyphRun1 colorGlyphRun = default;
18+
ColorGlyphRun1.__Native* colorGlyphRun_ = (ColorGlyphRun1.__Native*)GetCurrentRun_();
19+
colorGlyphRun.__MarshalFrom(ref *colorGlyphRun_);
20+
return colorGlyphRun;
21+
}
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
// Copyright (c) Amer Koleci and contributors.
22
// Distributed under the MIT license. See the LICENSE file in the project root for more information.
33

4-
using System;
5-
using System.Numerics;
4+
using System.Drawing;
5+
using SharpGen.Runtime;
66
using Vortice.DCommon;
7-
using Vortice.Direct2D1;
87

98
namespace Vortice.DirectWrite
109
{
@@ -14,6 +13,38 @@ public IDWriteColorGlyphRunEnumerator TranslateColorGlyphRun(
1413
float baselineOriginX,
1514
float baselineOriginY,
1615
GlyphRun glyphRun)
16+
{
17+
TranslateColorGlyphRun(
18+
baselineOriginX,
19+
baselineOriginY,
20+
glyphRun,
21+
null,
22+
MeasuringMode.Natural,
23+
null,
24+
0,
25+
out IDWriteColorGlyphRunEnumerator colorLayers).CheckError();
26+
return colorLayers;
27+
}
28+
29+
public IDWriteColorGlyphRunEnumerator TranslateColorGlyphRun(in PointF baselineOrigin, GlyphRun glyphRun)
30+
{
31+
TranslateColorGlyphRun(
32+
baselineOrigin.X,
33+
baselineOrigin.Y,
34+
glyphRun,
35+
null,
36+
MeasuringMode.Natural,
37+
null,
38+
0,
39+
out IDWriteColorGlyphRunEnumerator colorLayers).CheckError();
40+
return colorLayers;
41+
}
42+
43+
public Result TranslateColorGlyphRun(
44+
float baselineOriginX,
45+
float baselineOriginY,
46+
GlyphRun glyphRun,
47+
out IDWriteColorGlyphRunEnumerator colorLayers)
1748
{
1849
return TranslateColorGlyphRun(
1950
baselineOriginX,
@@ -22,7 +53,22 @@ public IDWriteColorGlyphRunEnumerator TranslateColorGlyphRun(
2253
null,
2354
MeasuringMode.Natural,
2455
null,
25-
0);
56+
0,
57+
out colorLayers);
58+
}
59+
60+
public Result TranslateColorGlyphRun(in PointF baselineOrigin, GlyphRun glyphRun,
61+
out IDWriteColorGlyphRunEnumerator colorLayers)
62+
{
63+
return TranslateColorGlyphRun(
64+
baselineOrigin.X,
65+
baselineOrigin.Y,
66+
glyphRun,
67+
null,
68+
MeasuringMode.Natural,
69+
null,
70+
0,
71+
out colorLayers);
2672
}
2773
}
2874
}

0 commit comments

Comments
 (0)