aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaibo Huang <hhb@google.com>2019-07-11 12:34:30 -0700
committerandroid-build-merger <android-build-merger@google.com>2019-07-11 12:34:30 -0700
commita43c21305607a1870f05f962a2e5db5d99dace7e (patch)
tree9004cd003599c03e7bf821adff6983de7ad156a4
parentd24a6dde80fac8ec51afcc4f7ae86d83b717b39e (diff)
parent70a8d12c5e7a898721d38e40fa5e6030cf11490a (diff)
downloadfonttools-a43c21305607a1870f05f962a2e5db5d99dace7e.tar.gz
Upgrade fonttools to 3.43.2 am: 3422e6b762 am: b58205c46d
am: 70a8d12c5e Change-Id: I13e043ece60dfbdb96c1b4b93ddf3b5c1fe53b78
-rw-r--r--Lib/fontTools/__init__.py2
-rw-r--r--Lib/fontTools/varLib/__init__.py56
-rw-r--r--[-rwxr-xr-x]Lib/fontTools/varLib/cff.py31
-rw-r--r--Lib/fontTools/varLib/featureVars.py6
-rw-r--r--Lib/fonttools.egg-info/PKG-INFO18
-rw-r--r--METADATA8
-rw-r--r--NEWS.rst6
-rw-r--r--PKG-INFO18
-rw-r--r--Tests/otlLib/builder_test.py1711
-rw-r--r--Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w0.00.ttx1
-rw-r--r--Tests/varLib/data/test_results/BuildMain.ttx2
-rw-r--r--Tests/varLib/data/test_results/BuildTestCFF2.ttx4
-rw-r--r--Tests/varLib/data/test_results/SparseMasters.ttx2
-rw-r--r--Tests/varLib/data/test_results/TestNonMarkingCFF2.ttx4
-rw-r--r--Tests/varLib/data/test_results/TestSparseCFF2VF.ttx1
-rw-r--r--Tests/varLib/varLib_test.py77
-rw-r--r--setup.cfg2
-rwxr-xr-xsetup.py2
18 files changed, 1079 insertions, 872 deletions
diff --git a/Lib/fontTools/__init__.py b/Lib/fontTools/__init__.py
index d6919b28..1a49c104 100644
--- a/Lib/fontTools/__init__.py
+++ b/Lib/fontTools/__init__.py
@@ -5,6 +5,6 @@ from fontTools.misc.loggingTools import configLogger
log = logging.getLogger(__name__)
-version = __version__ = "3.43.1"
+version = __version__ = "3.43.2"
__all__ = ["version", "log", "configLogger"]
diff --git a/Lib/fontTools/varLib/__init__.py b/Lib/fontTools/varLib/__init__.py
index 891e92c5..b428aeb1 100644
--- a/Lib/fontTools/varLib/__init__.py
+++ b/Lib/fontTools/varLib/__init__.py
@@ -23,8 +23,7 @@ from __future__ import unicode_literals
from fontTools.misc.py23 import *
from fontTools.misc.fixedTools import otRound
from fontTools.misc.arrayTools import Vector
-from fontTools.ttLib import TTFont, newTable, TTLibError
-from fontTools.ttLib.tables._n_a_m_e import NameRecord
+from fontTools.ttLib import TTFont, newTable
from fontTools.ttLib.tables._f_v_a_r import Axis, NamedInstance
from fontTools.ttLib.tables._g_l_y_f import GlyphCoordinates
from fontTools.ttLib.tables.ttProgram import Program
@@ -36,7 +35,7 @@ from fontTools.varLib.merger import VariationMerger
from fontTools.varLib.mvar import MVAR_ENTRIES
from fontTools.varLib.iup import iup_delta_optimize
from fontTools.varLib.featureVars import addFeatureVariations
-from fontTools.designspaceLib import DesignSpaceDocument, AxisDescriptor
+from fontTools.designspaceLib import DesignSpaceDocument
from collections import OrderedDict, namedtuple
import os.path
import logging
@@ -857,6 +856,45 @@ def load_designspace(designspace):
)
+# https://docs.microsoft.com/en-us/typography/opentype/spec/os2#uswidthclass
+WDTH_VALUE_TO_OS2_WIDTH_CLASS = {
+ 50: 1,
+ 62.5: 2,
+ 75: 3,
+ 87.5: 4,
+ 100: 5,
+ 112.5: 6,
+ 125: 7,
+ 150: 8,
+ 200: 9,
+}
+
+
+def set_default_weight_width_slant(font, location):
+ if "OS/2" in font:
+ if "wght" in location:
+ weight_class = otRound(max(1, min(location["wght"], 1000)))
+ if font["OS/2"].usWeightClass != weight_class:
+ log.info("Setting OS/2.usWidthClass = %s", weight_class)
+ font["OS/2"].usWeightClass = weight_class
+
+ if "wdth" in location:
+ # map 'wdth' axis (50..200) to OS/2.usWidthClass (1..9), rounding to closest
+ widthValue = min(max(location["wdth"], 50), 200)
+ widthClass = otRound(
+ models.piecewiseLinearMap(widthValue, WDTH_VALUE_TO_OS2_WIDTH_CLASS)
+ )
+ if font["OS/2"].usWidthClass != widthClass:
+ log.info("Setting OS/2.usWidthClass = %s", widthClass)
+ font["OS/2"].usWidthClass = widthClass
+
+ if "slnt" in location and "post" in font:
+ italicAngle = max(-90, min(location["slnt"], 90))
+ if font["post"].italicAngle != italicAngle:
+ log.info("Setting post.italicAngle = %s", italicAngle)
+ font["post"].italicAngle = italicAngle
+
+
def build(designspace, master_finder=lambda s:s, exclude=[], optimize=True):
"""
Build variation font from a designspace file.
@@ -930,6 +968,10 @@ def build(designspace, master_finder=lambda s:s, exclude=[], optimize=True):
post.extraNames = []
post.mapping = {}
+ set_default_weight_width_slant(
+ vf, location={axis.axisTag: axis.defaultValue for axis in vf["fvar"].axes}
+ )
+
for tag in exclude:
if tag in vf:
del vf[tag]
@@ -1064,9 +1106,6 @@ def main(args=None):
designspace_filename = options.designspace
finder = MasterFinder(options.master_finder)
- outfile = options.outfile
- if outfile is None:
- outfile = os.path.splitext(designspace_filename)[0] + '-VF.ttf'
vf, _, _ = build(
designspace_filename,
@@ -1075,6 +1114,11 @@ def main(args=None):
optimize=options.optimize
)
+ outfile = options.outfile
+ if outfile is None:
+ ext = "otf" if vf.sfntVersion == "OTTO" else "ttf"
+ outfile = os.path.splitext(designspace_filename)[0] + '-VF.' + ext
+
log.info("Saving variation font %s", outfile)
vf.save(outfile)
diff --git a/Lib/fontTools/varLib/cff.py b/Lib/fontTools/varLib/cff.py
index bcafdeee..aaabf857 100755..100644
--- a/Lib/fontTools/varLib/cff.py
+++ b/Lib/fontTools/varLib/cff.py
@@ -131,7 +131,7 @@ class MergeDictError(TypeError):
def conv_to_int(num):
- if num % 1 == 0:
+ if isinstance(num, float) and num.is_integer():
return int(num)
return num
@@ -198,17 +198,17 @@ def merge_PrivateDicts(top_dicts, vsindex_dict, var_model, fd_map):
pds.append(pd)
num_masters = len(pds)
for key, value in private_dict.rawDict.items():
+ dataList = []
if key not in pd_blend_fields:
continue
if isinstance(value, list):
try:
values = [pd.rawDict[key] for pd in pds]
except KeyError:
- del private_dict.rawDict[key]
print(
- b"Warning: {key} in default font Private dict is "
- b"missing from another font, and was "
- b"discarded.".format(key=key))
+ "Warning: {key} in default font Private dict is "
+ "missing from another font, and was "
+ "discarded.".format(key=key))
continue
try:
values = zip(*values)
@@ -227,7 +227,6 @@ def merge_PrivateDicts(top_dicts, vsindex_dict, var_model, fd_map):
and is converted finally to:
OtherBlues = [[-217, 17.0, 46.0], [-205, 0.0, 0.0]]
"""
- dataList = []
prev_val_list = [0] * num_masters
any_points_differ = False
for val_list in values:
@@ -237,8 +236,6 @@ def merge_PrivateDicts(top_dicts, vsindex_dict, var_model, fd_map):
any_points_differ = True
prev_val_list = val_list
deltas = sub_model.getDeltas(rel_list)
- # Convert numbers with no decimal part to an int.
- deltas = [conv_to_int(delta) for delta in deltas]
# For PrivateDict BlueValues, the default font
# values are absolute, not relative to the prior value.
deltas[0] = val_list[0]
@@ -253,6 +250,18 @@ def merge_PrivateDicts(top_dicts, vsindex_dict, var_model, fd_map):
dataList = sub_model.getDeltas(values)
else:
dataList = values[0]
+
+ # Convert numbers with no decimal part to an int
+ if isinstance(dataList, list):
+ for i, item in enumerate(dataList):
+ if isinstance(item, list):
+ for j, jtem in enumerate(item):
+ dataList[i][j] = conv_to_int(jtem)
+ else:
+ dataList[i] = conv_to_int(item)
+ else:
+ dataList = conv_to_int(dataList)
+
private_dict.rawDict[key] = dataList
@@ -270,7 +279,7 @@ def getfd_map(varFont, fonts_list):
num_regions = len(region_fonts)
topDict = default_font['CFF '].cff.topDictIndex[0]
if not hasattr(topDict, 'FDSelect'):
- # All glyphs reference only one FontDict.
+ # All glyphs reference only one FontDict.
# Map the FD index for regions to index 0.
fd_map[0] = {ri:0 for ri in range(num_regions)}
return fd_map
@@ -390,9 +399,9 @@ def merge_charstrings(glyphOrder, num_masters, top_dicts, masterModel):
# as we know it doesn't exist yet.
if vsindex != 0:
new_cs.program[:0] = [vsindex, 'vsindex']
-
+
# If there is no variation in any of the charstrings, then vsindex_dict
- # never gets built. This could still be needed if there is variation
+ # never gets built. This could still be needed if there is variation
# in the PrivatDict, so we will build the default data for vsindex = 0.
if not vsindex_dict:
key = (True,) * num_masters
diff --git a/Lib/fontTools/varLib/featureVars.py b/Lib/fontTools/varLib/featureVars.py
index 4caf30a2..e3aa6b6e 100644
--- a/Lib/fontTools/varLib/featureVars.py
+++ b/Lib/fontTools/varLib/featureVars.py
@@ -71,7 +71,7 @@ def overlayFeatureVariations(conditionalSubstitutions):
and rules with the same Box merged. The more specific rules appear earlier
in the resulting list. Moreover, instead of just a dictionary of substitutions,
a list of dictionaries is returned for substitutions corresponding to each
- uniq space, with each dictionary being identical to one of the input
+ unique space, with each dictionary being identical to one of the input
substitution dictionaries. These dictionaries are not merged to allow data
sharing when they are converted into font tables.
@@ -79,6 +79,7 @@ def overlayFeatureVariations(conditionalSubstitutions):
>>> condSubst = [
... # A list of (Region, Substitution) tuples.
... ([{"wght": (0.5, 1.0)}], {"dollar": "dollar.rvrn"}),
+ ... ([{"wght": (0.5, 1.0)}], {"dollar": "dollar.rvrn"}),
... ([{"wdth": (0.5, 1.0)}], {"cent": "cent.rvrn"}),
... ]
>>> from pprint import pprint
@@ -107,7 +108,8 @@ def overlayFeatureVariations(conditionalSubstitutions):
# rules for the same region.
merged = OrderedDict()
for key,value in reversed(conditionalSubstitutions):
- key = tuple(sorted(hashdict(cleanupBox(k)) for k in key))
+ key = tuple(sorted((hashdict(cleanupBox(k)) for k in key),
+ key=lambda d: tuple(sorted(d.items()))))
if key in merged:
merged[key].update(value)
else:
diff --git a/Lib/fonttools.egg-info/PKG-INFO b/Lib/fonttools.egg-info/PKG-INFO
index 74bb40d0..2dc1e573 100644
--- a/Lib/fonttools.egg-info/PKG-INFO
+++ b/Lib/fonttools.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: fonttools
-Version: 3.43.1
+Version: 3.43.2
Summary: Tools to manipulate font files
Home-page: http://github.com/fonttools/fonttools
Author: Just van Rossum
@@ -415,6 +415,12 @@ Description: |Travis Build Status| |Appveyor Build status| |Coverage Status| |Py
Changelog
~~~~~~~~~
+ 3.43.2 (released 2019-07-10)
+ ----------------------------
+
+ - [featureVars] Fixed region-merging code on python3 (#1659).
+ - [varLib.cff] Fixed merging of sparse PrivateDict items (#1653).
+
3.43.1 (released 2019-06-19)
----------------------------
@@ -1787,13 +1793,13 @@ Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Text Processing :: Fonts
Classifier: Topic :: Multimedia :: Graphics
Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
+Provides-Extra: plot
+Provides-Extra: unicode
+Provides-Extra: all
Provides-Extra: lxml
Provides-Extra: interpolatable
-Provides-Extra: unicode
+Provides-Extra: woff
+Provides-Extra: symfont
Provides-Extra: type1
-Provides-Extra: all
Provides-Extra: ufo
Provides-Extra: graphite
-Provides-Extra: woff
-Provides-Extra: plot
-Provides-Extra: symfont
diff --git a/METADATA b/METADATA
index ef73891b..61c9a718 100644
--- a/METADATA
+++ b/METADATA
@@ -7,12 +7,12 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://github.com/fonttools/fonttools/releases/download/3.43.1/fonttools-3.43.1.zip"
+ value: "https://github.com/fonttools/fonttools/releases/download/3.43.2/fonttools-3.43.2.zip"
}
- version: "3.43.1"
+ version: "3.43.2"
last_upgrade_date {
year: 2019
- month: 6
- day: 19
+ month: 7
+ day: 10
}
}
diff --git a/NEWS.rst b/NEWS.rst
index b7b1b506..0105e42e 100644
--- a/NEWS.rst
+++ b/NEWS.rst
@@ -1,3 +1,9 @@
+3.43.2 (released 2019-07-10)
+----------------------------
+
+- [featureVars] Fixed region-merging code on python3 (#1659).
+- [varLib.cff] Fixed merging of sparse PrivateDict items (#1653).
+
3.43.1 (released 2019-06-19)
----------------------------
diff --git a/PKG-INFO b/PKG-INFO
index 74bb40d0..2dc1e573 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: fonttools
-Version: 3.43.1
+Version: 3.43.2
Summary: Tools to manipulate font files
Home-page: http://github.com/fonttools/fonttools
Author: Just van Rossum
@@ -415,6 +415,12 @@ Description: |Travis Build Status| |Appveyor Build status| |Coverage Status| |Py
Changelog
~~~~~~~~~
+ 3.43.2 (released 2019-07-10)
+ ----------------------------
+
+ - [featureVars] Fixed region-merging code on python3 (#1659).
+ - [varLib.cff] Fixed merging of sparse PrivateDict items (#1653).
+
3.43.1 (released 2019-06-19)
----------------------------
@@ -1787,13 +1793,13 @@ Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Text Processing :: Fonts
Classifier: Topic :: Multimedia :: Graphics
Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
+Provides-Extra: plot
+Provides-Extra: unicode
+Provides-Extra: all
Provides-Extra: lxml
Provides-Extra: interpolatable
-Provides-Extra: unicode
+Provides-Extra: woff
+Provides-Extra: symfont
Provides-Extra: type1
-Provides-Extra: all
Provides-Extra: ufo
Provides-Extra: graphite
-Provides-Extra: woff
-Provides-Extra: plot
-Provides-Extra: symfont
diff --git a/Tests/otlLib/builder_test.py b/Tests/otlLib/builder_test.py
index 0829176c..83f7c828 100644
--- a/Tests/otlLib/builder_test.py
+++ b/Tests/otlLib/builder_test.py
@@ -3,1011 +3,1071 @@ from __future__ import unicode_literals
from fontTools.misc.testTools import getXML
from fontTools.otlLib import builder
from fontTools.ttLib.tables import otTables
-from itertools import chain
-import unittest
+import pytest
-class BuilderTest(unittest.TestCase):
- GLYPHS = (".notdef space zero one two three four five six "
- "A B C a b c grave acute cedilla f_f_i f_i c_t").split()
+class BuilderTest(object):
+ GLYPHS = (
+ ".notdef space zero one two three four five six "
+ "A B C a b c grave acute cedilla f_f_i f_i c_t"
+ ).split()
GLYPHMAP = {name: num for num, name in enumerate(GLYPHS)}
ANCHOR1 = builder.buildAnchor(11, -11)
ANCHOR2 = builder.buildAnchor(22, -22)
ANCHOR3 = builder.buildAnchor(33, -33)
- def __init__(self, methodName):
- unittest.TestCase.__init__(self, methodName)
- # Python 3 renamed assertRaisesRegexp to assertRaisesRegex,
- # and fires deprecation warnings if a program uses the old name.
- if not hasattr(self, "assertRaisesRegex"):
- self.assertRaisesRegex = self.assertRaisesRegexp
-
- @classmethod
- def setUpClass(cls):
- cls.maxDiff = None
-
def test_buildAnchor_format1(self):
anchor = builder.buildAnchor(23, 42)
- self.assertEqual(getXML(anchor.toXML),
- ['<Anchor Format="1">',
- ' <XCoordinate value="23"/>',
- ' <YCoordinate value="42"/>',
- '</Anchor>'])
+ assert getXML(anchor.toXML) == [
+ '<Anchor Format="1">',
+ ' <XCoordinate value="23"/>',
+ ' <YCoordinate value="42"/>',
+ "</Anchor>",
+ ]
def test_buildAnchor_format2(self):
anchor = builder.buildAnchor(23, 42, point=17)
- self.assertEqual(getXML(anchor.toXML),
- ['<Anchor Format="2">',
- ' <XCoordinate value="23"/>',
- ' <YCoordinate value="42"/>',
- ' <AnchorPoint value="17"/>',
- '</Anchor>'])
+ assert getXML(anchor.toXML) == [
+ '<Anchor Format="2">',
+ ' <XCoordinate value="23"/>',
+ ' <YCoordinate value="42"/>',
+ ' <AnchorPoint value="17"/>',
+ "</Anchor>",
+ ]
def test_buildAnchor_format3(self):
anchor = builder.buildAnchor(
- 23, 42,
+ 23,
+ 42,
deviceX=builder.buildDevice({1: 1, 0: 0}),
- deviceY=builder.buildDevice({7: 7}))
- self.assertEqual(getXML(anchor.toXML),
- ['<Anchor Format="3">',
- ' <XCoordinate value="23"/>',
- ' <YCoordinate value="42"/>',
- ' <XDeviceTable>',
- ' <StartSize value="0"/>',
- ' <EndSize value="1"/>',
- ' <DeltaFormat value="1"/>',
- ' <DeltaValue value="[0, 1]"/>',
- ' </XDeviceTable>',
- ' <YDeviceTable>',
- ' <StartSize value="7"/>',
- ' <EndSize value="7"/>',
- ' <DeltaFormat value="2"/>',
- ' <DeltaValue value="[7]"/>',
- ' </YDeviceTable>',
- '</Anchor>'])
+ deviceY=builder.buildDevice({7: 7}),
+ )
+ assert getXML(anchor.toXML) == [
+ '<Anchor Format="3">',
+ ' <XCoordinate value="23"/>',
+ ' <YCoordinate value="42"/>',
+ " <XDeviceTable>",
+ ' <StartSize value="0"/>',
+ ' <EndSize value="1"/>',
+ ' <DeltaFormat value="1"/>',
+ ' <DeltaValue value="[0, 1]"/>',
+ " </XDeviceTable>",
+ " <YDeviceTable>",
+ ' <StartSize value="7"/>',
+ ' <EndSize value="7"/>',
+ ' <DeltaFormat value="2"/>',
+ ' <DeltaValue value="[7]"/>',
+ " </YDeviceTable>",
+ "</Anchor>",
+ ]
def test_buildAttachList(self):
- attachList = builder.buildAttachList({
- "zero": [23, 7], "one": [1],
- }, self.GLYPHMAP)
- self.assertEqual(getXML(attachList.toXML),
- ['<AttachList>',
- ' <Coverage>',
- ' <Glyph value="zero"/>',
- ' <Glyph value="one"/>',
- ' </Coverage>',
- ' <!-- GlyphCount=2 -->',
- ' <AttachPoint index="0">',
- ' <!-- PointCount=2 -->',
- ' <PointIndex index="0" value="7"/>',
- ' <PointIndex index="1" value="23"/>',
- ' </AttachPoint>',
- ' <AttachPoint index="1">',
- ' <!-- PointCount=1 -->',
- ' <PointIndex index="0" value="1"/>',
- ' </AttachPoint>',
- '</AttachList>'])
+ attachList = builder.buildAttachList(
+ {"zero": [23, 7], "one": [1]}, self.GLYPHMAP
+ )
+ assert getXML(attachList.toXML) == [
+ "<AttachList>",
+ " <Coverage>",
+ ' <Glyph value="zero"/>',
+ ' <Glyph value="one"/>',
+ " </Coverage>",
+ " <!-- GlyphCount=2 -->",
+ ' <AttachPoint index="0">',
+ " <!-- PointCount=2 -->",
+ ' <PointIndex index="0" value="7"/>',
+ ' <PointIndex index="1" value="23"/>',
+ " </AttachPoint>",
+ ' <AttachPoint index="1">',
+ " <!-- PointCount=1 -->",
+ ' <PointIndex index="0" value="1"/>',
+ " </AttachPoint>",
+ "</AttachList>",
+ ]
def test_buildAttachList_empty(self):
- self.assertIsNone(builder.buildAttachList({}, self.GLYPHMAP))
+ assert builder.buildAttachList({}, self.GLYPHMAP) is None
def test_buildAttachPoint(self):
attachPoint = builder.buildAttachPoint([7, 3])
- self.assertEqual(getXML(attachPoint.toXML),
- ['<AttachPoint>',
- ' <!-- PointCount=2 -->',
- ' <PointIndex index="0" value="3"/>',
- ' <PointIndex index="1" value="7"/>',
- '</AttachPoint>'])
+ assert getXML(attachPoint.toXML) == [
+ "<AttachPoint>",
+ " <!-- PointCount=2 -->",
+ ' <PointIndex index="0" value="3"/>',
+ ' <PointIndex index="1" value="7"/>',
+ "</AttachPoint>",
+ ]
def test_buildAttachPoint_empty(self):
- self.assertIsNone(builder.buildAttachPoint([]))
+ assert builder.buildAttachPoint([]) is None
def test_buildAttachPoint_duplicate(self):
attachPoint = builder.buildAttachPoint([7, 3, 7])
- self.assertEqual(getXML(attachPoint.toXML),
- ['<AttachPoint>',
- ' <!-- PointCount=2 -->',
- ' <PointIndex index="0" value="3"/>',
- ' <PointIndex index="1" value="7"/>',
- '</AttachPoint>'])
-
+ assert getXML(attachPoint.toXML) == [
+ "<AttachPoint>",
+ " <!-- PointCount=2 -->",
+ ' <PointIndex index="0" value="3"/>',
+ ' <PointIndex index="1" value="7"/>',
+ "</AttachPoint>",
+ ]
def test_buildBaseArray(self):
anchor = builder.buildAnchor
- baseArray = builder.buildBaseArray({
- "a": {2: anchor(300, 80)},
- "c": {1: anchor(300, 80), 2: anchor(300, -20)}
- }, numMarkClasses=4, glyphMap=self.GLYPHMAP)
- self.assertEqual(getXML(baseArray.toXML),
- ['<BaseArray>',
- ' <!-- BaseCount=2 -->',
- ' <BaseRecord index="0">',
- ' <BaseAnchor index="0" empty="1"/>',
- ' <BaseAnchor index="1" empty="1"/>',
- ' <BaseAnchor index="2" Format="1">',
- ' <XCoordinate value="300"/>',
- ' <YCoordinate value="80"/>',
- ' </BaseAnchor>',
- ' <BaseAnchor index="3" empty="1"/>',
- ' </BaseRecord>',
- ' <BaseRecord index="1">',
- ' <BaseAnchor index="0" empty="1"/>',
- ' <BaseAnchor index="1" Format="1">',
- ' <XCoordinate value="300"/>',
- ' <YCoordinate value="80"/>',
- ' </BaseAnchor>',
- ' <BaseAnchor index="2" Format="1">',
- ' <XCoordinate value="300"/>',
- ' <YCoordinate value="-20"/>',
- ' </BaseAnchor>',
- ' <BaseAnchor index="3" empty="1"/>',
- ' </BaseRecord>',
- '</BaseArray>'])
+ baseArray = builder.buildBaseArray(
+ {"a": {2: anchor(300, 80)}, "c": {1: anchor(300, 80), 2: anchor(300, -20)}},
+ numMarkClasses=4,
+ glyphMap=self.GLYPHMAP,
+ )
+ assert getXML(baseArray.toXML) == [
+ "<BaseArray>",
+ " <!-- BaseCount=2 -->",
+ ' <BaseRecord index="0">',
+ ' <BaseAnchor index="0" empty="1"/>',
+ ' <BaseAnchor index="1" empty="1"/>',
+ ' <BaseAnchor index="2" Format="1">',
+ ' <XCoordinate value="300"/>',
+ ' <YCoordinate value="80"/>',
+ " </BaseAnchor>",
+ ' <BaseAnchor index="3" empty="1"/>',
+ " </BaseRecord>",
+ ' <BaseRecord index="1">',
+ ' <BaseAnchor index="0" empty="1"/>',
+ ' <BaseAnchor index="1" Format="1">',
+ ' <XCoordinate value="300"/>',
+ ' <YCoordinate value="80"/>',
+ " </BaseAnchor>",
+ ' <BaseAnchor index="2" Format="1">',
+ ' <XCoordinate value="300"/>',
+ ' <YCoordinate value="-20"/>',
+ " </BaseAnchor>",
+ ' <BaseAnchor index="3" empty="1"/>',
+ " </BaseRecord>",
+ "</BaseArray>",
+ ]
def test_buildBaseRecord(self):
a = builder.buildAnchor
rec = builder.buildBaseRecord([a(500, -20), None, a(300, -15)])
- self.assertEqual(getXML(rec.toXML),
- ['<BaseRecord>',
- ' <BaseAnchor index="0" Format="1">',
- ' <XCoordinate value="500"/>',
- ' <YCoordinate value="-20"/>',
- ' </BaseAnchor>',
- ' <BaseAnchor index="1" empty="1"/>',
- ' <BaseAnchor index="2" Format="1">',
- ' <XCoordinate value="300"/>',
- ' <YCoordinate value="-15"/>',
- ' </BaseAnchor>',
- '</BaseRecord>'])
+ assert getXML(rec.toXML) == [
+ "<BaseRecord>",
+ ' <BaseAnchor index="0" Format="1">',
+ ' <XCoordinate value="500"/>',
+ ' <YCoordinate value="-20"/>',
+ " </BaseAnchor>",
+ ' <BaseAnchor index="1" empty="1"/>',
+ ' <BaseAnchor index="2" Format="1">',
+ ' <XCoordinate value="300"/>',
+ ' <YCoordinate value="-15"/>',
+ " </BaseAnchor>",
+ "</BaseRecord>",
+ ]
def test_buildCaretValueForCoord(self):
caret = builder.buildCaretValueForCoord(500)
- self.assertEqual(getXML(caret.toXML),
- ['<CaretValue Format="1">',
- ' <Coordinate value="500"/>',
- '</CaretValue>'])
+ assert getXML(caret.toXML) == [
+ '<CaretValue Format="1">',
+ ' <Coordinate value="500"/>',
+ "</CaretValue>",
+ ]
def test_buildCaretValueForPoint(self):
caret = builder.buildCaretValueForPoint(23)
- self.assertEqual(getXML(caret.toXML),
- ['<CaretValue Format="2">',
- ' <CaretValuePoint value="23"/>',
- '</CaretValue>'])
+ assert getXML(caret.toXML) == [
+ '<CaretValue Format="2">',
+ ' <CaretValuePoint value="23"/>',
+ "</CaretValue>",
+ ]
def test_buildComponentRecord(self):
a = builder.buildAnchor
rec = builder.buildComponentRecord([a(500, -20), None, a(300, -15)])
- self.assertEqual(getXML(rec.toXML),
- ['<ComponentRecord>',
- ' <LigatureAnchor index="0" Format="1">',
- ' <XCoordinate value="500"/>',
- ' <YCoordinate value="-20"/>',
- ' </LigatureAnchor>',
- ' <LigatureAnchor index="1" empty="1"/>',
- ' <LigatureAnchor index="2" Format="1">',
- ' <XCoordinate value="300"/>',
- ' <YCoordinate value="-15"/>',
- ' </LigatureAnchor>',
- '</ComponentRecord>'])
+ assert getXML(rec.toXML) == [
+ "<ComponentRecord>",
+ ' <LigatureAnchor index="0" Format="1">',
+ ' <XCoordinate value="500"/>',
+ ' <YCoordinate value="-20"/>',
+ " </LigatureAnchor>",
+ ' <LigatureAnchor index="1" empty="1"/>',
+ ' <LigatureAnchor index="2" Format="1">',
+ ' <XCoordinate value="300"/>',
+ ' <YCoordinate value="-15"/>',
+ " </LigatureAnchor>",
+ "</ComponentRecord>",
+ ]
def test_buildComponentRecord_empty(self):
- self.assertIsNone(builder.buildComponentRecord([]))
+ assert builder.buildComponentRecord([]) is None
def test_buildComponentRecord_None(self):
- self.assertIsNone(builder.buildComponentRecord(None))
+ assert builder.buildComponentRecord(None) is None
def test_buildCoverage(self):
cov = builder.buildCoverage({"two", "four"}, {"two": 2, "four": 4})
- self.assertEqual(getXML(cov.toXML),
- ['<Coverage>',
- ' <Glyph value="two"/>',
- ' <Glyph value="four"/>',
- '</Coverage>'])
+ assert getXML(cov.toXML) == [
+ "<Coverage>",
+ ' <Glyph value="two"/>',
+ ' <Glyph value="four"/>',
+ "</Coverage>",
+ ]
def test_buildCursivePos(self):
- pos = builder.buildCursivePosSubtable({
- "two": (self.ANCHOR1, self.ANCHOR2),
- "four": (self.ANCHOR3, self.ANCHOR1)
- }, self.GLYPHMAP)
- self.assertEqual(getXML(pos.toXML),
- ['<CursivePos Format="1">',
- ' <Coverage>',
- ' <Glyph value="two"/>',
- ' <Glyph value="four"/>',
- ' </Coverage>',
- ' <!-- EntryExitCount=2 -->',
- ' <EntryExitRecord index="0">',
- ' <EntryAnchor Format="1">',
- ' <XCoordinate value="11"/>',
- ' <YCoordinate value="-11"/>',
- ' </EntryAnchor>',
- ' <ExitAnchor Format="1">',
- ' <XCoordinate value="22"/>',
- ' <YCoordinate value="-22"/>',
- ' </ExitAnchor>',
- ' </EntryExitRecord>',
- ' <EntryExitRecord index="1">',
- ' <EntryAnchor Format="1">',
- ' <XCoordinate value="33"/>',
- ' <YCoordinate value="-33"/>',
- ' </EntryAnchor>',
- ' <ExitAnchor Format="1">',
- ' <XCoordinate value="11"/>',
- ' <YCoordinate value="-11"/>',
- ' </ExitAnchor>',
- ' </EntryExitRecord>',
- '</CursivePos>'])
+ pos = builder.buildCursivePosSubtable(
+ {"two": (self.ANCHOR1, self.ANCHOR2), "four": (self.ANCHOR3, self.ANCHOR1)},
+ self.GLYPHMAP,
+ )
+ assert getXML(pos.toXML) == [
+ '<CursivePos Format="1">',
+ " <Coverage>",
+ ' <Glyph value="two"/>',
+ ' <Glyph value="four"/>',
+ " </Coverage>",
+ " <!-- EntryExitCount=2 -->",
+ ' <EntryExitRecord index="0">',
+ ' <EntryAnchor Format="1">',
+ ' <XCoordinate value="11"/>',
+ ' <YCoordinate value="-11"/>',
+ " </EntryAnchor>",
+ ' <ExitAnchor Format="1">',
+ ' <XCoordinate value="22"/>',
+ ' <YCoordinate value="-22"/>',
+ " </ExitAnchor>",
+ " </EntryExitRecord>",
+ ' <EntryExitRecord index="1">',
+ ' <EntryAnchor Format="1">',
+ ' <XCoordinate value="33"/>',
+ ' <YCoordinate value="-33"/>',
+ " </EntryAnchor>",
+ ' <ExitAnchor Format="1">',
+ ' <XCoordinate value="11"/>',
+ ' <YCoordinate value="-11"/>',
+ " </ExitAnchor>",
+ " </EntryExitRecord>",
+ "</CursivePos>",
+ ]
def test_buildDevice_format1(self):
- device = builder.buildDevice({1:1, 0:0})
- self.assertEqual(getXML(device.toXML),
- ['<Device>',
- ' <StartSize value="0"/>',
- ' <EndSize value="1"/>',
- ' <DeltaFormat value="1"/>',
- ' <DeltaValue value="[0, 1]"/>',
- '</Device>'])
+ device = builder.buildDevice({1: 1, 0: 0})
+ assert getXML(device.toXML) == [
+ "<Device>",
+ ' <StartSize value="0"/>',
+ ' <EndSize value="1"/>',
+ ' <DeltaFormat value="1"/>',
+ ' <DeltaValue value="[0, 1]"/>',
+ "</Device>",
+ ]
def test_buildDevice_format2(self):
- device = builder.buildDevice({2:2, 0:1, 1:0})
- self.assertEqual(getXML(device.toXML),
- ['<Device>',
- ' <StartSize value="0"/>',
- ' <EndSize value="2"/>',
- ' <DeltaFormat value="2"/>',
- ' <DeltaValue value="[1, 0, 2]"/>',
- '</Device>'])
+ device = builder.buildDevice({2: 2, 0: 1, 1: 0})
+ assert getXML(device.toXML) == [
+ "<Device>",
+ ' <StartSize value="0"/>',
+ ' <EndSize value="2"/>',
+ ' <DeltaFormat value="2"/>',
+ ' <DeltaValue value="[1, 0, 2]"/>',
+ "</Device>",
+ ]
def test_buildDevice_format3(self):
- device = builder.buildDevice({5:3, 1:77})
- self.assertEqual(getXML(device.toXML),
- ['<Device>',
- ' <StartSize value="1"/>',
- ' <EndSize value="5"/>',
- ' <DeltaFormat value="3"/>',
- ' <DeltaValue value="[77, 0, 0, 0, 3]"/>',
- '</Device>'])
+ device = builder.buildDevice({5: 3, 1: 77})
+ assert getXML(device.toXML) == [
+ "<Device>",
+ ' <StartSize value="1"/>',
+ ' <EndSize value="5"/>',
+ ' <DeltaFormat value="3"/>',
+ ' <DeltaValue value="[77, 0, 0, 0, 3]"/>',
+ "</Device>",
+ ]
def test_buildLigatureArray(self):
anchor = builder.buildAnchor
- ligatureArray = builder.buildLigatureArray({
- "f_i": [{2: anchor(300, -20)}, {}],
- "c_t": [{}, {1: anchor(500, 350), 2: anchor(1300, -20)}]
- }, numMarkClasses=4, glyphMap=self.GLYPHMAP)
- self.assertEqual(getXML(ligatureArray.toXML),
- ['<LigatureArray>',
- ' <!-- LigatureCount=2 -->',
- ' <LigatureAttach index="0">', # f_i
- ' <!-- ComponentCount=2 -->',
- ' <ComponentRecord index="0">',
- ' <LigatureAnchor index="0" empty="1"/>',
- ' <LigatureAnchor index="1" empty="1"/>',
- ' <LigatureAnchor index="2" Format="1">',
- ' <XCoordinate value="300"/>',
- ' <YCoordinate value="-20"/>',
- ' </LigatureAnchor>',
- ' <LigatureAnchor index="3" empty="1"/>',
- ' </ComponentRecord>',
- ' <ComponentRecord index="1">',
- ' <LigatureAnchor index="0" empty="1"/>',
- ' <LigatureAnchor index="1" empty="1"/>',
- ' <LigatureAnchor index="2" empty="1"/>',
- ' <LigatureAnchor index="3" empty="1"/>',
- ' </ComponentRecord>',
- ' </LigatureAttach>',
- ' <LigatureAttach index="1">',
- ' <!-- ComponentCount=2 -->',
- ' <ComponentRecord index="0">',
- ' <LigatureAnchor index="0" empty="1"/>',
- ' <LigatureAnchor index="1" empty="1"/>',
- ' <LigatureAnchor index="2" empty="1"/>',
- ' <LigatureAnchor index="3" empty="1"/>',
- ' </ComponentRecord>',
- ' <ComponentRecord index="1">',
- ' <LigatureAnchor index="0" empty="1"/>',
- ' <LigatureAnchor index="1" Format="1">',
- ' <XCoordinate value="500"/>',
- ' <YCoordinate value="350"/>',
- ' </LigatureAnchor>',
- ' <LigatureAnchor index="2" Format="1">',
- ' <XCoordinate value="1300"/>',
- ' <YCoordinate value="-20"/>',
- ' </LigatureAnchor>',
- ' <LigatureAnchor index="3" empty="1"/>',
- ' </ComponentRecord>',
- ' </LigatureAttach>',
- '</LigatureArray>'])
+ ligatureArray = builder.buildLigatureArray(
+ {
+ "f_i": [{2: anchor(300, -20)}, {}],
+ "c_t": [{}, {1: anchor(500, 350), 2: anchor(1300, -20)}],
+ },
+ numMarkClasses=4,
+ glyphMap=self.GLYPHMAP,
+ )
+ assert getXML(ligatureArray.toXML) == [
+ "<LigatureArray>",
+ " <!-- LigatureCount=2 -->",
+ ' <LigatureAttach index="0">', # f_i
+ " <!-- ComponentCount=2 -->",
+ ' <ComponentRecord index="0">',
+ ' <LigatureAnchor index="0" empty="1"/>',
+ ' <LigatureAnchor index="1" empty="1"/>',
+ ' <LigatureAnchor index="2" Format="1">',
+ ' <XCoordinate value="300"/>',
+ ' <YCoordinate value="-20"/>',
+ " </LigatureAnchor>",
+ ' <LigatureAnchor index="3" empty="1"/>',
+ " </ComponentRecord>",
+ ' <ComponentRecord index="1">',
+ ' <LigatureAnchor index="0" empty="1"/>',
+ ' <LigatureAnchor index="1" empty="1"/>',
+ ' <LigatureAnchor index="2" empty="1"/>',
+ ' <LigatureAnchor index="3" empty="1"/>',
+ " </ComponentRecord>",
+ " </LigatureAttach>",
+ ' <LigatureAttach index="1">',
+ " <!-- ComponentCount=2 -->",
+ ' <ComponentRecord index="0">',
+ ' <LigatureAnchor index="0" empty="1"/>',
+ ' <LigatureAnchor index="1" empty="1"/>',
+ ' <LigatureAnchor index="2" empty="1"/>',
+ ' <LigatureAnchor index="3" empty="1"/>',
+ " </ComponentRecord>",
+ ' <ComponentRecord index="1">',
+ ' <LigatureAnchor index="0" empty="1"/>',
+ ' <LigatureAnchor index="1" Format="1">',
+ ' <XCoordinate value="500"/>',
+ ' <YCoordinate value="350"/>',
+ " </LigatureAnchor>",
+ ' <LigatureAnchor index="2" Format="1">',
+ ' <XCoordinate value="1300"/>',
+ ' <YCoordinate value="-20"/>',
+ " </LigatureAnchor>",
+ ' <LigatureAnchor index="3" empty="1"/>',
+ " </ComponentRecord>",
+ " </LigatureAttach>",
+ "</LigatureArray>",
+ ]
def test_buildLigatureAttach(self):
anchor = builder.buildAnchor
- attach = builder.buildLigatureAttach([
- [anchor(500, -10), None],
- [None, anchor(300, -20), None]])
- self.assertEqual(getXML(attach.toXML),
- ['<LigatureAttach>',
- ' <!-- ComponentCount=2 -->',
- ' <ComponentRecord index="0">',
- ' <LigatureAnchor index="0" Format="1">',
- ' <XCoordinate value="500"/>',
- ' <YCoordinate value="-10"/>',
- ' </LigatureAnchor>',
- ' <LigatureAnchor index="1" empty="1"/>',
- ' </ComponentRecord>',
- ' <ComponentRecord index="1">',
- ' <LigatureAnchor index="0" empty="1"/>',
- ' <LigatureAnchor index="1" Format="1">',
- ' <XCoordinate value="300"/>',
- ' <YCoordinate value="-20"/>',
- ' </LigatureAnchor>',
- ' <LigatureAnchor index="2" empty="1"/>',
- ' </ComponentRecord>',
- '</LigatureAttach>'])
+ attach = builder.buildLigatureAttach(
+ [[anchor(500, -10), None], [None, anchor(300, -20), None]]
+ )
+ assert getXML(attach.toXML) == [
+ "<LigatureAttach>",
+ " <!-- ComponentCount=2 -->",
+ ' <ComponentRecord index="0">',
+ ' <LigatureAnchor index="0" Format="1">',
+ ' <XCoordinate value="500"/>',
+ ' <YCoordinate value="-10"/>',
+ " </LigatureAnchor>",
+ ' <LigatureAnchor index="1" empty="1"/>',
+ " </ComponentRecord>",
+ ' <ComponentRecord index="1">',
+ ' <LigatureAnchor index="0" empty="1"/>',
+ ' <LigatureAnchor index="1" Format="1">',
+ ' <XCoordinate value="300"/>',
+ ' <YCoordinate value="-20"/>',
+ " </LigatureAnchor>",
+ ' <LigatureAnchor index="2" empty="1"/>',
+ " </ComponentRecord>",
+ "</LigatureAttach>",
+ ]
def test_buildLigatureAttach_emptyComponents(self):
attach = builder.buildLigatureAttach([[], None])
- self.assertEqual(getXML(attach.toXML),
- ['<LigatureAttach>',
- ' <!-- ComponentCount=2 -->',
- ' <ComponentRecord index="0" empty="1"/>',
- ' <ComponentRecord index="1" empty="1"/>',
- '</LigatureAttach>'])
+ assert getXML(attach.toXML) == [
+ "<LigatureAttach>",
+ " <!-- ComponentCount=2 -->",
+ ' <ComponentRecord index="0" empty="1"/>',
+ ' <ComponentRecord index="1" empty="1"/>',
+ "</LigatureAttach>",
+ ]
def test_buildLigatureAttach_noComponents(self):
attach = builder.buildLigatureAttach([])
- self.assertEqual(getXML(attach.toXML),
- ['<LigatureAttach>',
- ' <!-- ComponentCount=0 -->',
- '</LigatureAttach>'])
+ assert getXML(attach.toXML) == [
+ "<LigatureAttach>",
+ " <!-- ComponentCount=0 -->",
+ "</LigatureAttach>",
+ ]
def test_buildLigCaretList(self):
carets = builder.buildLigCaretList(
- {"f_f_i": [300, 600]}, {"c_t": [42]}, self.GLYPHMAP)
- self.assertEqual(getXML(carets.toXML),
- ['<LigCaretList>',
- ' <Coverage>',
- ' <Glyph value="f_f_i"/>',
- ' <Glyph value="c_t"/>',
- ' </Coverage>',
- ' <!-- LigGlyphCount=2 -->',
- ' <LigGlyph index="0">',
- ' <!-- CaretCount=2 -->',
- ' <CaretValue index="0" Format="1">',
- ' <Coordinate value="300"/>',
- ' </CaretValue>',
- ' <CaretValue index="1" Format="1">',
- ' <Coordinate value="600"/>',
- ' </CaretValue>',
- ' </LigGlyph>',
- ' <LigGlyph index="1">',
- ' <!-- CaretCount=1 -->',
- ' <CaretValue index="0" Format="2">',
- ' <CaretValuePoint value="42"/>',
- ' </CaretValue>',
- ' </LigGlyph>',
- '</LigCaretList>'])
+ {"f_f_i": [300, 600]}, {"c_t": [42]}, self.GLYPHMAP
+ )
+ assert getXML(carets.toXML) == [
+ "<LigCaretList>",
+ " <Coverage>",
+ ' <Glyph value="f_f_i"/>',
+ ' <Glyph value="c_t"/>',
+ " </Coverage>",
+ " <!-- LigGlyphCount=2 -->",
+ ' <LigGlyph index="0">',
+ " <!-- CaretCount=2 -->",
+ ' <CaretValue index="0" Format="1">',
+ ' <Coordinate value="300"/>',
+ " </CaretValue>",
+ ' <CaretValue index="1" Format="1">',
+ ' <Coordinate value="600"/>',
+ " </CaretValue>",
+ " </LigGlyph>",
+ ' <LigGlyph index="1">',
+ " <!-- CaretCount=1 -->",
+ ' <CaretValue index="0" Format="2">',
+ ' <CaretValuePoint value="42"/>',
+ " </CaretValue>",
+ " </LigGlyph>",
+ "</LigCaretList>",
+ ]
def test_buildLigCaretList_bothCoordsAndPointsForSameGlyph(self):
carets = builder.buildLigCaretList(
- {"f_f_i": [300]}, {"f_f_i": [7]}, self.GLYPHMAP)
- self.assertEqual(getXML(carets.toXML),
- ['<LigCaretList>',
- ' <Coverage>',
- ' <Glyph value="f_f_i"/>',
- ' </Coverage>',
- ' <!-- LigGlyphCount=1 -->',
- ' <LigGlyph index="0">',
- ' <!-- CaretCount=2 -->',
- ' <CaretValue index="0" Format="1">',
- ' <Coordinate value="300"/>',
- ' </CaretValue>',
- ' <CaretValue index="1" Format="2">',
- ' <CaretValuePoint value="7"/>',
- ' </CaretValue>',
- ' </LigGlyph>',
- '</LigCaretList>'])
+ {"f_f_i": [300]}, {"f_f_i": [7]}, self.GLYPHMAP
+ )
+ assert getXML(carets.toXML) == [
+ "<LigCaretList>",
+ " <Coverage>",
+ ' <Glyph value="f_f_i"/>',
+ " </Coverage>",
+ " <!-- LigGlyphCount=1 -->",
+ ' <LigGlyph index="0">',
+ " <!-- CaretCount=2 -->",
+ ' <CaretValue index="0" Format="1">',
+ ' <Coordinate value="300"/>',
+ " </CaretValue>",
+ ' <CaretValue index="1" Format="2">',
+ ' <CaretValuePoint value="7"/>',
+ " </CaretValue>",
+ " </LigGlyph>",
+ "</LigCaretList>",
+ ]
def test_buildLigCaretList_empty(self):
- self.assertIsNone(builder.buildLigCaretList({}, {}, self.GLYPHMAP))
+ assert builder.buildLigCaretList({}, {}, self.GLYPHMAP) is None
def test_buildLigCaretList_None(self):
- self.assertIsNone(builder.buildLigCaretList(None, None, self.GLYPHMAP))
+ assert builder.buildLigCaretList(None, None, self.GLYPHMAP) is None
def test_buildLigGlyph_coords(self):
lig = builder.buildLigGlyph([500, 800], None)
- self.assertEqual(getXML(lig.toXML),
- ['<LigGlyph>',
- ' <!-- CaretCount=2 -->',
- ' <CaretValue index="0" Format="1">',
- ' <Coordinate value="500"/>',
- ' </CaretValue>',
- ' <CaretValue index="1" Format="1">',
- ' <Coordinate value="800"/>',
- ' </CaretValue>',
- '</LigGlyph>'])
+ assert getXML(lig.toXML) == [
+ "<LigGlyph>",
+ " <!-- CaretCount=2 -->",
+ ' <CaretValue index="0" Format="1">',
+ ' <Coordinate value="500"/>',
+ " </CaretValue>",
+ ' <CaretValue index="1" Format="1">',
+ ' <Coordinate value="800"/>',
+ " </CaretValue>",
+ "</LigGlyph>",
+ ]
def test_buildLigGlyph_empty(self):
- self.assertIsNone(builder.buildLigGlyph([], []))
+ assert builder.buildLigGlyph([], []) is None
def test_buildLigGlyph_None(self):
- self.assertIsNone(builder.buildLigGlyph(None, None))
+ assert builder.buildLigGlyph(None, None) is None
def test_buildLigGlyph_points(self):
lig = builder.buildLigGlyph(None, [2])
- self.assertEqual(getXML(lig.toXML),
- ['<LigGlyph>',
- ' <!-- CaretCount=1 -->',
- ' <CaretValue index="0" Format="2">',
- ' <CaretValuePoint value="2"/>',
- ' </CaretValue>',
- '</LigGlyph>'])
+ assert getXML(lig.toXML) == [
+ "<LigGlyph>",
+ " <!-- CaretCount=1 -->",
+ ' <CaretValue index="0" Format="2">',
+ ' <CaretValuePoint value="2"/>',
+ " </CaretValue>",
+ "</LigGlyph>",
+ ]
def test_buildLookup(self):
s1 = builder.buildSingleSubstSubtable({"one": "two"})
s2 = builder.buildSingleSubstSubtable({"three": "four"})
lookup = builder.buildLookup([s1, s2], flags=7)
- self.assertEqual(getXML(lookup.toXML),
- ['<Lookup>',
- ' <LookupType value="1"/>',
- ' <LookupFlag value="7"/>',
- ' <!-- SubTableCount=2 -->',
- ' <SingleSubst index="0">',
- ' <Substitution in="one" out="two"/>',
- ' </SingleSubst>',
- ' <SingleSubst index="1">',
- ' <Substitution in="three" out="four"/>',
- ' </SingleSubst>',
- '</Lookup>'])
+ assert getXML(lookup.toXML) == [
+ "<Lookup>",
+ ' <LookupType value="1"/>',
+ ' <LookupFlag value="7"/>',
+ " <!-- SubTableCount=2 -->",
+ ' <SingleSubst index="0">',
+ ' <Substitution in="one" out="two"/>',
+ " </SingleSubst>",
+ ' <SingleSubst index="1">',
+ ' <Substitution in="three" out="four"/>',
+ " </SingleSubst>",
+ "</Lookup>",
+ ]
def test_buildLookup_badFlags(self):
s = builder.buildSingleSubstSubtable({"one": "two"})
- self.assertRaisesRegex(
- AssertionError, "if markFilterSet is None, "
- "flags must not set LOOKUP_FLAG_USE_MARK_FILTERING_SET; "
- "flags=0x0010",
- builder.buildLookup, [s],
- builder.LOOKUP_FLAG_USE_MARK_FILTERING_SET, None)
- self.assertRaisesRegex(
- AssertionError, "if markFilterSet is not None, "
- "flags must set LOOKUP_FLAG_USE_MARK_FILTERING_SET; "
- "flags=0x0004",
- builder.buildLookup, [s],
- builder.LOOKUP_FLAG_IGNORE_LIGATURES, 777)
+ with pytest.raises(
+ AssertionError,
+ match=(
+ "if markFilterSet is None, flags must not set "
+ "LOOKUP_FLAG_USE_MARK_FILTERING_SET; flags=0x0010"
+ ),
+ ) as excinfo:
+ builder.buildLookup([s], builder.LOOKUP_FLAG_USE_MARK_FILTERING_SET, None)
+ with pytest.raises(
+ AssertionError,
+ match=(
+ "if markFilterSet is not None, flags must set "
+ "LOOKUP_FLAG_USE_MARK_FILTERING_SET; flags=0x0004"
+ ),
+ ) as excinfo:
+ builder.buildLookup([s], builder.LOOKUP_FLAG_IGNORE_LIGATURES, 777)
def test_buildLookup_conflictingSubtableTypes(self):
s1 = builder.buildSingleSubstSubtable({"one": "two"})
s2 = builder.buildAlternateSubstSubtable({"one": ["two", "three"]})
- self.assertRaisesRegex(
- AssertionError, "all subtables must have the same LookupType",
- builder.buildLookup, [s1, s2])
+ with pytest.raises(
+ AssertionError, match="all subtables must have the same LookupType"
+ ) as excinfo:
+ builder.buildLookup([s1, s2])
def test_buildLookup_noSubtables(self):
- self.assertIsNone(builder.buildLookup([]))
- self.assertIsNone(builder.buildLookup(None))
- self.assertIsNone(builder.buildLookup([None]))
- self.assertIsNone(builder.buildLookup([None, None]))
+ assert builder.buildLookup([]) is None
+ assert builder.buildLookup(None) is None
+ assert builder.buildLookup([None]) is None
+ assert builder.buildLookup([None, None]) is None
def test_buildLookup_markFilterSet(self):
s = builder.buildSingleSubstSubtable({"one": "two"})
- flags = (builder.LOOKUP_FLAG_RIGHT_TO_LEFT |
- builder.LOOKUP_FLAG_USE_MARK_FILTERING_SET)
+ flags = (
+ builder.LOOKUP_FLAG_RIGHT_TO_LEFT
+ | builder.LOOKUP_FLAG_USE_MARK_FILTERING_SET
+ )
lookup = builder.buildLookup([s], flags, markFilterSet=999)
- self.assertEqual(getXML(lookup.toXML),
- ['<Lookup>',
- ' <LookupType value="1"/>',
- ' <LookupFlag value="17"/>',
- ' <!-- SubTableCount=1 -->',
- ' <SingleSubst index="0">',
- ' <Substitution in="one" out="two"/>',
- ' </SingleSubst>',
- ' <MarkFilteringSet value="999"/>',
- '</Lookup>'])
+ assert getXML(lookup.toXML) == [
+ "<Lookup>",
+ ' <LookupType value="1"/>',
+ ' <LookupFlag value="17"/>',
+ " <!-- SubTableCount=1 -->",
+ ' <SingleSubst index="0">',
+ ' <Substitution in="one" out="two"/>',
+ " </SingleSubst>",
+ ' <MarkFilteringSet value="999"/>',
+ "</Lookup>",
+ ]
def test_buildMarkArray(self):
- markArray = builder.buildMarkArray({
- "acute": (7, builder.buildAnchor(300, 800)),
- "grave": (2, builder.buildAnchor(10, 80))
- }, self.GLYPHMAP)
- self.assertLess(self.GLYPHMAP["grave"], self.GLYPHMAP["acute"])
- self.assertEqual(getXML(markArray.toXML),
- ['<MarkArray>',
- ' <!-- MarkCount=2 -->',
- ' <MarkRecord index="0">',
- ' <Class value="2"/>',
- ' <MarkAnchor Format="1">',
- ' <XCoordinate value="10"/>',
- ' <YCoordinate value="80"/>',
- ' </MarkAnchor>',
- ' </MarkRecord>',
- ' <MarkRecord index="1">',
- ' <Class value="7"/>',
- ' <MarkAnchor Format="1">',
- ' <XCoordinate value="300"/>',
- ' <YCoordinate value="800"/>',
- ' </MarkAnchor>',
- ' </MarkRecord>',
- '</MarkArray>'])
+ markArray = builder.buildMarkArray(
+ {
+ "acute": (7, builder.buildAnchor(300, 800)),
+ "grave": (2, builder.buildAnchor(10, 80)),
+ },
+ self.GLYPHMAP,
+ )
+ assert self.GLYPHMAP["grave"] < self.GLYPHMAP["acute"]
+ assert getXML(markArray.toXML) == [
+ "<MarkArray>",
+ " <!-- MarkCount=2 -->",
+ ' <MarkRecord index="0">',
+ ' <Class value="2"/>',
+ ' <MarkAnchor Format="1">',
+ ' <XCoordinate value="10"/>',
+ ' <YCoordinate value="80"/>',
+ " </MarkAnchor>",
+ " </MarkRecord>",
+ ' <MarkRecord index="1">',
+ ' <Class value="7"/>',
+ ' <MarkAnchor Format="1">',
+ ' <XCoordinate value="300"/>',
+ ' <YCoordinate value="800"/>',
+ " </MarkAnchor>",
+ " </MarkRecord>",
+ "</MarkArray>",
+ ]
def test_buildMarkBasePosSubtable(self):
anchor = builder.buildAnchor
marks = {
"acute": (0, anchor(300, 700)),
"cedilla": (1, anchor(300, -100)),
- "grave": (0, anchor(300, 700))
+ "grave": (0, anchor(300, 700)),
}
bases = {
# Make sure we can handle missing entries.
"A": {}, # no entry for any markClass
"B": {0: anchor(500, 900)}, # only markClass 0 specified
"C": {1: anchor(500, -10)}, # only markClass 1 specified
-
"a": {0: anchor(500, 400), 1: anchor(500, -20)},
- "b": {0: anchor(500, 800), 1: anchor(500, -20)}
+ "b": {0: anchor(500, 800), 1: anchor(500, -20)},
}
table = builder.buildMarkBasePosSubtable(marks, bases, self.GLYPHMAP)
- self.assertEqual(getXML(table.toXML),
- ['<MarkBasePos Format="1">',
- ' <MarkCoverage>',
- ' <Glyph value="grave"/>',
- ' <Glyph value="acute"/>',
- ' <Glyph value="cedilla"/>',
- ' </MarkCoverage>',
- ' <BaseCoverage>',
- ' <Glyph value="A"/>',
- ' <Glyph value="B"/>',
- ' <Glyph value="C"/>',
- ' <Glyph value="a"/>',
- ' <Glyph value="b"/>',
- ' </BaseCoverage>',
- ' <!-- ClassCount=2 -->',
- ' <MarkArray>',
- ' <!-- MarkCount=3 -->',
- ' <MarkRecord index="0">', # grave
- ' <Class value="0"/>',
- ' <MarkAnchor Format="1">',
- ' <XCoordinate value="300"/>',
- ' <YCoordinate value="700"/>',
- ' </MarkAnchor>',
- ' </MarkRecord>',
- ' <MarkRecord index="1">', # acute
- ' <Class value="0"/>',
- ' <MarkAnchor Format="1">',
- ' <XCoordinate value="300"/>',
- ' <YCoordinate value="700"/>',
- ' </MarkAnchor>',
- ' </MarkRecord>',
- ' <MarkRecord index="2">', # cedilla
- ' <Class value="1"/>',
- ' <MarkAnchor Format="1">',
- ' <XCoordinate value="300"/>',
- ' <YCoordinate value="-100"/>',
- ' </MarkAnchor>',
- ' </MarkRecord>',
- ' </MarkArray>',
- ' <BaseArray>',
- ' <!-- BaseCount=5 -->',
- ' <BaseRecord index="0">', # A
- ' <BaseAnchor index="0" empty="1"/>',
- ' <BaseAnchor index="1" empty="1"/>',
- ' </BaseRecord>',
- ' <BaseRecord index="1">', # B
- ' <BaseAnchor index="0" Format="1">',
- ' <XCoordinate value="500"/>',
- ' <YCoordinate value="900"/>',
- ' </BaseAnchor>',
- ' <BaseAnchor index="1" empty="1"/>',
- ' </BaseRecord>',
- ' <BaseRecord index="2">', # C
- ' <BaseAnchor index="0" empty="1"/>',
- ' <BaseAnchor index="1" Format="1">',
- ' <XCoordinate value="500"/>',
- ' <YCoordinate value="-10"/>',
- ' </BaseAnchor>',
- ' </BaseRecord>',
- ' <BaseRecord index="3">', # a
- ' <BaseAnchor index="0" Format="1">',
- ' <XCoordinate value="500"/>',
- ' <YCoordinate value="400"/>',
- ' </BaseAnchor>',
- ' <BaseAnchor index="1" Format="1">',
- ' <XCoordinate value="500"/>',
- ' <YCoordinate value="-20"/>',
- ' </BaseAnchor>',
- ' </BaseRecord>',
- ' <BaseRecord index="4">', # b
- ' <BaseAnchor index="0" Format="1">',
- ' <XCoordinate value="500"/>',
- ' <YCoordinate value="800"/>',
- ' </BaseAnchor>',
- ' <BaseAnchor index="1" Format="1">',
- ' <XCoordinate value="500"/>',
- ' <YCoordinate value="-20"/>',
- ' </BaseAnchor>',
- ' </BaseRecord>',
- ' </BaseArray>',
- '</MarkBasePos>'])
+ assert getXML(table.toXML) == [
+ '<MarkBasePos Format="1">',
+ " <MarkCoverage>",
+ ' <Glyph value="grave"/>',
+ ' <Glyph value="acute"/>',
+ ' <Glyph value="cedilla"/>',
+ " </MarkCoverage>",
+ " <BaseCoverage>",
+ ' <Glyph value="A"/>',
+ ' <Glyph value="B"/>',
+ ' <Glyph value="C"/>',
+ ' <Glyph value="a"/>',
+ ' <Glyph value="b"/>',
+ " </BaseCoverage>",
+ " <!-- ClassCount=2 -->",
+ " <MarkArray>",
+ " <!-- MarkCount=3 -->",
+ ' <MarkRecord index="0">', # grave
+ ' <Class value="0"/>',
+ ' <MarkAnchor Format="1">',
+ ' <XCoordinate value="300"/>',
+ ' <YCoordinate value="700"/>',
+ " </MarkAnchor>",
+ " </MarkRecord>",
+ ' <MarkRecord index="1">', # acute
+ ' <Class value="0"/>',
+ ' <MarkAnchor Format="1">',
+ ' <XCoordinate value="300"/>',
+ ' <YCoordinate value="700"/>',
+ " </MarkAnchor>",
+ " </MarkRecord>",
+ ' <MarkRecord index="2">', # cedilla
+ ' <Class value="1"/>',
+ ' <MarkAnchor Format="1">',
+ ' <XCoordinate value="300"/>',
+ ' <YCoordinate value="-100"/>',
+ " </MarkAnchor>",
+ " </MarkRecord>",
+ " </MarkArray>",
+ " <BaseArray>",
+ " <!-- BaseCount=5 -->",
+ ' <BaseRecord index="0">', # A
+ ' <BaseAnchor index="0" empty="1"/>',
+ ' <BaseAnchor index="1" empty="1"/>',
+ " </BaseRecord>",
+ ' <BaseRecord index="1">', # B
+ ' <BaseAnchor index="0" Format="1">',
+ ' <XCoordinate value="500"/>',
+ ' <YCoordinate value="900"/>',
+ " </BaseAnchor>",
+ ' <BaseAnchor index="1" empty="1"/>',
+ " </BaseRecord>",
+ ' <BaseRecord index="2">', # C
+ ' <BaseAnchor index="0" empty="1"/>',
+ ' <BaseAnchor index="1" Format="1">',
+ ' <XCoordinate value="500"/>',
+ ' <YCoordinate value="-10"/>',
+ " </BaseAnchor>",
+ " </BaseRecord>",
+ ' <BaseRecord index="3">', # a
+ ' <BaseAnchor index="0" Format="1">',
+ ' <XCoordinate value="500"/>',
+ ' <YCoordinate value="400"/>',
+ " </BaseAnchor>",
+ ' <BaseAnchor index="1" Format="1">',
+ ' <XCoordinate value="500"/>',
+ ' <YCoordinate value="-20"/>',
+ " </BaseAnchor>",
+ " </BaseRecord>",
+ ' <BaseRecord index="4">', # b
+ ' <BaseAnchor index="0" Format="1">',
+ ' <XCoordinate value="500"/>',
+ ' <YCoordinate value="800"/>',
+ " </BaseAnchor>",
+ ' <BaseAnchor index="1" Format="1">',
+ ' <XCoordinate value="500"/>',
+ ' <YCoordinate value="-20"/>',
+ " </BaseAnchor>",
+ " </BaseRecord>",
+ " </BaseArray>",
+ "</MarkBasePos>",
+ ]
def test_buildMarkGlyphSetsDef(self):
marksets = builder.buildMarkGlyphSetsDef(
- [{"acute", "grave"}, {"cedilla", "grave"}], self.GLYPHMAP)
- self.assertEqual(getXML(marksets.toXML),
- ['<MarkGlyphSetsDef>',
- ' <MarkSetTableFormat value="1"/>',
- ' <!-- MarkSetCount=2 -->',
- ' <Coverage index="0">',
- ' <Glyph value="grave"/>',
- ' <Glyph value="acute"/>',
- ' </Coverage>',
- ' <Coverage index="1">',
- ' <Glyph value="grave"/>',
- ' <Glyph value="cedilla"/>',
- ' </Coverage>',
- '</MarkGlyphSetsDef>'])
+ [{"acute", "grave"}, {"cedilla", "grave"}], self.GLYPHMAP
+ )
+ assert getXML(marksets.toXML) == [
+ "<MarkGlyphSetsDef>",
+ ' <MarkSetTableFormat value="1"/>',
+ " <!-- MarkSetCount=2 -->",
+ ' <Coverage index="0">',
+ ' <Glyph value="grave"/>',
+ ' <Glyph value="acute"/>',
+ " </Coverage>",
+ ' <Coverage index="1">',
+ ' <Glyph value="grave"/>',
+ ' <Glyph value="cedilla"/>',
+ " </Coverage>",
+ "</MarkGlyphSetsDef>",
+ ]
def test_buildMarkGlyphSetsDef_empty(self):
- self.assertIsNone(builder.buildMarkGlyphSetsDef([], self.GLYPHMAP))
+ assert builder.buildMarkGlyphSetsDef([], self.GLYPHMAP) is None
def test_buildMarkGlyphSetsDef_None(self):
- self.assertIsNone(builder.buildMarkGlyphSetsDef(None, self.GLYPHMAP))
+ assert builder.buildMarkGlyphSetsDef(None, self.GLYPHMAP) is None
def test_buildMarkLigPosSubtable(self):
anchor = builder.buildAnchor
marks = {
"acute": (0, anchor(300, 700)),
"cedilla": (1, anchor(300, -100)),
- "grave": (0, anchor(300, 700))
+ "grave": (0, anchor(300, 700)),
}
bases = {
"f_i": [{}, {0: anchor(200, 400)}], # nothing on f; only 1 on i
"c_t": [
- {0: anchor(500, 600), 1: anchor(500, -20)}, # c
- {0: anchor(1300, 800), 1: anchor(1300, -20)} # t
- ]
+ {0: anchor(500, 600), 1: anchor(500, -20)}, # c
+ {0: anchor(1300, 800), 1: anchor(1300, -20)}, # t
+ ],
}
table = builder.buildMarkLigPosSubtable(marks, bases, self.GLYPHMAP)
- self.assertEqual(getXML(table.toXML),
- ['<MarkLigPos Format="1">',
- ' <MarkCoverage>',
- ' <Glyph value="grave"/>',
- ' <Glyph value="acute"/>',
- ' <Glyph value="cedilla"/>',
- ' </MarkCoverage>',
- ' <LigatureCoverage>',
- ' <Glyph value="f_i"/>',
- ' <Glyph value="c_t"/>',
- ' </LigatureCoverage>',
- ' <!-- ClassCount=2 -->',
- ' <MarkArray>',
- ' <!-- MarkCount=3 -->',
- ' <MarkRecord index="0">',
- ' <Class value="0"/>',
- ' <MarkAnchor Format="1">',
- ' <XCoordinate value="300"/>',
- ' <YCoordinate value="700"/>',
- ' </MarkAnchor>',
- ' </MarkRecord>',
- ' <MarkRecord index="1">',
- ' <Class value="0"/>',
- ' <MarkAnchor Format="1">',
- ' <XCoordinate value="300"/>',
- ' <YCoordinate value="700"/>',
- ' </MarkAnchor>',
- ' </MarkRecord>',
- ' <MarkRecord index="2">',
- ' <Class value="1"/>',
- ' <MarkAnchor Format="1">',
- ' <XCoordinate value="300"/>',
- ' <YCoordinate value="-100"/>',
- ' </MarkAnchor>',
- ' </MarkRecord>',
- ' </MarkArray>',
- ' <LigatureArray>',
- ' <!-- LigatureCount=2 -->',
- ' <LigatureAttach index="0">',
- ' <!-- ComponentCount=2 -->',
- ' <ComponentRecord index="0">',
- ' <LigatureAnchor index="0" empty="1"/>',
- ' <LigatureAnchor index="1" empty="1"/>',
- ' </ComponentRecord>',
- ' <ComponentRecord index="1">',
- ' <LigatureAnchor index="0" Format="1">',
- ' <XCoordinate value="200"/>',
- ' <YCoordinate value="400"/>',
- ' </LigatureAnchor>',
- ' <LigatureAnchor index="1" empty="1"/>',
- ' </ComponentRecord>',
- ' </LigatureAttach>',
- ' <LigatureAttach index="1">',
- ' <!-- ComponentCount=2 -->',
- ' <ComponentRecord index="0">',
- ' <LigatureAnchor index="0" Format="1">',
- ' <XCoordinate value="500"/>',
- ' <YCoordinate value="600"/>',
- ' </LigatureAnchor>',
- ' <LigatureAnchor index="1" Format="1">',
- ' <XCoordinate value="500"/>',
- ' <YCoordinate value="-20"/>',
- ' </LigatureAnchor>',
- ' </ComponentRecord>',
- ' <ComponentRecord index="1">',
- ' <LigatureAnchor index="0" Format="1">',
- ' <XCoordinate value="1300"/>',
- ' <YCoordinate value="800"/>',
- ' </LigatureAnchor>',
- ' <LigatureAnchor index="1" Format="1">',
- ' <XCoordinate value="1300"/>',
- ' <YCoordinate value="-20"/>',
- ' </LigatureAnchor>',
- ' </ComponentRecord>',
- ' </LigatureAttach>',
- ' </LigatureArray>',
- '</MarkLigPos>'])
+ assert getXML(table.toXML) == [
+ '<MarkLigPos Format="1">',
+ " <MarkCoverage>",
+ ' <Glyph value="grave"/>',
+ ' <Glyph value="acute"/>',
+ ' <Glyph value="cedilla"/>',
+ " </MarkCoverage>",
+ " <LigatureCoverage>",
+ ' <Glyph value="f_i"/>',
+ ' <Glyph value="c_t"/>',
+ " </LigatureCoverage>",
+ " <!-- ClassCount=2 -->",
+ " <MarkArray>",
+ " <!-- MarkCount=3 -->",
+ ' <MarkRecord index="0">',
+ ' <Class value="0"/>',
+ ' <MarkAnchor Format="1">',
+ ' <XCoordinate value="300"/>',
+ ' <YCoordinate value="700"/>',
+ " </MarkAnchor>",
+ " </MarkRecord>",
+ ' <MarkRecord index="1">',
+ ' <Class value="0"/>',
+ ' <MarkAnchor Format="1">',
+ ' <XCoordinate value="300"/>',
+ ' <YCoordinate value="700"/>',
+ " </MarkAnchor>",
+ " </MarkRecord>",
+ ' <MarkRecord index="2">',
+ ' <Class value="1"/>',
+ ' <MarkAnchor Format="1">',
+ ' <XCoordinate value="300"/>',
+ ' <YCoordinate value="-100"/>',
+ " </MarkAnchor>",
+ " </MarkRecord>",
+ " </MarkArray>",
+ " <LigatureArray>",
+ " <!-- LigatureCount=2 -->",
+ ' <LigatureAttach index="0">',
+ " <!-- ComponentCount=2 -->",
+ ' <ComponentRecord index="0">',
+ ' <LigatureAnchor index="0" empty="1"/>',
+ ' <LigatureAnchor index="1" empty="1"/>',
+ " </ComponentRecord>",
+ ' <ComponentRecord index="1">',
+ ' <LigatureAnchor index="0" Format="1">',
+ ' <XCoordinate value="200"/>',
+ ' <YCoordinate value="400"/>',
+ " </LigatureAnchor>",
+ ' <LigatureAnchor index="1" empty="1"/>',
+ " </ComponentRecord>",
+ " </LigatureAttach>",
+ ' <LigatureAttach index="1">',
+ " <!-- ComponentCount=2 -->",
+ ' <ComponentRecord index="0">',
+ ' <LigatureAnchor index="0" Format="1">',
+ ' <XCoordinate value="500"/>',
+ ' <YCoordinate value="600"/>',
+ " </LigatureAnchor>",
+ ' <LigatureAnchor index="1" Format="1">',
+ ' <XCoordinate value="500"/>',
+ ' <YCoordinate value="-20"/>',
+ " </LigatureAnchor>",
+ " </ComponentRecord>",
+ ' <ComponentRecord index="1">',
+ ' <LigatureAnchor index="0" Format="1">',
+ ' <XCoordinate value="1300"/>',
+ ' <YCoordinate value="800"/>',
+ " </LigatureAnchor>",
+ ' <LigatureAnchor index="1" Format="1">',
+ ' <XCoordinate value="1300"/>',
+ ' <YCoordinate value="-20"/>',
+ " </LigatureAnchor>",
+ " </ComponentRecord>",
+ " </LigatureAttach>",
+ " </LigatureArray>",
+ "</MarkLigPos>",
+ ]
def test_buildMarkRecord(self):
rec = builder.buildMarkRecord(17, builder.buildAnchor(500, -20))
- self.assertEqual(getXML(rec.toXML),
- ['<MarkRecord>',
- ' <Class value="17"/>',
- ' <MarkAnchor Format="1">',
- ' <XCoordinate value="500"/>',
- ' <YCoordinate value="-20"/>',
- ' </MarkAnchor>',
- '</MarkRecord>'])
+ assert getXML(rec.toXML) == [
+ "<MarkRecord>",
+ ' <Class value="17"/>',
+ ' <MarkAnchor Format="1">',
+ ' <XCoordinate value="500"/>',
+ ' <YCoordinate value="-20"/>',
+ " </MarkAnchor>",
+ "</MarkRecord>",
+ ]
def test_buildMark2Record(self):
a = builder.buildAnchor
rec = builder.buildMark2Record([a(500, -20), None, a(300, -15)])
- self.assertEqual(getXML(rec.toXML),
- ['<Mark2Record>',
- ' <Mark2Anchor index="0" Format="1">',
- ' <XCoordinate value="500"/>',
- ' <YCoordinate value="-20"/>',
- ' </Mark2Anchor>',
- ' <Mark2Anchor index="1" empty="1"/>',
- ' <Mark2Anchor index="2" Format="1">',
- ' <XCoordinate value="300"/>',
- ' <YCoordinate value="-15"/>',
- ' </Mark2Anchor>',
- '</Mark2Record>'])
+ assert getXML(rec.toXML) == [
+ "<Mark2Record>",
+ ' <Mark2Anchor index="0" Format="1">',
+ ' <XCoordinate value="500"/>',
+ ' <YCoordinate value="-20"/>',
+ " </Mark2Anchor>",
+ ' <Mark2Anchor index="1" empty="1"/>',
+ ' <Mark2Anchor index="2" Format="1">',
+ ' <XCoordinate value="300"/>',
+ ' <YCoordinate value="-15"/>',
+ " </Mark2Anchor>",
+ "</Mark2Record>",
+ ]
def test_buildPairPosClassesSubtable(self):
d20 = builder.buildValue({"XPlacement": -20})
d50 = builder.buildValue({"XPlacement": -50})
d0 = builder.buildValue({})
d8020 = builder.buildValue({"XPlacement": -80, "YPlacement": -20})
- subtable = builder.buildPairPosClassesSubtable({
- (tuple("A",), tuple(["zero"])): (d0, d50),
- (tuple("A",), tuple(["one", "two"])): (None, d20),
- (tuple(["B", "C"]), tuple(["zero"])): (d8020, d50),
- }, self.GLYPHMAP)
- self.assertEqual(getXML(subtable.toXML),
- ['<PairPos Format="2">',
- ' <Coverage>',
- ' <Glyph value="A"/>',
- ' <Glyph value="B"/>',
- ' <Glyph value="C"/>',
- ' </Coverage>',
- ' <ValueFormat1 value="3"/>',
- ' <ValueFormat2 value="1"/>',
- ' <ClassDef1>',
- ' <ClassDef glyph="A" class="1"/>',
- ' </ClassDef1>',
- ' <ClassDef2>',
- ' <ClassDef glyph="one" class="1"/>',
- ' <ClassDef glyph="two" class="1"/>',
- ' <ClassDef glyph="zero" class="2"/>',
- ' </ClassDef2>',
- ' <!-- Class1Count=2 -->',
- ' <!-- Class2Count=3 -->',
- ' <Class1Record index="0">',
- ' <Class2Record index="0">',
- ' </Class2Record>',
- ' <Class2Record index="1">',
- ' </Class2Record>',
- ' <Class2Record index="2">',
- ' <Value1 XPlacement="-80" YPlacement="-20"/>',
- ' <Value2 XPlacement="-50"/>',
- ' </Class2Record>',
- ' </Class1Record>',
- ' <Class1Record index="1">',
- ' <Class2Record index="0">',
- ' </Class2Record>',
- ' <Class2Record index="1">',
- ' <Value2 XPlacement="-20"/>',
- ' </Class2Record>',
- ' <Class2Record index="2">',
- ' <Value1/>',
- ' <Value2 XPlacement="-50"/>',
- ' </Class2Record>',
- ' </Class1Record>',
- '</PairPos>'])
+ subtable = builder.buildPairPosClassesSubtable(
+ {
+ (tuple("A"), tuple(["zero"])): (d0, d50),
+ (tuple("A"), tuple(["one", "two"])): (None, d20),
+ (tuple(["B", "C"]), tuple(["zero"])): (d8020, d50),
+ },
+ self.GLYPHMAP,
+ )
+ assert getXML(subtable.toXML) == [
+ '<PairPos Format="2">',
+ " <Coverage>",
+ ' <Glyph value="A"/>',
+ ' <Glyph value="B"/>',
+ ' <Glyph value="C"/>',
+ " </Coverage>",
+ ' <ValueFormat1 value="3"/>',
+ ' <ValueFormat2 value="1"/>',
+ " <ClassDef1>",
+ ' <ClassDef glyph="A" class="1"/>',
+ " </ClassDef1>",
+ " <ClassDef2>",
+ ' <ClassDef glyph="one" class="1"/>',
+ ' <ClassDef glyph="two" class="1"/>',
+ ' <ClassDef glyph="zero" class="2"/>',
+ " </ClassDef2>",
+ " <!-- Class1Count=2 -->",
+ " <!-- Class2Count=3 -->",
+ ' <Class1Record index="0">',
+ ' <Class2Record index="0">',
+ " </Class2Record>",
+ ' <Class2Record index="1">',
+ " </Class2Record>",
+ ' <Class2Record index="2">',
+ ' <Value1 XPlacement="-80" YPlacement="-20"/>',
+ ' <Value2 XPlacement="-50"/>',
+ " </Class2Record>",
+ " </Class1Record>",
+ ' <Class1Record index="1">',
+ ' <Class2Record index="0">',
+ " </Class2Record>",
+ ' <Class2Record index="1">',
+ ' <Value2 XPlacement="-20"/>',
+ " </Class2Record>",
+ ' <Class2Record index="2">',
+ " <Value1/>",
+ ' <Value2 XPlacement="-50"/>',
+ " </Class2Record>",
+ " </Class1Record>",
+ "</PairPos>",
+ ]
def test_buildPairPosGlyphs(self):
d50 = builder.buildValue({"XPlacement": -50})
d8020 = builder.buildValue({"XPlacement": -80, "YPlacement": -20})
- subtables = builder.buildPairPosGlyphs({
- ("A", "zero"): (None, d50),
- ("A", "one"): (d8020, d50),
- }, self.GLYPHMAP)
- self.assertEqual(sum([getXML(t.toXML) for t in subtables], []),
- ['<PairPos Format="1">',
- ' <Coverage>',
- ' <Glyph value="A"/>',
- ' </Coverage>',
- ' <ValueFormat1 value="0"/>',
- ' <ValueFormat2 value="1"/>',
- ' <!-- PairSetCount=1 -->',
- ' <PairSet index="0">',
- ' <!-- PairValueCount=1 -->',
- ' <PairValueRecord index="0">',
- ' <SecondGlyph value="zero"/>',
- ' <Value2 XPlacement="-50"/>',
- ' </PairValueRecord>',
- ' </PairSet>',
- '</PairPos>',
- '<PairPos Format="1">',
- ' <Coverage>',
- ' <Glyph value="A"/>',
- ' </Coverage>',
- ' <ValueFormat1 value="3"/>',
- ' <ValueFormat2 value="1"/>',
- ' <!-- PairSetCount=1 -->',
- ' <PairSet index="0">',
- ' <!-- PairValueCount=1 -->',
- ' <PairValueRecord index="0">',
- ' <SecondGlyph value="one"/>',
- ' <Value1 XPlacement="-80" YPlacement="-20"/>',
- ' <Value2 XPlacement="-50"/>',
- ' </PairValueRecord>',
- ' </PairSet>',
- '</PairPos>'])
+ subtables = builder.buildPairPosGlyphs(
+ {("A", "zero"): (None, d50), ("A", "one"): (d8020, d50)}, self.GLYPHMAP
+ )
+ assert sum([getXML(t.toXML) for t in subtables], []) == [
+ '<PairPos Format="1">',
+ " <Coverage>",
+ ' <Glyph value="A"/>',
+ " </Coverage>",
+ ' <ValueFormat1 value="0"/>',
+ ' <ValueFormat2 value="1"/>',
+ " <!-- PairSetCount=1 -->",
+ ' <PairSet index="0">',
+ " <!-- PairValueCount=1 -->",
+ ' <PairValueRecord index="0">',
+ ' <SecondGlyph value="zero"/>',
+ ' <Value2 XPlacement="-50"/>',
+ " </PairValueRecord>",
+ " </PairSet>",
+ "</PairPos>",
+ '<PairPos Format="1">',
+ " <Coverage>",
+ ' <Glyph value="A"/>',
+ " </Coverage>",
+ ' <ValueFormat1 value="3"/>',
+ ' <ValueFormat2 value="1"/>',
+ " <!-- PairSetCount=1 -->",
+ ' <PairSet index="0">',
+ " <!-- PairValueCount=1 -->",
+ ' <PairValueRecord index="0">',
+ ' <SecondGlyph value="one"/>',
+ ' <Value1 XPlacement="-80" YPlacement="-20"/>',
+ ' <Value2 XPlacement="-50"/>',
+ " </PairValueRecord>",
+ " </PairSet>",
+ "</PairPos>",
+ ]
def test_buildPairPosGlyphsSubtable(self):
d20 = builder.buildValue({"XPlacement": -20})
d50 = builder.buildValue({"XPlacement": -50})
d0 = builder.buildValue({})
d8020 = builder.buildValue({"XPlacement": -80, "YPlacement": -20})
- subtable = builder.buildPairPosGlyphsSubtable({
- ("A", "zero"): (d0, d50),
- ("A", "one"): (None, d20),
- ("B", "five"): (d8020, d50),
- }, self.GLYPHMAP)
- self.assertEqual(getXML(subtable.toXML),
- ['<PairPos Format="1">',
- ' <Coverage>',
- ' <Glyph value="A"/>',
- ' <Glyph value="B"/>',
- ' </Coverage>',
- ' <ValueFormat1 value="3"/>',
- ' <ValueFormat2 value="1"/>',
- ' <!-- PairSetCount=2 -->',
- ' <PairSet index="0">',
- ' <!-- PairValueCount=2 -->',
- ' <PairValueRecord index="0">',
- ' <SecondGlyph value="zero"/>',
- ' <Value2 XPlacement="-50"/>',
- ' </PairValueRecord>',
- ' <PairValueRecord index="1">',
- ' <SecondGlyph value="one"/>',
- ' <Value2 XPlacement="-20"/>',
- ' </PairValueRecord>',
- ' </PairSet>',
- ' <PairSet index="1">',
- ' <!-- PairValueCount=1 -->',
- ' <PairValueRecord index="0">',
- ' <SecondGlyph value="five"/>',
- ' <Value1 XPlacement="-80" YPlacement="-20"/>',
- ' <Value2 XPlacement="-50"/>',
- ' </PairValueRecord>',
- ' </PairSet>',
- '</PairPos>'])
+ subtable = builder.buildPairPosGlyphsSubtable(
+ {
+ ("A", "zero"): (d0, d50),
+ ("A", "one"): (None, d20),
+ ("B", "five"): (d8020, d50),
+ },
+ self.GLYPHMAP,
+ )
+ assert getXML(subtable.toXML) == [
+ '<PairPos Format="1">',
+ " <Coverage>",
+ ' <Glyph value="A"/>',
+ ' <Glyph value="B"/>',
+ " </Coverage>",
+ ' <ValueFormat1 value="3"/>',
+ ' <ValueFormat2 value="1"/>',
+ " <!-- PairSetCount=2 -->",
+ ' <PairSet index="0">',
+ " <!-- PairValueCount=2 -->",
+ ' <PairValueRecord index="0">',
+ ' <SecondGlyph value="zero"/>',
+ ' <Value2 XPlacement="-50"/>',
+ " </PairValueRecord>",
+ ' <PairValueRecord index="1">',
+ ' <SecondGlyph value="one"/>',
+ ' <Value2 XPlacement="-20"/>',
+ " </PairValueRecord>",
+ " </PairSet>",
+ ' <PairSet index="1">',
+ " <!-- PairValueCount=1 -->",
+ ' <PairValueRecord index="0">',
+ ' <SecondGlyph value="five"/>',
+ ' <Value1 XPlacement="-80" YPlacement="-20"/>',
+ ' <Value2 XPlacement="-50"/>',
+ " </PairValueRecord>",
+ " </PairSet>",
+ "</PairPos>",
+ ]
def test_buildSinglePos(self):
- subtables = builder.buildSinglePos({
- "one": builder.buildValue({"XPlacement": 500}),
- "two": builder.buildValue({"XPlacement": 500}),
- "three": builder.buildValue({"XPlacement": 200}),
- "four": builder.buildValue({"XPlacement": 400}),
- "five": builder.buildValue({"XPlacement": 500}),
- "six": builder.buildValue({"YPlacement": -6}),
- }, self.GLYPHMAP)
- self.assertEqual(sum([getXML(t.toXML) for t in subtables], []),
- ['<SinglePos Format="2">',
- ' <Coverage>',
- ' <Glyph value="one"/>',
- ' <Glyph value="two"/>',
- ' <Glyph value="three"/>',
- ' <Glyph value="four"/>',
- ' <Glyph value="five"/>',
- ' </Coverage>',
- ' <ValueFormat value="1"/>',
- ' <!-- ValueCount=5 -->',
- ' <Value index="0" XPlacement="500"/>',
- ' <Value index="1" XPlacement="500"/>',
- ' <Value index="2" XPlacement="200"/>',
- ' <Value index="3" XPlacement="400"/>',
- ' <Value index="4" XPlacement="500"/>',
- '</SinglePos>',
- '<SinglePos Format="1">',
- ' <Coverage>',
- ' <Glyph value="six"/>',
- ' </Coverage>',
- ' <ValueFormat value="2"/>',
- ' <Value YPlacement="-6"/>',
- '</SinglePos>'])
+ subtables = builder.buildSinglePos(
+ {
+ "one": builder.buildValue({"XPlacement": 500}),
+ "two": builder.buildValue({"XPlacement": 500}),
+ "three": builder.buildValue({"XPlacement": 200}),
+ "four": builder.buildValue({"XPlacement": 400}),
+ "five": builder.buildValue({"XPlacement": 500}),
+ "six": builder.buildValue({"YPlacement": -6}),
+ },
+ self.GLYPHMAP,
+ )
+ assert sum([getXML(t.toXML) for t in subtables], []) == [
+ '<SinglePos Format="2">',
+ " <Coverage>",
+ ' <Glyph value="one"/>',
+ ' <Glyph value="two"/>',
+ ' <Glyph value="three"/>',
+ ' <Glyph value="four"/>',
+ ' <Glyph value="five"/>',
+ " </Coverage>",
+ ' <ValueFormat value="1"/>',
+ " <!-- ValueCount=5 -->",
+ ' <Value index="0" XPlacement="500"/>',
+ ' <Value index="1" XPlacement="500"/>',
+ ' <Value index="2" XPlacement="200"/>',
+ ' <Value index="3" XPlacement="400"/>',
+ ' <Value index="4" XPlacement="500"/>',
+ "</SinglePos>",
+ '<SinglePos Format="1">',
+ " <Coverage>",
+ ' <Glyph value="six"/>',
+ " </Coverage>",
+ ' <ValueFormat value="2"/>',
+ ' <Value YPlacement="-6"/>',
+ "</SinglePos>",
+ ]
def test_buildSinglePos_ValueFormat0(self):
- subtables = builder.buildSinglePos({
- "zero": builder.buildValue({})
- }, self.GLYPHMAP)
- self.assertEqual(sum([getXML(t.toXML) for t in subtables], []),
- ['<SinglePos Format="1">',
- ' <Coverage>',
- ' <Glyph value="zero"/>',
- ' </Coverage>',
- ' <ValueFormat value="0"/>',
- '</SinglePos>'])
+ subtables = builder.buildSinglePos(
+ {"zero": builder.buildValue({})}, self.GLYPHMAP
+ )
+ assert sum([getXML(t.toXML) for t in subtables], []) == [
+ '<SinglePos Format="1">',
+ " <Coverage>",
+ ' <Glyph value="zero"/>',
+ " </Coverage>",
+ ' <ValueFormat value="0"/>',
+ "</SinglePos>",
+ ]
def test_buildSinglePosSubtable_format1(self):
- subtable = builder.buildSinglePosSubtable({
- "one": builder.buildValue({"XPlacement": 777}),
- "two": builder.buildValue({"XPlacement": 777}),
- }, self.GLYPHMAP)
- self.assertEqual(getXML(subtable.toXML),
- ['<SinglePos Format="1">',
- ' <Coverage>',
- ' <Glyph value="one"/>',
- ' <Glyph value="two"/>',
- ' </Coverage>',
- ' <ValueFormat value="1"/>',
- ' <Value XPlacement="777"/>',
- '</SinglePos>'])
+ subtable = builder.buildSinglePosSubtable(
+ {
+ "one": builder.buildValue({"XPlacement": 777}),
+ "two": builder.buildValue({"XPlacement": 777}),
+ },
+ self.GLYPHMAP,
+ )
+ assert getXML(subtable.toXML) == [
+ '<SinglePos Format="1">',
+ " <Coverage>",
+ ' <Glyph value="one"/>',
+ ' <Glyph value="two"/>',
+ " </Coverage>",
+ ' <ValueFormat value="1"/>',
+ ' <Value XPlacement="777"/>',
+ "</SinglePos>",
+ ]
def test_buildSinglePosSubtable_format2(self):
- subtable = builder.buildSinglePosSubtable({
- "one": builder.buildValue({"XPlacement": 777}),
- "two": builder.buildValue({"YPlacement": -888}),
- }, self.GLYPHMAP)
- self.assertEqual(getXML(subtable.toXML),
- ['<SinglePos Format="2">',
- ' <Coverage>',
- ' <Glyph value="one"/>',
- ' <Glyph value="two"/>',
- ' </Coverage>',
- ' <ValueFormat value="3"/>',
- ' <!-- ValueCount=2 -->',
- ' <Value index="0" XPlacement="777"/>',
- ' <Value index="1" YPlacement="-888"/>',
- '</SinglePos>'])
+ subtable = builder.buildSinglePosSubtable(
+ {
+ "one": builder.buildValue({"XPlacement": 777}),
+ "two": builder.buildValue({"YPlacement": -888}),
+ },
+ self.GLYPHMAP,
+ )
+ assert getXML(subtable.toXML) == [
+ '<SinglePos Format="2">',
+ " <Coverage>",
+ ' <Glyph value="one"/>',
+ ' <Glyph value="two"/>',
+ " </Coverage>",
+ ' <ValueFormat value="3"/>',
+ " <!-- ValueCount=2 -->",
+ ' <Value index="0" XPlacement="777"/>',
+ ' <Value index="1" YPlacement="-888"/>',
+ "</SinglePos>",
+ ]
def test_buildValue(self):
value = builder.buildValue({"XPlacement": 7, "YPlacement": 23})
func = lambda writer, font: value.toXML(writer, font, valueName="Val")
- self.assertEqual(getXML(func),
- ['<Val XPlacement="7" YPlacement="23"/>'])
+ assert getXML(func) == ['<Val XPlacement="7" YPlacement="23"/>']
def test_getLigatureKey(self):
components = lambda s: [tuple(word) for word in s.split()]
c = components("fi fl ff ffi fff")
c.sort(key=builder._getLigatureKey)
- self.assertEqual(c, components("fff ffi ff fi fl"))
+ assert c == components("fff ffi ff fi fl")
def test_getSinglePosValueKey(self):
- device = builder.buildDevice({10:1, 11:3})
+ device = builder.buildDevice({10: 1, 11: 3})
a1 = builder.buildValue({"XPlacement": 500, "XPlaDevice": device})
a2 = builder.buildValue({"XPlacement": 500, "XPlaDevice": device})
b = builder.buildValue({"XPlacement": 500})
keyA1 = builder._getSinglePosValueKey(a1)
keyA2 = builder._getSinglePosValueKey(a1)
keyB = builder._getSinglePosValueKey(b)
- self.assertEqual(keyA1, keyA2)
- self.assertEqual(hash(keyA1), hash(keyA2))
- self.assertNotEqual(keyA1, keyB)
- self.assertNotEqual(hash(keyA1), hash(keyB))
+ assert keyA1 == keyA2
+ assert hash(keyA1) == hash(keyA2)
+ assert keyA1 != keyB
+ assert hash(keyA1) != hash(keyB)
-class ClassDefBuilderTest(unittest.TestCase):
+class ClassDefBuilderTest(object):
def test_build_usingClass0(self):
b = builder.ClassDefBuilder(useClass0=True)
b.add({"aa", "bb"})
@@ -1015,14 +1075,8 @@ class ClassDefBuilderTest(unittest.TestCase):
b.add({"c"})
b.add({"e", "f", "g", "h"})
cdef = b.build()
- self.assertIsInstance(cdef, otTables.ClassDef)
- self.assertEqual(cdef.classDefs, {
- "a": 2,
- "b": 2,
- "c": 3,
- "aa": 1,
- "bb": 1
- })
+ assert isinstance(cdef, otTables.ClassDef)
+ assert cdef.classDefs == {"a": 2, "b": 2, "c": 3, "aa": 1, "bb": 1}
def test_build_notUsingClass0(self):
b = builder.ClassDefBuilder(useClass0=False)
@@ -1030,30 +1084,31 @@ class ClassDefBuilderTest(unittest.TestCase):
b.add({"c"})
b.add({"e", "f", "g", "h"})
cdef = b.build()
- self.assertIsInstance(cdef, otTables.ClassDef)
- self.assertEqual(cdef.classDefs, {
+ assert isinstance(cdef, otTables.ClassDef)
+ assert cdef.classDefs == {
"a": 2,
"b": 2,
"c": 3,
"e": 1,
"f": 1,
"g": 1,
- "h": 1
- })
+ "h": 1,
+ }
def test_canAdd(self):
b = builder.ClassDefBuilder(useClass0=True)
b.add({"a", "b", "c", "d"})
b.add({"e", "f"})
- self.assertTrue(b.canAdd({"a", "b", "c", "d"}))
- self.assertTrue(b.canAdd({"e", "f"}))
- self.assertTrue(b.canAdd({"g", "h", "i"}))
- self.assertFalse(b.canAdd({"b", "c", "d"}))
- self.assertFalse(b.canAdd({"a", "b", "c", "d", "e", "f"}))
- self.assertFalse(b.canAdd({"d", "e", "f"}))
- self.assertFalse(b.canAdd({"f"}))
+ assert b.canAdd({"a", "b", "c", "d"})
+ assert b.canAdd({"e", "f"})
+ assert b.canAdd({"g", "h", "i"})
+ assert not b.canAdd({"b", "c", "d"})
+ assert not b.canAdd({"a", "b", "c", "d", "e", "f"})
+ assert not b.canAdd({"d", "e", "f"})
+ assert not b.canAdd({"f"})
if __name__ == "__main__":
import sys
- sys.exit(unittest.main())
+
+ sys.exit(pytest.main(sys.argv))
diff --git a/Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w0.00.ttx b/Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w0.00.ttx
index 57731584..f6568fd8 100644
--- a/Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w0.00.ttx
+++ b/Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w0.00.ttx
@@ -374,6 +374,7 @@
<FontName value="MasterSet_Kanji-w0.00-Generic"/>
<Private>
<BlueValues value="-250 -250 1100 1100"/>
+ <FamilyBlues value="-250 -240 1100 1110"/>
<BlueScale value="0.039625"/>
<BlueShift value="7"/>
<BlueFuzz value="0"/>
diff --git a/Tests/varLib/data/test_results/BuildMain.ttx b/Tests/varLib/data/test_results/BuildMain.ttx
index 7150a579..7e5d9561 100644
--- a/Tests/varLib/data/test_results/BuildMain.ttx
+++ b/Tests/varLib/data/test_results/BuildMain.ttx
@@ -55,7 +55,7 @@
will be recalculated by the compiler -->
<version value="4"/>
<xAvgCharWidth value="506"/>
- <usWeightClass value="400"/>
+ <usWeightClass value="368"/>
<usWidthClass value="5"/>
<fsType value="00000000 00000100"/>
<ySubscriptXSize value="650"/>
diff --git a/Tests/varLib/data/test_results/BuildTestCFF2.ttx b/Tests/varLib/data/test_results/BuildTestCFF2.ttx
index 91b83fc0..29044525 100644
--- a/Tests/varLib/data/test_results/BuildTestCFF2.ttx
+++ b/Tests/varLib/data/test_results/BuildTestCFF2.ttx
@@ -86,10 +86,10 @@
<BlueShift value="7"/>
<BlueFuzz value="0"/>
<StdHW>
- <blend value="67 -39.0 67.0"/>
+ <blend value="67 -39 67"/>
</StdHW>
<StdVW>
- <blend value="85 -51.0 87.0"/>
+ <blend value="85 -51 87"/>
</StdVW>
</Private>
</FontDict>
diff --git a/Tests/varLib/data/test_results/SparseMasters.ttx b/Tests/varLib/data/test_results/SparseMasters.ttx
index 06e58c92..c2aa335c 100644
--- a/Tests/varLib/data/test_results/SparseMasters.ttx
+++ b/Tests/varLib/data/test_results/SparseMasters.ttx
@@ -55,7 +55,7 @@
will be recalculated by the compiler -->
<version value="4"/>
<xAvgCharWidth value="580"/>
- <usWeightClass value="400"/>
+ <usWeightClass value="350"/>
<usWidthClass value="5"/>
<fsType value="00000000 00000100"/>
<ySubscriptXSize value="650"/>
diff --git a/Tests/varLib/data/test_results/TestNonMarkingCFF2.ttx b/Tests/varLib/data/test_results/TestNonMarkingCFF2.ttx
index 5ded5b91..26bd7ba7 100644
--- a/Tests/varLib/data/test_results/TestNonMarkingCFF2.ttx
+++ b/Tests/varLib/data/test_results/TestNonMarkingCFF2.ttx
@@ -31,10 +31,10 @@
<BlueShift value="7"/>
<BlueFuzz value="0"/>
<StdHW>
- <blend value="28 39.0"/>
+ <blend value="28 39"/>
</StdHW>
<StdVW>
- <blend value="34 51.0"/>
+ <blend value="34 51"/>
</StdVW>
</Private>
</FontDict>
diff --git a/Tests/varLib/data/test_results/TestSparseCFF2VF.ttx b/Tests/varLib/data/test_results/TestSparseCFF2VF.ttx
index 442ae91e..f05f62f7 100644
--- a/Tests/varLib/data/test_results/TestSparseCFF2VF.ttx
+++ b/Tests/varLib/data/test_results/TestSparseCFF2VF.ttx
@@ -132,6 +132,7 @@
<FontDict index="0">
<Private>
<BlueValues value="-250 -250 1100 1100"/>
+ <FamilyBlues value="-250 -240 1100 1110"/>
<BlueScale value="0.039625"/>
<BlueShift value="7"/>
<BlueFuzz value="0"/>
diff --git a/Tests/varLib/varLib_test.py b/Tests/varLib/varLib_test.py
index e29befbf..ec05d565 100644
--- a/Tests/varLib/varLib_test.py
+++ b/Tests/varLib/varLib_test.py
@@ -4,6 +4,7 @@ from fontTools.ttLib import TTFont, newTable
from fontTools.varLib import build
from fontTools.varLib.mutator import instantiateVariableFont
from fontTools.varLib import main as varLib_main, load_masters
+from fontTools.varLib import set_default_weight_width_slant
from fontTools.designspaceLib import (
DesignSpaceDocumentError, DesignSpaceDocument, SourceDescriptor,
)
@@ -661,5 +662,81 @@ def _extract_flat_kerning(font, pairpos_table):
return extracted_kerning
+@pytest.fixture
+def ttFont():
+ f = TTFont()
+ f["OS/2"] = newTable("OS/2")
+ f["OS/2"].usWeightClass = 400
+ f["OS/2"].usWidthClass = 100
+ f["post"] = newTable("post")
+ f["post"].italicAngle = 0
+ return f
+
+
+class SetDefaultWeightWidthSlantTest(object):
+ @pytest.mark.parametrize(
+ "location, expected",
+ [
+ ({"wght": 0}, 1),
+ ({"wght": 1}, 1),
+ ({"wght": 100}, 100),
+ ({"wght": 1000}, 1000),
+ ({"wght": 1001}, 1000),
+ ],
+ )
+ def test_wght(self, ttFont, location, expected):
+ set_default_weight_width_slant(ttFont, location)
+
+ assert ttFont["OS/2"].usWeightClass == expected
+
+ @pytest.mark.parametrize(
+ "location, expected",
+ [
+ ({"wdth": 0}, 1),
+ ({"wdth": 56}, 1),
+ ({"wdth": 57}, 2),
+ ({"wdth": 62.5}, 2),
+ ({"wdth": 75}, 3),
+ ({"wdth": 87.5}, 4),
+ ({"wdth": 100}, 5),
+ ({"wdth": 112.5}, 6),
+ ({"wdth": 125}, 7),
+ ({"wdth": 150}, 8),
+ ({"wdth": 200}, 9),
+ ({"wdth": 201}, 9),
+ ({"wdth": 1000}, 9),
+ ],
+ )
+ def test_wdth(self, ttFont, location, expected):
+ set_default_weight_width_slant(ttFont, location)
+
+ assert ttFont["OS/2"].usWidthClass == expected
+
+ @pytest.mark.parametrize(
+ "location, expected",
+ [
+ ({"slnt": -91}, -90),
+ ({"slnt": -90}, -90),
+ ({"slnt": 0}, 0),
+ ({"slnt": 11.5}, 11.5),
+ ({"slnt": 90}, 90),
+ ({"slnt": 91}, 90),
+ ],
+ )
+ def test_slnt(self, ttFont, location, expected):
+ set_default_weight_width_slant(ttFont, location)
+
+ assert ttFont["post"].italicAngle == expected
+
+ def test_all(self, ttFont):
+ set_default_weight_width_slant(
+ ttFont, {"wght": 500, "wdth": 150, "slnt": -12.0}
+ )
+
+ assert ttFont["OS/2"].usWeightClass == 500
+ assert ttFont["OS/2"].usWidthClass == 8
+ assert ttFont["post"].italicAngle == -12.0
+
+
if __name__ == "__main__":
sys.exit(unittest.main())
diff --git a/setup.cfg b/setup.cfg
index c7b9d0a5..a5287c05 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,5 @@
[bumpversion]
-current_version = 3.43.1
+current_version = 3.43.2
commit = True
tag = False
tag_name = {new_version}
diff --git a/setup.py b/setup.py
index ea4c92a9..eca6a351 100755
--- a/setup.py
+++ b/setup.py
@@ -352,7 +352,7 @@ def find_data_files(manpath="share/man"):
setup(
name="fonttools",
- version="3.43.1",
+ version="3.43.2",
description="Tools to manipulate font files",
author="Just van Rossum",
author_email="just@letterror.com",