Merge pull request #1434 from justvanrossum/fontbuilder-uvs
[fontBuilder] adding support for cmap format 14 Unicode Variation Sequences
This commit is contained in:
commit
b920b3b36f
@ -364,9 +364,18 @@ class FontBuilder(object):
|
||||
"""Set the glyph order for the font."""
|
||||
self.font.setGlyphOrder(glyphOrder)
|
||||
|
||||
def setupCharacterMap(self, cmapping, allowFallback=False):
|
||||
def setupCharacterMap(self, cmapping, uvs=None, allowFallback=False):
|
||||
"""Build the `cmap` table for the font. The `cmapping` argument should
|
||||
be a dict mapping unicode code points as integers to glyph names.
|
||||
|
||||
The `uvs` argument, when passed, must be a list of tuples, describing
|
||||
Unicode Variation Sequences. These tuples have three elements:
|
||||
(unicodeValue, variationSelector, glyphName)
|
||||
`unicodeValue` and `variationSelector` are integer code points.
|
||||
`glyphName` may be None, to indicate this is the default variation.
|
||||
Text processors will then use the cmap to find the glyph name.
|
||||
Each Unicode Variation Sequence should be an officially supported
|
||||
sequence, but this is not policed.
|
||||
"""
|
||||
subTables = []
|
||||
highestUnicode = max(cmapping)
|
||||
@ -390,6 +399,19 @@ class FontBuilder(object):
|
||||
subTable_0_3 = buildCmapSubTable(cmapping_3_1, format, 0, 3)
|
||||
subTables.append(subTable_0_3)
|
||||
|
||||
if uvs is not None:
|
||||
uvsDict = {}
|
||||
for unicodeValue, variationSelector, glyphName in uvs:
|
||||
if cmapping.get(unicodeValue) == glyphName:
|
||||
# this is a default variation
|
||||
glyphName = None
|
||||
if variationSelector not in uvsDict:
|
||||
uvsDict[variationSelector] = []
|
||||
uvsDict[variationSelector].append((unicodeValue, glyphName))
|
||||
uvsSubTable = buildCmapSubTable({}, 14, 0, 5)
|
||||
uvsSubTable.uvsDict = uvsDict
|
||||
subTables.append(uvsSubTable)
|
||||
|
||||
self.font["cmap"] = newTable("cmap")
|
||||
self.font["cmap"].tableVersion = 0
|
||||
self.font["cmap"].tables = subTables
|
||||
|
20
Tests/fontBuilder/data/test_uvs.ttf.ttx
Normal file
20
Tests/fontBuilder/data/test_uvs.ttf.ttx
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.35">
|
||||
|
||||
<cmap>
|
||||
<tableVersion version="0"/>
|
||||
<cmap_format_4 platformID="0" platEncID="3" language="0">
|
||||
<map code="0x20" name="space"/><!-- SPACE -->
|
||||
<map code="0x30" name="zero"/><!-- DIGIT ZERO -->
|
||||
</cmap_format_4>
|
||||
<cmap_format_14 platformID="0" platEncID="5" format="14" length="49" numVarSelectorRecords="2">
|
||||
<map uvs="0xfe00" uv="0x30" name="zero.slash"/>
|
||||
<map uvs="0xfe01" uv="0x30" name="None"/>
|
||||
</cmap_format_14>
|
||||
<cmap_format_4 platformID="3" platEncID="1" language="0">
|
||||
<map code="0x20" name="space"/><!-- SPACE -->
|
||||
<map code="0x30" name="zero"/><!-- DIGIT ZERO -->
|
||||
</cmap_format_4>
|
||||
</cmap>
|
||||
|
||||
</ttFont>
|
@ -53,9 +53,9 @@ def _setupFontBuilder(isTTF, unitsPerEm=1024):
|
||||
return fb, advanceWidths, nameStrings
|
||||
|
||||
|
||||
def _verifyOutput(outPath):
|
||||
def _verifyOutput(outPath, tables=None):
|
||||
f = TTFont(outPath)
|
||||
f.saveXML(outPath + ".ttx")
|
||||
f.saveXML(outPath + ".ttx", tables=tables)
|
||||
with open(outPath + ".ttx") as f:
|
||||
testData = strip_VariableItems(f.read())
|
||||
refData = strip_VariableItems(getTestData(os.path.basename(outPath) + ".ttx"))
|
||||
@ -244,3 +244,42 @@ def test_setupNameTable_no_windows():
|
||||
|
||||
assert all(n for n in fb.font["name"].names if n.platformID == 1)
|
||||
assert not any(n for n in fb.font["name"].names if n.platformID == 3)
|
||||
|
||||
|
||||
def test_unicodeVariationSequences(tmpdir):
|
||||
familyName = "UVSTestFont"
|
||||
styleName = "Regular"
|
||||
nameStrings = dict(familyName=familyName, styleName=styleName)
|
||||
nameStrings['psName'] = familyName + "-" + styleName
|
||||
glyphOrder = [".notdef", "space", "zero", "zero.slash"]
|
||||
cmap = {ord(" "): "space", ord("0"): "zero"}
|
||||
uvs = [
|
||||
(0x0030, 0xFE00, "zero.slash"),
|
||||
(0x0030, 0xFE01, None), # not an official sequence, just testing
|
||||
]
|
||||
metrics = {gn: (600, 0) for gn in glyphOrder}
|
||||
pen = TTGlyphPen(None)
|
||||
glyph = pen.glyph() # empty placeholder
|
||||
glyphs = {gn: glyph for gn in glyphOrder}
|
||||
|
||||
fb = FontBuilder(1024, isTTF=True)
|
||||
fb.setupGlyphOrder(glyphOrder)
|
||||
fb.setupCharacterMap(cmap, uvs)
|
||||
fb.setupGlyf(glyphs)
|
||||
fb.setupHorizontalMetrics(metrics)
|
||||
fb.setupHorizontalHeader(ascent=824, descent=200)
|
||||
fb.setupNameTable(nameStrings)
|
||||
fb.setupOS2()
|
||||
fb.setupPost()
|
||||
|
||||
outPath = os.path.join(str(tmpdir), "test_uvs.ttf")
|
||||
fb.save(outPath)
|
||||
_verifyOutput(outPath, tables=["cmap"])
|
||||
|
||||
uvs = [
|
||||
(0x0030, 0xFE00, "zero.slash"),
|
||||
(0x0030, 0xFE01, "zero"), # should result in the exact same subtable data, due to cmap[0x0030] == "zero"
|
||||
]
|
||||
fb.setupCharacterMap(cmap, uvs)
|
||||
fb.save(outPath)
|
||||
_verifyOutput(outPath, tables=["cmap"])
|
||||
|
Loading…
x
Reference in New Issue
Block a user