Skip to content

Commit 3a26671

Browse files
committed
Wip
1 parent ffcfc32 commit 3a26671

20 files changed

Lines changed: 1262 additions & 227 deletions
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using Microsoft.ApplicationInsights.DataContracts;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Text;
6+
7+
namespace EPPlus.Fonts.OpenType.Tests.Reading
8+
{
9+
[TestClass]
10+
public class VerticalTextTests : FontTestBase
11+
{
12+
public override TestContext? TestContext { get; set; }
13+
14+
15+
[TestMethod]
16+
public void TestVerticalMetrics_Vhea()
17+
{
18+
var font = OpenTypeFonts.GetFontDataOpen(FontFolders, "BIZ UDGothic");
19+
Assert.IsNotNull(font);
20+
var vhea = font.VheaTable;
21+
Assert.IsNotNull(vhea, "vhea table should be present in a CJK font.");
22+
// Basic sanity checks on vhea values
23+
Assert.IsTrue(vhea.Ascent > 0, "Ascent should be positive.");
24+
Assert.IsTrue(vhea.AdvanceHeightMax > 0, "AdvanceHeightMax should be positive.");
25+
Assert.IsTrue(
26+
vhea.NumberOfVMetrics <= font.MaxpTable.numGlyphs,
27+
$"NumberOfVMetrics ({vhea.NumberOfVMetrics}) exceeds numGlyphs ({font.MaxpTable.numGlyphs}).");
28+
}
29+
30+
[TestMethod]
31+
public void TestVerticalMetrics_Vmtx()
32+
{
33+
var font = OpenTypeFonts.GetFontDataOpen(FontFolders, "BIZ UDGothic");
34+
Assert.IsNotNull(font);
35+
36+
var vhea = font.VheaTable;
37+
var vmtx = font.VmtxTable;
38+
Assert.IsNotNull(vmtx, "vmtx table should be present in a CJK font.");
39+
40+
// VMetrics count must match vhea.NumberOfVMetrics
41+
Assert.AreEqual(
42+
(int)vhea.NumberOfVMetrics,
43+
vmtx.VMetrics.Count,
44+
$"VMetrics.Count ({vmtx.VMetrics.Count}) should match vhea.NumberOfVMetrics ({vhea.NumberOfVMetrics}).");
45+
46+
// Total glyph coverage must equal maxp.numGlyphs
47+
int totalCoverage = vmtx.VMetrics.Count + vmtx.TopSideBearings.Count;
48+
Assert.AreEqual(
49+
font.MaxpTable.numGlyphs,
50+
totalCoverage,
51+
$"VMetrics ({vmtx.VMetrics.Count}) + TopSideBearings ({vmtx.TopSideBearings.Count}) should equal numGlyphs ({font.MaxpTable.numGlyphs}).");
52+
53+
// Majority of advance heights should be > 0 (some glyphs like .notdef may be 0)
54+
int zeroCount = 0;
55+
for (int i = 0; i < vmtx.VMetrics.Count; i++)
56+
{
57+
if (vmtx.VMetrics[i].AdvanceHeight == 0)
58+
zeroCount++;
59+
}
60+
Assert.IsTrue(
61+
zeroCount < vmtx.VMetrics.Count / 2,
62+
$"Too many zero AdvanceHeights: {zeroCount} out of {vmtx.VMetrics.Count}.");
63+
64+
// GetAdvanceHeight should work for first and last glyph
65+
Assert.IsTrue(vmtx.GetAdvanceHeight(0) > 0, "GetAdvanceHeight(0) should be > 0.");
66+
Assert.IsTrue(
67+
vmtx.GetAdvanceHeight((ushort)(font.MaxpTable.numGlyphs - 1)) > 0,
68+
"GetAdvanceHeight for last glyph should be > 0.");
69+
}
70+
}
71+
}

src/EPPlus.Fonts.OpenType/FontValidation/FontValidator.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ Date Author Change
2323
using EPPlus.Fonts.OpenType.Tables.Name;
2424
using EPPlus.Fonts.OpenType.Tables.Os2;
2525
using EPPlus.Fonts.OpenType.Tables.Post;
26+
using EPPlus.Fonts.OpenType.Tables.Vhea;
27+
using EPPlus.Fonts.OpenType.Tables.Vmtx;
2628
using System;
2729
using System.Collections.Generic;
2830

