[otlLib] Support building MATH table
This commit is contained in:
parent
a7a0f41c90
commit
0f953cccd8
@ -1,6 +1,7 @@
|
|||||||
from collections import namedtuple, OrderedDict
|
from collections import namedtuple, OrderedDict
|
||||||
import os
|
import os
|
||||||
from fontTools.misc.fixedTools import fixedToFloat
|
from fontTools.misc.fixedTools import fixedToFloat
|
||||||
|
from fontTools.misc.roundTools import otRound
|
||||||
from fontTools import ttLib
|
from fontTools import ttLib
|
||||||
from fontTools.ttLib.tables import otTables as ot
|
from fontTools.ttLib.tables import otTables as ot
|
||||||
from fontTools.ttLib.tables.otBase import (
|
from fontTools.ttLib.tables.otBase import (
|
||||||
@ -2906,3 +2907,201 @@ def _addName(ttFont, value, minNameID=0, windows=True, mac=True):
|
|||||||
return nameTable.addMultilingualName(
|
return nameTable.addMultilingualName(
|
||||||
names, ttFont=ttFont, windows=windows, mac=mac, minNameID=minNameID
|
names, ttFont=ttFont, windows=windows, mac=mac, minNameID=minNameID
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def buildMathTable(
|
||||||
|
ttFont,
|
||||||
|
constants=None,
|
||||||
|
italicsCorrections=None,
|
||||||
|
topAccentAttachments=None,
|
||||||
|
extendedShapes=None,
|
||||||
|
mathKerns=None,
|
||||||
|
minConnectorOverlap=0,
|
||||||
|
vertGlyphVariants=None,
|
||||||
|
horizGlyphVariants=None,
|
||||||
|
vertGlyphAssembly=None,
|
||||||
|
horizGlyphAssembly=None,
|
||||||
|
):
|
||||||
|
glyphMap = ttFont.getReverseGlyphMap()
|
||||||
|
|
||||||
|
ttFont["MATH"] = math = ttLib.newTable("MATH")
|
||||||
|
math.table = table = ot.MATH()
|
||||||
|
table.Version = 0x00010000
|
||||||
|
table.populateDefaults()
|
||||||
|
|
||||||
|
table.MathConstants = _buildMathConstants(constants)
|
||||||
|
table.MathGlyphInfo = _buildMathGlyphInfo(
|
||||||
|
glyphMap,
|
||||||
|
italicsCorrections,
|
||||||
|
topAccentAttachments,
|
||||||
|
extendedShapes,
|
||||||
|
mathKerns,
|
||||||
|
)
|
||||||
|
table.MathVariants = _buildMathVariants(
|
||||||
|
glyphMap,
|
||||||
|
minConnectorOverlap,
|
||||||
|
vertGlyphVariants,
|
||||||
|
horizGlyphVariants,
|
||||||
|
vertGlyphAssembly,
|
||||||
|
horizGlyphAssembly,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _buildMathConstants(constants):
|
||||||
|
if not constants:
|
||||||
|
return None
|
||||||
|
|
||||||
|
mathConstants = ot.MathConstants()
|
||||||
|
for conv in mathConstants.getConverters():
|
||||||
|
value = otRound(constants.get(conv.name, 0))
|
||||||
|
if conv.tableClass:
|
||||||
|
assert issubclass(conv.tableClass, ot.MathValueRecord)
|
||||||
|
value = _mathValueRecord(value)
|
||||||
|
setattr(mathConstants, conv.name, value)
|
||||||
|
return mathConstants
|
||||||
|
|
||||||
|
|
||||||
|
def _buildMathGlyphInfo(
|
||||||
|
glyphMap,
|
||||||
|
italicsCorrections,
|
||||||
|
topAccentAttachments,
|
||||||
|
extendedShapes,
|
||||||
|
mathKerns,
|
||||||
|
):
|
||||||
|
if not any([extendedShapes, italicsCorrections, topAccentAttachments, mathKerns]):
|
||||||
|
return None
|
||||||
|
|
||||||
|
info = ot.MathGlyphInfo()
|
||||||
|
info.populateDefaults()
|
||||||
|
|
||||||
|
if italicsCorrections:
|
||||||
|
coverage = buildCoverage(italicsCorrections.keys(), glyphMap)
|
||||||
|
info.MathItalicsCorrectionInfo = ot.MathItalicsCorrectionInfo()
|
||||||
|
info.MathItalicsCorrectionInfo.Coverage = coverage
|
||||||
|
info.MathItalicsCorrectionInfo.ItalicsCorrectionCount = len(coverage.glyphs)
|
||||||
|
info.MathItalicsCorrectionInfo.ItalicsCorrection = [
|
||||||
|
_mathValueRecord(italicsCorrections[n]) for n in coverage.glyphs
|
||||||
|
]
|
||||||
|
|
||||||
|
if topAccentAttachments:
|
||||||
|
coverage = buildCoverage(topAccentAttachments.keys(), glyphMap)
|
||||||
|
info.MathTopAccentAttachment = ot.MathTopAccentAttachment()
|
||||||
|
info.MathTopAccentAttachment.TopAccentCoverage = coverage
|
||||||
|
info.MathTopAccentAttachment.TopAccentAttachmentCount = len(coverage.glyphs)
|
||||||
|
info.MathTopAccentAttachment.TopAccentAttachment = [
|
||||||
|
_mathValueRecord(topAccentAttachments[n]) for n in coverage.glyphs
|
||||||
|
]
|
||||||
|
|
||||||
|
if extendedShapes:
|
||||||
|
info.ExtendedShapeCoverage = buildCoverage(extendedShapes, glyphMap)
|
||||||
|
|
||||||
|
if mathKerns:
|
||||||
|
coverage = buildCoverage(mathKerns.keys(), glyphMap)
|
||||||
|
info.MathKernInfo = ot.MathKernInfo()
|
||||||
|
info.MathKernInfo.MathKernCoverage = coverage
|
||||||
|
info.MathKernInfo.MathKernCount = len(coverage.glyphs)
|
||||||
|
info.MathKernInfo.MathKernInfoRecords = []
|
||||||
|
for glyph in coverage.glyphs:
|
||||||
|
record = ot.MathKernInfoRecord()
|
||||||
|
for side in {"TopRight", "TopLeft", "BottomRight", "BottomLeft"}:
|
||||||
|
if side in mathKerns[glyph]:
|
||||||
|
correctionHeights, kernValues = mathKerns[glyph][side]
|
||||||
|
assert len(correctionHeights) == len(kernValues) - 1
|
||||||
|
kern = ot.MathKern()
|
||||||
|
kern.HeightCount = len(correctionHeights)
|
||||||
|
kern.CorrectionHeight = [
|
||||||
|
_mathValueRecord(h) for h in correctionHeights
|
||||||
|
]
|
||||||
|
kern.KernValue = [_mathValueRecord(v) for v in kernValues]
|
||||||
|
setattr(record, f"{side}MathKern", kern)
|
||||||
|
info.MathKernInfo.MathKernInfoRecords.append(record)
|
||||||
|
|
||||||
|
return info
|
||||||
|
|
||||||
|
|
||||||
|
def _buildMathVariants(
|
||||||
|
glyphMap,
|
||||||
|
minConnectorOverlap,
|
||||||
|
vertGlyphVariants,
|
||||||
|
horizGlyphVariants,
|
||||||
|
vertGlyphAssembly,
|
||||||
|
horizGlyphAssembly,
|
||||||
|
):
|
||||||
|
if not any(
|
||||||
|
[vertGlyphVariants, horizGlyphVariants, vertGlyphAssembly, horizGlyphAssembly]
|
||||||
|
):
|
||||||
|
return None
|
||||||
|
|
||||||
|
variants = ot.MathVariants()
|
||||||
|
variants.populateDefaults()
|
||||||
|
|
||||||
|
variants.MinConnectorOverlap = minConnectorOverlap
|
||||||
|
|
||||||
|
if vertGlyphVariants or vertGlyphAssembly:
|
||||||
|
variants.VertGlyphCoverage, variants.VertGlyphConstruction = (
|
||||||
|
_buildMathGlyphConstruction(
|
||||||
|
glyphMap,
|
||||||
|
vertGlyphVariants,
|
||||||
|
vertGlyphAssembly,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if horizGlyphVariants or horizGlyphAssembly:
|
||||||
|
variants.HorizGlyphCoverage, variants.HorizGlyphConstruction = (
|
||||||
|
_buildMathGlyphConstruction(
|
||||||
|
glyphMap,
|
||||||
|
horizGlyphVariants,
|
||||||
|
horizGlyphAssembly,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return variants
|
||||||
|
|
||||||
|
|
||||||
|
def _buildMathGlyphConstruction(glyphMap, variants, assemblies):
|
||||||
|
glyphs = set()
|
||||||
|
if variants:
|
||||||
|
glyphs.update(variants.keys())
|
||||||
|
if assemblies:
|
||||||
|
glyphs.update(assemblies.keys())
|
||||||
|
coverage = buildCoverage(glyphs, glyphMap)
|
||||||
|
constructions = []
|
||||||
|
|
||||||
|
for glyphName in coverage.glyphs:
|
||||||
|
construction = ot.MathGlyphConstruction()
|
||||||
|
construction.populateDefaults()
|
||||||
|
|
||||||
|
if variants and glyphName in variants:
|
||||||
|
construction.VariantCount = len(variants[glyphName])
|
||||||
|
construction.MathGlyphVariantRecord = []
|
||||||
|
for variantName, advance in variants[glyphName]:
|
||||||
|
record = ot.MathGlyphVariantRecord()
|
||||||
|
record.VariantGlyph = variantName
|
||||||
|
record.AdvanceMeasurement = otRound(advance)
|
||||||
|
construction.MathGlyphVariantRecord.append(record)
|
||||||
|
|
||||||
|
if assemblies and glyphName in assemblies:
|
||||||
|
parts, ic = assemblies[glyphName]
|
||||||
|
construction.GlyphAssembly = ot.GlyphAssembly()
|
||||||
|
construction.GlyphAssembly.ItalicsCorrection = _mathValueRecord(ic)
|
||||||
|
construction.GlyphAssembly.PartCount = len(parts)
|
||||||
|
construction.GlyphAssembly.PartRecords = []
|
||||||
|
for part in parts:
|
||||||
|
part_name, flags, start, end, advance = part
|
||||||
|
record = ot.GlyphPartRecord()
|
||||||
|
record.glyph = part_name
|
||||||
|
record.PartFlags = int(flags)
|
||||||
|
record.StartConnectorLength = otRound(start)
|
||||||
|
record.EndConnectorLength = otRound(end)
|
||||||
|
record.FullAdvance = otRound(advance)
|
||||||
|
construction.GlyphAssembly.PartRecords.append(record)
|
||||||
|
|
||||||
|
constructions.append(construction)
|
||||||
|
|
||||||
|
return coverage, constructions
|
||||||
|
|
||||||
|
|
||||||
|
def _mathValueRecord(value):
|
||||||
|
value_record = ot.MathValueRecord()
|
||||||
|
value_record.Value = otRound(value)
|
||||||
|
return value_record
|
||||||
|
@ -1549,6 +1549,310 @@ def test_stat_infinities():
|
|||||||
assert struct.pack(">l", posInf) == b"\x7f\xff\xff\xff"
|
assert struct.pack(">l", posInf) == b"\x7f\xff\xff\xff"
|
||||||
|
|
||||||
|
|
||||||
|
def test_buildMathTable_empty():
|
||||||
|
ttFont = ttLib.TTFont()
|
||||||
|
ttFont.setGlyphOrder([])
|
||||||
|
builder.buildMathTable(ttFont)
|
||||||
|
|
||||||
|
assert "MATH" in ttFont
|
||||||
|
mathTable = ttFont["MATH"].table
|
||||||
|
assert mathTable.Version == 0x00010000
|
||||||
|
|
||||||
|
assert mathTable.MathConstants is None
|
||||||
|
assert mathTable.MathGlyphInfo is None
|
||||||
|
assert mathTable.MathVariants is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_buildMathTable_constants():
|
||||||
|
ttFont = ttLib.TTFont()
|
||||||
|
ttFont.setGlyphOrder([])
|
||||||
|
constants = {
|
||||||
|
"AccentBaseHeight": 516,
|
||||||
|
"AxisHeight": 262,
|
||||||
|
"DelimitedSubFormulaMinHeight": 1500,
|
||||||
|
"DisplayOperatorMinHeight": 2339,
|
||||||
|
"FlattenedAccentBaseHeight": 698,
|
||||||
|
"FractionDenomDisplayStyleGapMin": 198,
|
||||||
|
"FractionDenominatorDisplayStyleShiftDown": 698,
|
||||||
|
"FractionDenominatorGapMin": 66,
|
||||||
|
"FractionDenominatorShiftDown": 465,
|
||||||
|
"FractionNumDisplayStyleGapMin": 198,
|
||||||
|
"FractionNumeratorDisplayStyleShiftUp": 774,
|
||||||
|
"FractionNumeratorGapMin": 66,
|
||||||
|
"FractionNumeratorShiftUp": 516,
|
||||||
|
"FractionRuleThickness": 66,
|
||||||
|
"LowerLimitBaselineDropMin": 585,
|
||||||
|
"LowerLimitGapMin": 132,
|
||||||
|
"MathLeading": 300,
|
||||||
|
"OverbarExtraAscender": 66,
|
||||||
|
"OverbarRuleThickness": 66,
|
||||||
|
"OverbarVerticalGap": 198,
|
||||||
|
"RadicalDegreeBottomRaisePercent": 75,
|
||||||
|
"RadicalDisplayStyleVerticalGap": 195,
|
||||||
|
"RadicalExtraAscender": 66,
|
||||||
|
"RadicalKernAfterDegree": -556,
|
||||||
|
"RadicalKernBeforeDegree": 278,
|
||||||
|
"RadicalRuleThickness": 66,
|
||||||
|
"RadicalVerticalGap": 82,
|
||||||
|
"ScriptPercentScaleDown": 70,
|
||||||
|
"ScriptScriptPercentScaleDown": 55,
|
||||||
|
"SkewedFractionHorizontalGap": 66,
|
||||||
|
"SkewedFractionVerticalGap": 77,
|
||||||
|
"SpaceAfterScript": 42,
|
||||||
|
"StackBottomDisplayStyleShiftDown": 698,
|
||||||
|
"StackBottomShiftDown": 465,
|
||||||
|
"StackDisplayStyleGapMin": 462,
|
||||||
|
"StackGapMin": 198,
|
||||||
|
"StackTopDisplayStyleShiftUp": 774,
|
||||||
|
"StackTopShiftUp": 516,
|
||||||
|
"StretchStackBottomShiftDown": 585,
|
||||||
|
"StretchStackGapAboveMin": 132,
|
||||||
|
"StretchStackGapBelowMin": 132,
|
||||||
|
"StretchStackTopShiftUp": 165,
|
||||||
|
"SubSuperscriptGapMin": 264,
|
||||||
|
"SubscriptBaselineDropMin": 105,
|
||||||
|
"SubscriptShiftDown": 140,
|
||||||
|
"SubscriptTopMax": 413,
|
||||||
|
"SuperscriptBaselineDropMax": 221,
|
||||||
|
"SuperscriptBottomMaxWithSubscript": 413,
|
||||||
|
"SuperscriptBottomMin": 129,
|
||||||
|
"SuperscriptShiftUp": 477,
|
||||||
|
"SuperscriptShiftUpCramped": 358,
|
||||||
|
"UnderbarExtraDescender": 66,
|
||||||
|
"UnderbarRuleThickness": 66,
|
||||||
|
"UnderbarVerticalGap": 198,
|
||||||
|
"UpperLimitBaselineRiseMin": 165,
|
||||||
|
"UpperLimitGapMin": 132,
|
||||||
|
}
|
||||||
|
builder.buildMathTable(ttFont, constants=constants)
|
||||||
|
mathTable = ttFont["MATH"].table
|
||||||
|
assert mathTable.MathConstants
|
||||||
|
assert mathTable.MathGlyphInfo is None
|
||||||
|
assert mathTable.MathVariants is None
|
||||||
|
for k, v in constants.items():
|
||||||
|
r = getattr(mathTable.MathConstants, k)
|
||||||
|
try:
|
||||||
|
r = r.Value
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
assert r == v
|
||||||
|
|
||||||
|
|
||||||
|
def test_buildMathTable_italicsCorrection():
|
||||||
|
ttFont = ttLib.TTFont()
|
||||||
|
ttFont.setGlyphOrder(["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"])
|
||||||
|
italicsCorrections = {"A": 100, "C": 300, "D": 400, "E": 500}
|
||||||
|
builder.buildMathTable(ttFont, italicsCorrections=italicsCorrections)
|
||||||
|
mathTable = ttFont["MATH"].table
|
||||||
|
assert mathTable.MathConstants is None
|
||||||
|
assert mathTable.MathGlyphInfo
|
||||||
|
assert mathTable.MathVariants is None
|
||||||
|
assert set(
|
||||||
|
mathTable.MathGlyphInfo.MathItalicsCorrectionInfo.Coverage.glyphs
|
||||||
|
) == set(italicsCorrections.keys())
|
||||||
|
for glyph, correction in zip(
|
||||||
|
mathTable.MathGlyphInfo.MathItalicsCorrectionInfo.Coverage.glyphs,
|
||||||
|
mathTable.MathGlyphInfo.MathItalicsCorrectionInfo.ItalicsCorrection,
|
||||||
|
):
|
||||||
|
assert correction.Value == italicsCorrections[glyph]
|
||||||
|
|
||||||
|
|
||||||
|
def test_buildMathTable_topAccentAttachment():
|
||||||
|
ttFont = ttLib.TTFont()
|
||||||
|
ttFont.setGlyphOrder(["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"])
|
||||||
|
topAccentAttachments = {"A": 10, "B": 20, "C": 30, "E": 50}
|
||||||
|
builder.buildMathTable(ttFont, topAccentAttachments=topAccentAttachments)
|
||||||
|
mathTable = ttFont["MATH"].table
|
||||||
|
assert mathTable.MathConstants is None
|
||||||
|
assert mathTable.MathGlyphInfo
|
||||||
|
assert mathTable.MathVariants is None
|
||||||
|
assert set(
|
||||||
|
mathTable.MathGlyphInfo.MathTopAccentAttachment.TopAccentCoverage.glyphs
|
||||||
|
) == set(topAccentAttachments.keys())
|
||||||
|
for glyph, attachment in zip(
|
||||||
|
mathTable.MathGlyphInfo.MathTopAccentAttachment.TopAccentCoverage.glyphs,
|
||||||
|
mathTable.MathGlyphInfo.MathTopAccentAttachment.TopAccentAttachment,
|
||||||
|
):
|
||||||
|
assert attachment.Value == topAccentAttachments[glyph]
|
||||||
|
|
||||||
|
|
||||||
|
def test_buildMathTable_extendedShape():
|
||||||
|
ttFont = ttLib.TTFont()
|
||||||
|
ttFont.setGlyphOrder(["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"])
|
||||||
|
extendedShapes = {"A", "C", "E", "F"}
|
||||||
|
builder.buildMathTable(ttFont, extendedShapes=extendedShapes)
|
||||||
|
mathTable = ttFont["MATH"].table
|
||||||
|
assert mathTable.MathConstants is None
|
||||||
|
assert mathTable.MathGlyphInfo
|
||||||
|
assert mathTable.MathVariants is None
|
||||||
|
assert set(mathTable.MathGlyphInfo.ExtendedShapeCoverage.glyphs) == extendedShapes
|
||||||
|
|
||||||
|
|
||||||
|
def test_buildMathTable_mathKern():
|
||||||
|
ttFont = ttLib.TTFont()
|
||||||
|
ttFont.setGlyphOrder(["A", "B"])
|
||||||
|
mathKerns = {
|
||||||
|
"A": {
|
||||||
|
"TopRight": ([10, 20], [10, 20, 30]),
|
||||||
|
"BottomRight": ([], [10]),
|
||||||
|
"TopLeft": ([10], [0, 20]),
|
||||||
|
"BottomLeft": ([-10, 0], [0, 10, 20]),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
builder.buildMathTable(ttFont, mathKerns=mathKerns)
|
||||||
|
mathTable = ttFont["MATH"].table
|
||||||
|
assert mathTable.MathConstants is None
|
||||||
|
assert mathTable.MathGlyphInfo
|
||||||
|
assert mathTable.MathVariants is None
|
||||||
|
assert set(mathTable.MathGlyphInfo.MathKernInfo.MathKernCoverage.glyphs) == set(
|
||||||
|
mathKerns.keys()
|
||||||
|
)
|
||||||
|
for glyph, record in zip(
|
||||||
|
mathTable.MathGlyphInfo.MathKernInfo.MathKernCoverage.glyphs,
|
||||||
|
mathTable.MathGlyphInfo.MathKernInfo.MathKernInfoRecords,
|
||||||
|
):
|
||||||
|
h, k = mathKerns[glyph]["TopRight"]
|
||||||
|
assert [v.Value for v in record.TopRightMathKern.CorrectionHeight] == h
|
||||||
|
assert [v.Value for v in record.TopRightMathKern.KernValue] == k
|
||||||
|
h, k = mathKerns[glyph]["BottomRight"]
|
||||||
|
assert [v.Value for v in record.BottomRightMathKern.CorrectionHeight] == h
|
||||||
|
assert [v.Value for v in record.BottomRightMathKern.KernValue] == k
|
||||||
|
h, k = mathKerns[glyph]["TopLeft"]
|
||||||
|
assert [v.Value for v in record.TopLeftMathKern.CorrectionHeight] == h
|
||||||
|
assert [v.Value for v in record.TopLeftMathKern.KernValue] == k
|
||||||
|
h, k = mathKerns[glyph]["BottomLeft"]
|
||||||
|
assert [v.Value for v in record.BottomLeftMathKern.CorrectionHeight] == h
|
||||||
|
assert [v.Value for v in record.BottomLeftMathKern.KernValue] == k
|
||||||
|
|
||||||
|
|
||||||
|
def test_buildMathTable_vertVariants():
|
||||||
|
ttFont = ttLib.TTFont()
|
||||||
|
ttFont.setGlyphOrder(["A", "A.size1", "A.size2"])
|
||||||
|
vertGlyphVariants = {"A": [("A.size1", 100), ("A.size2", 200)]}
|
||||||
|
builder.buildMathTable(ttFont, vertGlyphVariants=vertGlyphVariants)
|
||||||
|
mathTable = ttFont["MATH"].table
|
||||||
|
assert mathTable.MathConstants is None
|
||||||
|
assert mathTable.MathGlyphInfo is None
|
||||||
|
assert mathTable.MathVariants
|
||||||
|
assert set(mathTable.MathVariants.VertGlyphCoverage.glyphs) == set(
|
||||||
|
vertGlyphVariants.keys()
|
||||||
|
)
|
||||||
|
for glyph, construction in zip(
|
||||||
|
mathTable.MathVariants.VertGlyphCoverage.glyphs,
|
||||||
|
mathTable.MathVariants.VertGlyphConstruction,
|
||||||
|
):
|
||||||
|
assert [
|
||||||
|
(r.VariantGlyph, r.AdvanceMeasurement)
|
||||||
|
for r in construction.MathGlyphVariantRecord
|
||||||
|
] == vertGlyphVariants[glyph]
|
||||||
|
|
||||||
|
|
||||||
|
def test_buildMathTable_horizVariants():
|
||||||
|
ttFont = ttLib.TTFont()
|
||||||
|
ttFont.setGlyphOrder(["A", "A.size1", "A.size2"])
|
||||||
|
horizGlyphVariants = {"A": [("A.size1", 100), ("A.size2", 200)]}
|
||||||
|
builder.buildMathTable(ttFont, horizGlyphVariants=horizGlyphVariants)
|
||||||
|
mathTable = ttFont["MATH"].table
|
||||||
|
assert mathTable.MathConstants is None
|
||||||
|
assert mathTable.MathGlyphInfo is None
|
||||||
|
assert mathTable.MathVariants
|
||||||
|
assert set(mathTable.MathVariants.HorizGlyphCoverage.glyphs) == set(
|
||||||
|
horizGlyphVariants.keys()
|
||||||
|
)
|
||||||
|
for glyph, construction in zip(
|
||||||
|
mathTable.MathVariants.HorizGlyphCoverage.glyphs,
|
||||||
|
mathTable.MathVariants.HorizGlyphConstruction,
|
||||||
|
):
|
||||||
|
assert [
|
||||||
|
(r.VariantGlyph, r.AdvanceMeasurement)
|
||||||
|
for r in construction.MathGlyphVariantRecord
|
||||||
|
] == horizGlyphVariants[glyph]
|
||||||
|
|
||||||
|
|
||||||
|
def test_buildMathTable_vertAssembly():
|
||||||
|
ttFont = ttLib.TTFont()
|
||||||
|
ttFont.setGlyphOrder(["A", "A.top", "A.middle", "A.bottom", "A.extender"])
|
||||||
|
vertGlyphAssembly = {
|
||||||
|
"A": [
|
||||||
|
[
|
||||||
|
("A.bottom", 0, 0, 100, 200),
|
||||||
|
("A.extender", 1, 50, 50, 100),
|
||||||
|
("A.middle", 0, 100, 100, 200),
|
||||||
|
("A.extender", 1, 50, 50, 100),
|
||||||
|
("A.top", 0, 100, 0, 200),
|
||||||
|
],
|
||||||
|
10,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
builder.buildMathTable(ttFont, vertGlyphAssembly=vertGlyphAssembly)
|
||||||
|
mathTable = ttFont["MATH"].table
|
||||||
|
assert mathTable.MathConstants is None
|
||||||
|
assert mathTable.MathGlyphInfo is None
|
||||||
|
assert mathTable.MathVariants
|
||||||
|
assert set(mathTable.MathVariants.VertGlyphCoverage.glyphs) == set(
|
||||||
|
vertGlyphAssembly.keys()
|
||||||
|
)
|
||||||
|
for glyph, construction in zip(
|
||||||
|
mathTable.MathVariants.VertGlyphCoverage.glyphs,
|
||||||
|
mathTable.MathVariants.VertGlyphConstruction,
|
||||||
|
):
|
||||||
|
assert [
|
||||||
|
[
|
||||||
|
(
|
||||||
|
r.glyph,
|
||||||
|
r.PartFlags,
|
||||||
|
r.StartConnectorLength,
|
||||||
|
r.EndConnectorLength,
|
||||||
|
r.FullAdvance,
|
||||||
|
)
|
||||||
|
for r in construction.GlyphAssembly.PartRecords
|
||||||
|
],
|
||||||
|
construction.GlyphAssembly.ItalicsCorrection.Value,
|
||||||
|
] == vertGlyphAssembly[glyph]
|
||||||
|
|
||||||
|
|
||||||
|
def test_buildMathTable_horizAssembly():
|
||||||
|
ttFont = ttLib.TTFont()
|
||||||
|
ttFont.setGlyphOrder(["A", "A.top", "A.middle", "A.bottom", "A.extender"])
|
||||||
|
horizGlyphAssembly = {
|
||||||
|
"A": [
|
||||||
|
[
|
||||||
|
("A.bottom", 0, 0, 100, 200),
|
||||||
|
("A.extender", 1, 50, 50, 100),
|
||||||
|
("A.middle", 0, 100, 100, 200),
|
||||||
|
("A.extender", 1, 50, 50, 100),
|
||||||
|
("A.top", 0, 100, 0, 200),
|
||||||
|
],
|
||||||
|
10,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
builder.buildMathTable(ttFont, horizGlyphAssembly=horizGlyphAssembly)
|
||||||
|
mathTable = ttFont["MATH"].table
|
||||||
|
assert mathTable.MathConstants is None
|
||||||
|
assert mathTable.MathGlyphInfo is None
|
||||||
|
assert mathTable.MathVariants
|
||||||
|
assert set(mathTable.MathVariants.HorizGlyphCoverage.glyphs) == set(
|
||||||
|
horizGlyphAssembly.keys()
|
||||||
|
)
|
||||||
|
for glyph, construction in zip(
|
||||||
|
mathTable.MathVariants.HorizGlyphCoverage.glyphs,
|
||||||
|
mathTable.MathVariants.HorizGlyphConstruction,
|
||||||
|
):
|
||||||
|
assert [
|
||||||
|
[
|
||||||
|
(
|
||||||
|
r.glyph,
|
||||||
|
r.PartFlags,
|
||||||
|
r.StartConnectorLength,
|
||||||
|
r.EndConnectorLength,
|
||||||
|
r.FullAdvance,
|
||||||
|
)
|
||||||
|
for r in construction.GlyphAssembly.PartRecords
|
||||||
|
],
|
||||||
|
construction.GlyphAssembly.ItalicsCorrection.Value,
|
||||||
|
] == horizGlyphAssembly[glyph]
|
||||||
|
|
||||||
|
|
||||||
class ChainContextualRulesetTest(object):
|
class ChainContextualRulesetTest(object):
|
||||||
def test_makeRulesets(self):
|
def test_makeRulesets(self):
|
||||||
font = ttLib.TTFont()
|
font = ttLib.TTFont()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user