Skip to content

Commit bf2e3cb

Browse files
committed
Add Typesetter tests for UnderAnnotation
1 parent 374a442 commit bf2e3cb

8 files changed

Lines changed: 7669 additions & 5442 deletions

File tree

.github/workflows/Nightly.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ jobs:
77
runs-on: windows-latest
88
permissions:
99
contents: write
10+
packages: write
1011
steps:
1112
- name: Update draft on GitHub Releases
1213
id: release_drafter

CSharpMath.Core.Example/BackEnd/JsonMathTable.cs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class JsonMathTable : FontMathTable<TFont, TGlyph> {
1414
/// typically loaded from a .json file.</summary>
1515
private readonly JToken _mathTable;
1616
private readonly JObject _constantsDictionary;
17-
private readonly JObject _assemblyTable;
17+
private readonly JObject _vAssemblyTable, _hAssemblyTable;
1818
private readonly JObject _italicTable;
1919
public TestFontMeasurer FontMeasurer { get; }
2020
public TestGlyphNameProvider GlyphNameProvider { get; }
@@ -41,7 +41,8 @@ JObject GetTable(string name) =>
4141
GlyphBoundsProvider = glyphBoundsProvider;
4242
_mathTable = mathTable;
4343
_constantsDictionary = GetTable("constants");
44-
_assemblyTable = GetTable("v_assembly");
44+
_vAssemblyTable = GetTable("v_assembly");
45+
_hAssemblyTable = GetTable("h_assembly");
4546
_italicTable = GetTable("italic");
4647
}
4748
// different from _ConstantFromTable in that the _ConstantFromTable requires
@@ -137,7 +138,18 @@ public override float RadicalExtraAscender(TFont font) =>
137138
private const string _extenderKey = "extender";
138139
private const string _glyphKey = "glyph";
139140
public override IEnumerable<GlyphPart<TGlyph>>? GetVerticalGlyphAssembly(TGlyph rawGlyph, TFont font) =>
140-
_assemblyTable[GlyphNameProvider.GetGlyphName(rawGlyph)]?[_assemblyPartsKey] is JArray parts
141+
_vAssemblyTable[GlyphNameProvider.GetGlyphName(rawGlyph)]?[_assemblyPartsKey] is JArray parts
142+
? parts.Select(partInfo =>
143+
new GlyphPart<TGlyph>(
144+
GlyphNameProvider.GetGlyph(partInfo[_glyphKey]!.Value<string>()!),
145+
FontUnitsToPt(font, partInfo[_advanceKey]!.Value<int>()),
146+
FontUnitsToPt(font, partInfo[_startConnectorKey]!.Value<int>()),
147+
FontUnitsToPt(font, partInfo[_endConnectorKey]!.Value<int>()),
148+
partInfo[_extenderKey]!.Value<bool>()))
149+
// Should have been defined, but let's return null
150+
: null;
151+
public override IEnumerable<GlyphPart<TGlyph>>? GetHorizontalGlyphAssembly(TGlyph rawGlyph, TFont font) =>
152+
_hAssemblyTable[GlyphNameProvider.GetGlyphName(rawGlyph)]?[_assemblyPartsKey] is JArray parts
141153
? parts.Select(partInfo =>
142154
new GlyphPart<TGlyph>(
143155
GlyphNameProvider.GetGlyph(partInfo[_glyphKey]!.Value<string>()!),
@@ -218,16 +230,5 @@ public override float GetTopAccentAdjustment(TFont font, TGlyph glyph) {
218230
return Total / 2;
219231
}
220232
}
221-
222-
public override IEnumerable<GlyphPart<TGlyph>>? GetHorizontalGlyphAssembly(TGlyph rawGlyph, TFont font) => _assemblyTable[GlyphNameProvider.GetGlyphName(rawGlyph)]?[_assemblyPartsKey] is JArray parts
223-
? parts.Select(partInfo =>
224-
new GlyphPart<TGlyph>(
225-
GlyphNameProvider.GetGlyph(partInfo[_glyphKey]!.Value<string>()!),
226-
FontUnitsToPt(font, partInfo[_advanceKey]!.Value<int>()),
227-
FontUnitsToPt(font, partInfo[_startConnectorKey]!.Value<int>()),
228-
FontUnitsToPt(font, partInfo[_endConnectorKey]!.Value<int>()),
229-
partInfo[_extenderKey]!.Value<bool>()))
230-
// Should have been defined, but let's return null
231-
: null;
232233
}
233234
}