@@ -42,12 +44,14 @@ public FontValidator()
4244
_validators.Add(new HeadTableValidator());
4345
_validators.Add(new MaxpTableValidator());
4446
_validators.Add(new HheaTableValidator());
47+
_validators.Add(new VheaTableValidator());
4548
_validators.Add(new NameTableValidator());
4649
_validators.Add(new Os2TableValidator());
4750
_validators.Add(new PostTableValidator());
4851
_validators.Add(new CmapTableValidator());
4952
_validators.Add(new LocaTableValidator());
5053
_validators.Add(new HmtxTableValidator());
54+
_validators.Add(new VmtxTableValidator());
5155
_validators.Add(new GlyfTableValidator());
5256
_validators.Add(new GsubTableValidator());
5357
// Add more as needed...
@@ -56,12 +60,14 @@ public FontValidator()
5660
_tableAccessors.Add(typeof(HeadTable), delegate(OpenTypeFont font) { return font.HeadTable; });
5761
_tableAccessors.Add(typeof(MaxpTable), delegate(OpenTypeFont font) { return font.MaxpTable; });
5862
_tableAccessors.Add(typeof(HheaTable), delegate(OpenTypeFont font) { return font.HheaTable; });
63+
_tableAccessors.Add(typeof(VheaTable), delegate (OpenTypeFont font) { return font.VheaTable; });
5964
_tableAccessors.Add(typeof(NameTable), delegate(OpenTypeFont font) { return font.NameTable; });
6065
_tableAccessors.Add(typeof(Os2Table), delegate(OpenTypeFont font) { return font.Os2Table; });
6166
_tableAccessors.Add(typeof(PostTable), delegate (OpenTypeFont font) { return font.PostTable; });
6267
_tableAccessors.Add(typeof(CmapTable), delegate (OpenTypeFont font) { return font.CmapTable; });
6368
_tableAccessors.Add(typeof(LocaTable), delegate (OpenTypeFont font) { return font.LocaTable; });
6469
_tableAccessors.Add(typeof(HmtxTable), delegate (OpenTypeFont font) { return font.HmtxTable; });
70+
_tableAccessors.Add(typeof(VmtxTable), delegate (OpenTypeFont font) { return font.VmtxTable; });
6571
_tableAccessors.Add(typeof(GlyfTable), delegate (OpenTypeFont font) { return font.GlyfTable; });
6672
_tableAccessors.Add(typeof(GsubTable), delegate (OpenTypeFont font) { return font.GsubTable; });
6773
}

src/EPPlus.Fonts.OpenType/Integration/TextLayoutEngine.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ private List<string> WrapParagraph(
173173

174174
var charWidths = CalculateCharacterWidths(text, fontSize, options);
175175

176-
var state = new WrapState(startingWidthPoints, GetCachedSpaceWidth(fontSize, options));
176+
var state = new WrapStateText(startingWidthPoints, GetCachedSpaceWidth(fontSize, options));
177177

178178
PrepareLineBuilder(text.Length);
179179

src/EPPlus.Fonts.OpenType/OpenTypeFont.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ Date Author Change
2727
using EPPlus.Fonts.OpenType.Tables.Name;
2828
using EPPlus.Fonts.OpenType.Tables.Os2;
2929
using EPPlus.Fonts.OpenType.Tables.Post;
30+
using EPPlus.Fonts.OpenType.Tables.Vhea;
31+
using EPPlus.Fonts.OpenType.Tables.Vmtx;
3032
using System;
3133
using System.Collections.Generic;
3234
using System.Linq;
@@ -109,14 +111,22 @@ internal OpenTypeFont(byte[] fontBytes, long startOffset, FontFormat format)
109111
_kernTableLoader = TableRecords.ContainsKey(TableNames.Kern)
110112
? TableLoaders.GetKernTableLoader(_tblSettings)
111113
: null;
114+
_vheaTableLoader = TableRecords.ContainsKey(TableNames.Vhea)
115+
? TableLoaders.GetVheaTableLoader(_tblSettings)
116+
: null;
117+
_vmtxTableLoader = TableRecords.ContainsKey(TableNames.Vmtx)
118+
? TableLoaders.GetVmtxTableLoader(_tblSettings)
119+
: null;
112120
}
113121

114122
Os2TableLoader _os2TableLoader;
115123
NameTableLoader _nameTableLoader;
116124
HheaTableLoader _hheaTableLoader;
125+
VheaTableLoader _vheaTableLoader;
117126
HeadTableLoader _headTableLoader;
118127
CmapTableLoader _cmapTableLoader;
119128
HmtxTableLoader _hmtxTableLoader;
129+
VmtxTableLoader _vmtxTableLoader;
120130
MaxpTableLoader _maxpTableLoader;
121131
PostTableLoader _postTableLoader;
122132
LocaTableLoader _locaTableLoader;
@@ -190,6 +200,23 @@ public HheaTable HheaTable
190200
return null;
191201
}
192202
}
203+
204+
public VheaTable VheaTable
205+
{
206+
get
207+
{
208+
if (_vheaTableLoader != null)
209+
{
210+
return _vheaTableLoader.Load();
211+
}
212+
else if (_localTableCache.Contains(TableNames.Vhea))
213+
{
214+
return (VheaTable)_localTableCache.Get(TableNames.Vhea);
215+
}
216+
return null;
217+
}
218+
}
219+
193220
public HmtxTable HmtxTable
194221
{
195222
get
@@ -206,6 +233,23 @@ public HmtxTable HmtxTable
206233
}
207234

208235
}
236+
237+
public VmtxTable VmtxTable
238+
{
239+
get
240+
{
241+
if (_vmtxTableLoader != null)
242+
{
243+
return _vmtxTableLoader.Load();
244+
}
245+
else if (_localTableCache.Contains(TableNames.Vmtx))
246+
{
247+
return (VmtxTable)_localTableCache.Get(TableNames.Vmtx);
248+
}
249+
return null;
250+
}
251+
}
252+
209253
public MaxpTable MaxpTable
210254
{
211255
get

src/EPPlus.Fonts.OpenType/Tables/TableLoaderCache.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Date Author Change
2323
using EPPlus.Fonts.OpenType.Tables.Name;
2424
using EPPlus.Fonts.OpenType.Tables.Os2;
2525
using EPPlus.Fonts.OpenType.Tables.Post;
26+
using EPPlus.Fonts.OpenType.Tables.Vmtx;
2627

2728
namespace EPPlus.Fonts.OpenType.Tables
2829
{
@@ -40,8 +41,10 @@ internal class TableLoaderCache
4041
public GlyfTableLoader GlyfLoader;
4142
public Os2TableLoader Os2Loader;
4243
public HheaTableLoader HheaLoader;
44+
public VheaTableLoader VheaLoader;
4345
public MaxpTableLoader MaxpLoader;
4446
public HmtxTableLoader HmtxLoader;
47+
public VmtxTableLoader VmtxLoader;
4548
public NameTableLoader NameLoader;
4649
public KernTableLoader KernLoader;
4750
public PostTableLoader PostLoader;

src/EPPlus.Fonts.OpenType/Tables/TableLoaders.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Date Author Change
2424
using EPPlus.Fonts.OpenType.Tables.Name;
2525
using EPPlus.Fonts.OpenType.Tables.Os2;
2626
using EPPlus.Fonts.OpenType.Tables.Post;
27+
using EPPlus.Fonts.OpenType.Tables.Vmtx;
2728

2829
namespace EPPlus.Fonts.OpenType.Tables
2930
{
@@ -107,6 +108,19 @@ public static HheaTableLoader GetHheaTableLoader(TableLoaderSettings settings)
107108
}
108109
}
109110

111+
public static VheaTableLoader GetVheaTableLoader(TableLoaderSettings settings)
112+
{
113+
var cache = settings._loaderCacheRef;
114+
lock (cache.SyncLock)
115+
{
116+
if (cache.VheaLoader == null)
117+
{
118+
cache.VheaLoader = new VheaTableLoader(settings);
119+
}
120+
return cache.VheaLoader;
121+
}
122+
}
123+
110124
public static MaxpTableLoader GetMaxpTableLoader(TableLoaderSettings settings)
111125
{
112126
var cache = settings._loaderCacheRef;
@@ -133,6 +147,19 @@ public static HmtxTableLoader GetHmtxTableLoader(TableLoaderSettings settings)
133147
}
134148
}
135149

150+
public static VmtxTableLoader GetVmtxTableLoader(TableLoaderSettings settings)
151+
{
152+
var cache = settings._loaderCacheRef;
153+
lock (cache.SyncLock)
154+
{
155+
if (cache.VmtxLoader == null)
156+
{
157+
cache.VmtxLoader = new VmtxTableLoader(settings);
158+
}
159+
return cache.VmtxLoader;
160+
}
161+
}
162+
136163
public static NameTableLoader GetNameTableLoader(TableLoaderSettings settings)
137164
{
138165
var cache = settings._loaderCacheRef;

src/EPPlus.Fonts.OpenType/Tables/TableNames.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ internal static class TableNames
2020
public const string Os2 = "OS/2";
2121
public const string Hhea = "hhea";
2222
public const string Hmtx = "hmtx";
23+
public const string Vhea = "vhea";
24+
public const string Vmtx = "vmtx";
2325
public const string Maxp = "maxp";
2426
public const string Name = "name";
2527
public const string Kern = "kern";

0 commit comments

Comments
 (0)