CSharpMath.Core.Example/CSharpMath.Core.Example.csproj

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
<StartupObject>CSharpMath.Core.Checker</StartupObject>
66
</PropertyGroup>
77
<ItemGroup>
8-
<ProjectReference Include="..\CSharpMath\CSharpMath.csproj" />
9-
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
10-
<EmbeddedResource Include="Resources\latinmodern-math.json" />
8+
<ProjectReference Include="..\CSharpMath\CSharpMath.csproj" />
9+
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
10+
<EmbeddedResource Include="Resources\latinmodern-math.json" />
11+
<None Include="Resources\MathTableExport.py" />
1112
</ItemGroup>
1213
</Project>
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
# Based on https://github.com/kostub/iosMath/blob/master/fonts/math_table_to_plist.py
2+
# Added: get_h_assembly (version 1.3 -> 1.4)
3+
4+
import sys
5+
import json
6+
from fontTools.ttLib import TTFont
7+
8+
def process_font(font_file, out_file):
9+
font = TTFont(font_file)
10+
math_table = font['MATH'].table
11+
constants = get_constants(math_table)
12+
italic_c = get_italic_correction(math_table)
13+
v_variants = get_v_variants(math_table)
14+
h_variants = get_h_variants(math_table)
15+
v_assembly = get_v_assembly(math_table)
16+
h_assembly = get_h_assembly(math_table)
17+
accents = get_accent_attachments(math_table)
18+
pl = {
19+
"version" : "1.4",
20+
"constants": constants,
21+
"v_variants" : v_variants,
22+
"h_variants" : h_variants,
23+
"italic" : italic_c,
24+
"accents" : accents,
25+
"v_assembly" : v_assembly,
26+
"h_assembly" : h_assembly }
27+
ofile = open(out_file, 'w')
28+
json.dump(pl, ofile)
29+
ofile.close()
30+
31+
def get_constants(math_table):
32+
constants = math_table.MathConstants
33+
if constants is None:
34+
raise 'Cannot find MathConstants in MATH table'
35+
36+
int_consts = [ 'ScriptPercentScaleDown',
37+
'ScriptScriptPercentScaleDown',
38+
'DelimitedSubFormulaMinHeight',
39+
'DisplayOperatorMinHeight',
40+
'RadicalDegreeBottomRaisePercent']
41+
consts = { c : getattr(constants, c) for c in int_consts }
42+
43+
record_consts = [ 'MathLeading',
44+
'AxisHeight',
45+
'AccentBaseHeight',
46+
'FlattenedAccentBaseHeight',
47+
'SubscriptShiftDown',
48+
'SubscriptTopMax',
49+
'SubscriptBaselineDropMin',
50+
'SuperscriptShiftUp',
51+
'SuperscriptShiftUpCramped',
52+
'SuperscriptBottomMin',
53+
'SuperscriptBaselineDropMax',
54+
'SubSuperscriptGapMin',
55+
'SuperscriptBottomMaxWithSubscript',
56+
'SpaceAfterScript',
57+
'UpperLimitGapMin',
58+
'UpperLimitBaselineRiseMin',
59+
'LowerLimitGapMin',
60+
'LowerLimitBaselineDropMin',
61+
'StackTopShiftUp',
62+
'StackTopDisplayStyleShiftUp',
63+
'StackBottomShiftDown',
64+
'StackBottomDisplayStyleShiftDown',
65+
'StackGapMin',
66+
'StackDisplayStyleGapMin',
67+
'StretchStackTopShiftUp',
68+
'StretchStackBottomShiftDown',
69+
'StretchStackGapAboveMin',
70+
'StretchStackGapBelowMin',
71+
'FractionNumeratorShiftUp',
72+
'FractionNumeratorDisplayStyleShiftUp',
73+
'FractionDenominatorShiftDown',
74+
'FractionDenominatorDisplayStyleShiftDown',
75+
'FractionNumeratorGapMin',
76+
'FractionNumDisplayStyleGapMin',
77+
'FractionRuleThickness',
78+
'FractionDenominatorGapMin',
79+
'FractionDenomDisplayStyleGapMin',
80+
'SkewedFractionHorizontalGap',
81+
'SkewedFractionVerticalGap',
82+
'OverbarVerticalGap',
83+
'OverbarRuleThickness',
84+
'OverbarExtraAscender',
85+
'UnderbarVerticalGap',
86+
'UnderbarRuleThickness',
87+
'UnderbarExtraDescender',
88+
'RadicalVerticalGap',
89+
'RadicalDisplayStyleVerticalGap',
90+
'RadicalRuleThickness',
91+
'RadicalExtraAscender',
92+
'RadicalKernBeforeDegree',
93+
'RadicalKernAfterDegree',
94+
]
95+
consts_2 = { c : getattr(constants, c).Value for c in record_consts }
96+
consts.update(consts_2)
97+
98+
variants = math_table.MathVariants
99+
consts['MinConnectorOverlap'] = variants.MinConnectorOverlap
100+
return consts
101+
102+
def get_italic_correction(math_table):
103+
glyph_info = math_table.MathGlyphInfo
104+
if glyph_info is None:
105+
raise "Cannot find MathGlyphInfo in MATH table."
106+
italic = glyph_info.MathItalicsCorrectionInfo
107+
if italic is None:
108+
raise "Cannot find Italic Correction in GlyphInfo"
109+
110+
glyphs = italic.Coverage.glyphs
111+
count = italic.ItalicsCorrectionCount
112+
records = italic.ItalicsCorrection
113+
italic_dict = {}
114+
for i in range(count):
115+
name = glyphs[i]
116+
record = records[i]
117+
if record.DeviceTable is not None:
118+
raise "Don't know how to process device table for italic correction."
119+
italic_dict[name] = record.Value
120+
return italic_dict
121+
122+
def get_accent_attachments(math_table):
123+
glyph_info = math_table.MathGlyphInfo
124+
if glyph_info is None:
125+
raise "Cannot find MathGlyphInfo in MATH table."
126+
attach = glyph_info.MathTopAccentAttachment
127+
if attach is None:
128+
raise "Cannot find Top Accent Attachment in GlyphInfo"
129+
130+
glyphs = attach.TopAccentCoverage.glyphs
131+
count = attach.TopAccentAttachmentCount
132+
records = attach.TopAccentAttachment
133+
attach_dict = {}
134+
for i in range(count):
135+
name = glyphs[i]
136+
record = records[i]
137+
if record.DeviceTable is not None:
138+
raise "Don't know how to process device table for accent attachment."
139+
attach_dict[name] = record.Value
140+
return attach_dict
141+
142+
def get_v_variants(math_table):
143+
variants = math_table.MathVariants
144+
vglyphs = variants.VertGlyphCoverage.glyphs
145+
vconstruction = variants.VertGlyphConstruction
146+
count = variants.VertGlyphCount
147+
variant_dict = {}
148+
for i in range(count):
149+
name = vglyphs[i]
150+
record = vconstruction[i]
151+
glyph_variants = [x.VariantGlyph for x in
152+
record.MathGlyphVariantRecord]
153+
variant_dict[name] = glyph_variants
154+
return variant_dict
155+
156+
def get_h_variants(math_table):
157+
variants = math_table.MathVariants
158+
hglyphs = variants.HorizGlyphCoverage.glyphs
159+
hconstruction = variants.HorizGlyphConstruction
160+
count = variants.HorizGlyphCount
161+
variant_dict = {}
162+
for i in range(count):
163+
name = hglyphs[i]
164+
record = hconstruction[i]
165+
glyph_variants = [x.VariantGlyph for x in
166+
record.MathGlyphVariantRecord]
167+
variant_dict[name] = glyph_variants
168+
return variant_dict
169+
170+
def get_v_assembly(math_table):
171+
variants = math_table.MathVariants
172+
vglyphs = variants.VertGlyphCoverage.glyphs
173+
vconstruction = variants.VertGlyphConstruction
174+
count = variants.VertGlyphCount
175+
assembly_dict = {}
176+
for i in range(count):
177+
name = vglyphs[i]
178+
record = vconstruction[i]
179+
assembly = record.GlyphAssembly
180+
if assembly is not None:
181+
# There is an assembly for this glyph
182+
italic = assembly.ItalicsCorrection.Value
183+
parts = [part_dict(part) for part in assembly.PartRecords]
184+
assembly_dict[name] = {
185+
"italic" : assembly.ItalicsCorrection.Value,
186+
"parts" : parts }
187+
return assembly_dict
188+
189+
def get_h_assembly(math_table):
190+
variants = math_table.MathVariants
191+
hglyphs = variants.HorizGlyphCoverage.glyphs
192+
hconstruction = variants.HorizGlyphConstruction
193+
count = variants.HorizGlyphCount
194+
assembly_dict = {}
195+
for i in range(count):
196+
name = hglyphs[i]
197+
record = hconstruction[i]
198+
assembly = record.GlyphAssembly
199+
if assembly is not None:
200+
# There is an assembly for this glyph
201+
italic = assembly.ItalicsCorrection.Value
202+
parts = [part_dict(part) for part in assembly.PartRecords]
203+
assembly_dict[name] = {
204+
"italic" : assembly.ItalicsCorrection.Value,
205+
"parts" : parts }
206+
return assembly_dict
207+
208+
def part_dict(part):
209+
return {
210+
"glyph": part.glyph,
211+
"startConnector" : part.StartConnectorLength,
212+
"endConnector" : part.EndConnectorLength,
213+
"advance" : part.FullAdvance,
214+
"extender" : (part.PartFlags == 1) }
215+
216+
process_font('../../CSharpMath.Rendering/Reference Fonts/latinmodern-math.otf', 'latinmodern-math.json')

0 commit comments

Comments
 (0)