Snap for 8426163 from 375cb3ca5498f918169cf83acfb5abc6cd950495 to mainline-tzdata2-release

Change-Id: Id6e891e13ff23313c4f4866e794ba3ebd6600829
diff --git a/.appveyor.yml b/.appveyor.yml
new file mode 100644
index 0000000..9701df6
--- /dev/null
+++ b/.appveyor.yml
@@ -0,0 +1,57 @@
+environment:
+  matrix:
+    - JOB: "2.7 32-bit"
+      PYTHON_HOME: "C:\\Python27"
+
+    - JOB: "3.7 64-bit"
+      PYTHON_HOME: "C:\\Python37-x64"
+
+branches:
+  only:
+    - master
+    # We want to build wip/* branches since these are not usually used for PRs
+    - /^wip\/.*$/
+    # We want to build version tags as well.
+    - /^\d+\.\d+.*$/
+
+install:
+  # If there is a newer build queued for the same PR, cancel this one.
+  # The AppVeyor 'rollout builds' option is supposed to serve the same
+  # purpose but it is problematic because it tends to cancel builds pushed
+  # directly to master instead of just PR builds (or the converse).
+  # credits: JuliaLang developers.
+  - ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
+        https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `
+        Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
+          throw "There are newer queued builds for this pull request, failing early." }
+
+  # Prepend Python to the PATH of this build
+  - "SET PATH=%PYTHON_HOME%;%PYTHON_HOME%\\Scripts;%PATH%"
+
+  # check that we have the expected version and architecture for Python
+  - "python --version"
+  - "python -c \"import struct; print(struct.calcsize('P') * 8)\""
+
+  # upgrade pip and setuptools to avoid out-of-date warnings
+  - "python -m pip install --disable-pip-version-check --user --upgrade pip setuptools virtualenv"
+
+  # install the dependencies to run the tests
+  - "python -m pip install tox"
+
+build: false
+
+test_script:
+  # run tests with the current 'python' in %PATH%, and measure test coverage
+  - "tox -e py-cov"
+
+after_test:
+  # upload test coverage to Codecov.io
+  - "tox -e codecov"
+
+notifications:
+  - provider: Email
+    to:
+      - fonttools-dev@googlegroups.com
+    on_build_success: false
+    on_build_failure: true
+    on_build_status_changed: true
diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index b3b2b25..0000000
--- a/.gitattributes
+++ /dev/null
@@ -1,11 +0,0 @@
-# Set the default behavior, in case people don't have core.autocrlf set.
-* text=auto
-
-# Explicitly declare text files you want to always be normalized and converted
-# to native line endings on checkout.
-*.py text
-
-# Font files are binary (so that autocrlf doesn't muck with them)
-*.lwfn binary
-*.pfa binary
-*.pfb binary
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
deleted file mode 100644
index ec6abe2..0000000
--- a/.github/workflows/publish.yml
+++ /dev/null
@@ -1,31 +0,0 @@
-# This workflows will upload a Python Package using Twine when a tag is created
-# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
-
-name: Upload Python Package
-
-on:
-  push:
-    # Sequence of patterns matched against refs/tags
-    tags:
-      - '*.*.*' # e.g. 1.0.0 or 20.15.10
-
-jobs:
-  deploy:
-    runs-on: ubuntu-latest
-
-    steps:
-    - uses: actions/checkout@v2
-    - name: Set up Python
-      uses: actions/setup-python@v2
-      with:
-        python-version: '3.x'
-    - name: Install dependencies
-      run: |
-        pip install setuptools wheel twine
-    - name: Build and publish
-      env:
-        TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
-        TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
-      run: |
-        python setup.py sdist bdist_wheel
-        twine upload dist/*
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
deleted file mode 100644
index 89d668d..0000000
--- a/.github/workflows/test.yml
+++ /dev/null
@@ -1,91 +0,0 @@
-name: Test
-
-on:
-  push:
-    branches: [main]
-  pull_request:
-    branches: [main]
-
-jobs:
-  lint:
-    runs-on: ubuntu-latest
-    # https://github.community/t/github-actions-does-not-respect-skip-ci/17325/8
-    if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')"
-    steps:
-    - uses: actions/checkout@v2
-    - name: Set up Python 3.x
-      uses: actions/setup-python@v2
-      with:
-        python-version: "3.x"
-    - name: Install packages
-      run: pip install tox
-    - name: Run Tox
-      run: tox -e mypy,package_readme
-
-  test:
-    runs-on: ${{ matrix.platform }}
-    if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')"
-    strategy:
-      matrix:
-        python-version: [3.6, 3.7, 3.8, 3.9]
-        platform: [ubuntu-latest, macos-latest, windows-latest]
-        exclude: # Only test on the oldest and latest supported stable Python on macOS and Windows.
-          - platform: macos-latest
-            python-version: 3.7
-          - platform: macos-latest
-            python-version: 3.8
-          - platform: windows-latest
-            python-version: 3.7
-          - platform: windows-latest
-            python-version: 3.8
-    steps:
-    - uses: actions/checkout@v2
-    - name: Set up Python ${{ matrix.python-version }}
-      uses: actions/setup-python@v2
-      with:
-        python-version: ${{ matrix.python-version }}
-    - name: Install packages
-      run: pip install tox coverage
-    - name: Run Tox
-      run: tox -e py-cov
-    - name: Run Tox without lxml
-      run: tox -e py-cov-nolxml
-    - name: Produce coverage files
-      run: |
-        coverage combine
-        coverage xml
-    - name: Upload coverage to Codecov
-      uses: codecov/codecov-action@v1
-      with:
-        file: coverage.xml
-        flags: unittests
-        name: codecov-umbrella
-        fail_ci_if_error: true
-
-  test-cython:
-    runs-on: ubuntu-latest
-    if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')"
-    steps:
-    - uses: actions/checkout@v2
-    - name: Set up Python 3.x
-      uses: actions/setup-python@v2
-      with:
-        python-version: "3.x"
-    - name: Install packages
-      run: pip install tox
-    - name: Run Tox
-      run: tox -e py-cy-nolxml
-
-  test-pypy3:
-    runs-on: ubuntu-latest
-    if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')"
-    steps:
-    - uses: actions/checkout@v2
-    - name: Set up Python pypy3
-      uses: actions/setup-python@v2
-      with:
-        python-version: "pypy3"
-    - name: Install packages
-      run: pip install tox
-    - name: Run Tox
-      run: tox -e pypy3-nolxml
diff --git a/.gitignore b/.gitignore
index eba633e..4fca027 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,59 +1,3 @@
-# Byte-compiled / optimized / DLL files
-__pycache__/
-*.py[cod]
-*$py.class
-
-# C extensions
-*.so
-
-# Distribution / packaging
-.Python
-build/
-dist/
-.eggs/
-*.egg-info/
-*.egg
 MANIFEST
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.coverage
-.coverage.*
-.cache
-coverage.xml
-*.cover
-.pytest_cache/
-
-# Environments
-.env
-.venv
-env/
-venv/
-ENV/
-env.bak/
-venv.bak/
-
-# mypy
-.mypy_cache/
-.dmypy.json
-dmypy.json
-
-# emacs backup files
-*~
-
-# OSX Finder
-.DS_Store
-
-# VSCode
-.vscode
-
-# Cython sources (e.g. cu2qu)
-Lib/**/*.c
-
-# Ctags
-tags
+build
+dist
diff --git a/.pyup.yml b/.pyup.yml
deleted file mode 100644
index 6ea2065..0000000
--- a/.pyup.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-# autogenerated pyup.io config file 
-# see https://pyup.io/docs/configuration/ for all available options
-
-schedule: every week
diff --git a/.readthedocs.yml b/.readthedocs.yml
deleted file mode 100644
index 928d658..0000000
--- a/.readthedocs.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-# .readthedocs.yml
-# Read the Docs configuration file
-# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
-
-# Required
-version: 2
-
-build:
-  image: latest
-
-# Build documentation in the docs/ directory with Sphinx
-sphinx:
-  configuration: Doc/source/conf.py
-  fail_on_warning: false
-
-# Optionally build your docs in additional formats such as PDF and ePub
-formats:
-  - htmlzip
-  - epub
-
-# Optionally set the version of Python and requirements required to build your docs
-python:
-  version: 3.8
-  install:
-    - requirements: Doc/docs-requirements.txt
-    - method: pip
-      path: .
-      extra_requirements:
-        - all
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..66f80fc
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,99 @@
+language: python
+python: 3.5
+
+env:
+  global:
+    - TWINE_USERNAME="anthrotype"
+    - secure: PJuCmlDuwnojiw3QuDhfNAaU4f/yeJcEcRzJAudA66bwZK7hvxV7Tiy9A17Bm6yO0HbJmmyjsIr8h2e7/PyY6QCaV8RqcMDkQ0UraU16pRsihp0giVXJoWscj2sCP4cNDOBVwSaGAX8yZ2OONc5srESywghzcy8xmgw6O+XFqx4=
+
+branches:
+  only:
+    - master
+    # We want to build wip/* branches since these are not usually used for PRs
+    - /^wip\/.*$/
+    # We want to build version tags as well.
+    - /^\d+\.\d+.*$/
+
+matrix:
+  fast_finish: true
+  exclude:
+    # Exclude the default Python 3.5 build
+    - python: 3.5
+  include:
+    - python: 2.7
+      env: TOXENV=py27-cov
+    - python: 3.5
+      env: TOXENV=py35-cov
+    - python: 3.6
+      env:
+        - TOXENV=py36-cov,package_readme
+        - BUILD_DIST=true
+    - python: 3.7
+      env: TOXENV=py37-cov
+      # required to run python3.7 on Travis CI
+      # https://github.com/travis-ci/travis-ci/issues/9815
+      dist: xenial
+    - python: pypy2.7-6.0
+      # disable coverage.py on pypy because of performance problems
+      env: TOXENV=pypy
+      dist: xenial
+    - language: generic
+      os: osx
+      env: TOXENV=py27-cov
+    - language: generic
+      os: osx
+      env:
+        - TOXENV=py3-cov
+        - HOMEBREW_NO_AUTO_UPDATE=1
+    - env:
+        - TOXENV=py27
+        - PYENV_VERSION='2.7.6'
+        - PYENV_VERSION_STRING='Python 2.7.6'
+        - PYENV_ROOT=$HOME/.travis-pyenv
+        - TRAVIS_PYENV_VERSION='0.4.0'
+  allow_failures:
+    # We use fast_finish + allow_failures because OSX builds take forever
+    # https://blog.travis-ci.com/2013-11-27-fast-finishing-builds
+    - language: generic
+      os: osx
+      env: TOXENV=py27-cov
+    - language: generic
+      os: osx
+      env:
+        - TOXENV=py3-cov
+        - HOMEBREW_NO_AUTO_UPDATE=1
+
+cache:
+  - pip
+  - directories:
+    - $HOME/.pyenv_cache
+
+before_install:
+  - source ./.travis/before_install.sh
+
+install:
+  - ./.travis/install.sh
+
+script:
+  - ./.travis/run.sh
+
+after_success:
+  - ./.travis/after_success.sh
+
+notifications:
+  irc: "irc.freenode.org##fonts"
+  email: fonttools-dev@googlegroups.com
+
+deploy:
+  # deploy to Github Releases on tags
+  - provider: releases
+    api_key:
+      secure: KEcWhJxMcnKay7wmWJCpg2W5GWHTQ+LaRbqGM11IKGcQuEOFxWuG7W1xjGpVdKPj/MQ+cG0b9hGUFpls1hwseOA1HANMv4xjCgYkuvT1OdpX/KOcZ7gfe/qaovzVxHyP9xwohnHSJMb790t37fmDfFUSROx3iEexIX09LLoDjO8=
+    skip_cleanup: true
+    file_glob: true
+    file: "dist/*"
+    on:
+      tags: true
+      repo: fonttools/fonttools
+      all_branches: true
+      condition: "$BUILD_DIST == true"
diff --git a/.travis/after_success.sh b/.travis/after_success.sh
new file mode 100755
index 0000000..07bcab5
--- /dev/null
+++ b/.travis/after_success.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+set -x
+
+if [ "$TRAVIS_OS_NAME" == "osx" ]; then
+    source .venv/bin/activate
+fi
+
+# upload coverage data to Codecov.io
+[[ ${TOXENV} == *"-cov"* ]] && tox -e codecov
+
+# if tagged commit, create distribution packages and deploy to PyPI
+if [ -n "$TRAVIS_TAG" ] && [ "$TRAVIS_REPO_SLUG" == "fonttools/fonttools" ] && [ "$BUILD_DIST" == true ]; then
+    tox -e pypi
+fi
diff --git a/.travis/before_install.sh b/.travis/before_install.sh
new file mode 100755
index 0000000..8cc4edb
--- /dev/null
+++ b/.travis/before_install.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+if [[ -n "$PYENV_VERSION" ]]; then
+    wget https://github.com/praekeltfoundation/travis-pyenv/releases/download/${TRAVIS_PYENV_VERSION}/setup-pyenv.sh
+    source setup-pyenv.sh
+fi
diff --git a/.travis/install.sh b/.travis/install.sh
new file mode 100755
index 0000000..f2a0717
--- /dev/null
+++ b/.travis/install.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+set -e
+set -x
+
+ci_requirements="pip setuptools tox"
+
+if [ "$TRAVIS_OS_NAME" == "osx" ]; then
+    if [[ ${TOXENV} == *"py27"* ]]; then
+        # install pip on the system python
+        curl -O https://bootstrap.pypa.io/get-pip.py
+        python get-pip.py --user
+        python -m pip install --user virtualenv
+        python -m virtualenv .venv/
+    elif [[ ${TOXENV} == *"py3"* ]]; then
+        # install current python3 with homebrew
+        # NOTE: the formula is now named just "python"
+        brew install python
+        command -v python3
+        python3 --version
+        python3 -m pip install virtualenv
+        python3 -m virtualenv .venv/
+    else
+        echo "unsupported $TOXENV: "${TOXENV}
+        exit 1
+    fi
+    source .venv/bin/activate
+fi
+
+python -m pip install $ci_requirements
diff --git a/.travis/run.sh b/.travis/run.sh
new file mode 100755
index 0000000..ffb0ef7
--- /dev/null
+++ b/.travis/run.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+set -e
+set -x
+
+if [ "$TRAVIS_OS_NAME" == "osx" ]; then
+    source .venv/bin/activate
+fi
+
+tox
+
+# re-run all the XML-related tests, this time without lxml but using the
+# built-in ElementTree library.
+if [ -z "$TOXENV" ]; then
+    TOXENV="py-nolxml"
+else
+    # strip additional tox envs after the comma, add -nolxml factor
+    TOXENV="${TOXENV%,*}-nolxml"
+fi
+tox -e $TOXENV -- Tests/ufoLib Tests/misc/etree_test.py Tests/misc/plistlib_test.py
diff --git a/Android.bp b/Android.bp
deleted file mode 100644
index 0dc5289..0000000
--- a/Android.bp
+++ /dev/null
@@ -1,58 +0,0 @@
-//
-// Copyright (C) 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS.  PLEASE
-//     CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE
-//     DEPENDING ON IT IN YOUR PROJECT. ***
-package {
-    default_applicable_licenses: ["external_fonttools_license"],
-}
-
-// Added automatically by a large-scale-change that took the approach of
-// 'apply every license found to every target'. While this makes sure we respect
-// every license restriction, it may not be entirely correct.
-//
-// e.g. GPL in an MIT project might only apply to the contrib/ directory.
-//
-// Please consider splitting the single license below into multiple licenses,
-// taking care not to lose any license_kind information, and overriding the
-// default license using the 'licenses: [...]' property on targets as needed.
-//
-// For unused files, consider creating a 'fileGroup' with "//visibility:private"
-// to attach the license to, and including a comment whether the files may be
-// used in the current project.
-//
-// large-scale-change included anything that looked like it might be a license
-// text as a license_text. e.g. LICENSE, NOTICE, COPYING etc.
-//
-// Please consider removing redundant or irrelevant files from 'license_text:'.
-// See: http://go/android-license-faq
-license {
-    name: "external_fonttools_license",
-    visibility: [":__subpackages__"],
-    license_kinds: [
-        "SPDX-license-identifier-Apache-2.0",
-        "SPDX-license-identifier-BSD",
-        "SPDX-license-identifier-MIT",
-        "SPDX-license-identifier-OFL", // by exception only
-        "SPDX-license-identifier-Unicode-DFS",
-        "legacy_unencumbered",
-    ],
-    license_text: [
-        "LICENSE",
-        "LICENSE.external",
-        "NOTICE",
-    ],
-}
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
deleted file mode 100644
index 30f4976..0000000
--- a/CODE_OF_CONDUCT.md
+++ /dev/null
@@ -1,76 +0,0 @@
-# Contributor Covenant Code of Conduct
-
-## Our Pledge
-
-In the interest of fostering an open and welcoming environment, we as
-contributors and maintainers pledge to making participation in our project and
-our community a harassment-free experience for everyone, regardless of age, body
-size, disability, ethnicity, sex characteristics, gender identity and expression,
-level of experience, education, socio-economic status, nationality, personal
-appearance, race, religion, or sexual identity and orientation.
-
-## Our Standards
-
-Examples of behavior that contributes to creating a positive environment
-include:
-
-* Using welcoming and inclusive language
-* Being respectful of differing viewpoints and experiences
-* Gracefully accepting constructive criticism
-* Focusing on what is best for the community
-* Showing empathy towards other community members
-
-Examples of unacceptable behavior by participants include:
-
-* The use of sexualized language or imagery and unwelcome sexual attention or
- advances
-* Trolling, insulting/derogatory comments, and personal or political attacks
-* Public or private harassment
-* Publishing others' private information, such as a physical or electronic
- address, without explicit permission
-* Other conduct which could reasonably be considered inappropriate in a
- professional setting
-
-## Our Responsibilities
-
-Project maintainers are responsible for clarifying the standards of acceptable
-behavior and are expected to take appropriate and fair corrective action in
-response to any instances of unacceptable behavior.
-
-Project maintainers have the right and responsibility to remove, edit, or
-reject comments, commits, code, wiki edits, issues, and other contributions
-that are not aligned to this Code of Conduct, or to ban temporarily or
-permanently any contributor for other behaviors that they deem inappropriate,
-threatening, offensive, or harmful.
-
-## Scope
-
-This Code of Conduct applies both within project spaces and in public spaces
-when an individual is representing the project or its community. Examples of
-representing a project or community include using an official project e-mail
-address, posting via an official social media account, or acting as an appointed
-representative at an online or offline event. Representation of a project may be
-further defined and clarified by project maintainers.
-
-## Enforcement
-
-Instances of abusive, harassing, or otherwise unacceptable behavior may be
-reported by contacting the project team at <cosimo@anthrotype.com>. All
-complaints will be reviewed and investigated and will result in a response that
-is deemed necessary and appropriate to the circumstances. The project team is
-obligated to maintain confidentiality with regard to the reporter of an incident.
-Further details of specific enforcement policies may be posted separately.
-
-Project maintainers who do not follow or enforce the Code of Conduct in good
-faith may face temporary or permanent repercussions as determined by other
-members of the project's leadership.
-
-## Attribution
-
-This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
-available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
-
-[homepage]: https://www.contributor-covenant.org
-
-For answers to common questions about this code of conduct, see
-https://www.contributor-covenant.org/faq
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
deleted file mode 100644
index ea116c4..0000000
--- a/CONTRIBUTING.md
+++ /dev/null
@@ -1,26 +0,0 @@
-## How to Contribute
-
-FontTools development is on-going in an active community of developers, that includes professional developers employed at major software corporations and at type foundries, as well as hobbyists.
-
-The project is run on Github, in the typical free/libre/open-source software way. 
-If you are unfamiliar with that, check out [opensource.guide](https://opensource.guide) and [producingoss.com](http://producingoss.com).
-
-We use Github's Issue Tracker to report, discuss and track bugs, map out future improvements, set priorities, and self-assign issues.
-If you find a bug, have an idea for a new feature, then please [create a new issue](https://github.com/fonttools/fonttools/issues) and we'll be happy to work with you on it!
-
-If you have a question or want to discuss usage from an end-user perspective, there is a mailing list at [groups.google.com/d/forum/fonttools](https://groups.google.com/d/forum/fonttools) mailing list.
-
-If you would like to speak to someone directly, you can also email the project lead, Behdad Esfahbod, privately at <behdad@behdad.org>
-
-If you make a pull request, you (or the organization that owns your copyrights) should be listed in the [README](https://github.com/fonttools/fonttools#copyrights).
-
-(There is also a development [groups.google.com/d/forum/fonttools-dev](https://groups.google.com/d/forum/fonttools-dev) mailing list for Continuous Integration notifications.)
-
-## Code reviews
-
-All submissions, including submissions by project members, go through a review process using GitHub Pull Requests.
-Consult [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more information on making Pull Requests.
-
-## Code of Conduct
-
-This project has a [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
diff --git a/Doc/README.md b/Doc/README.md
deleted file mode 100644
index 26641b7..0000000
--- a/Doc/README.md
+++ /dev/null
@@ -1,121 +0,0 @@
-# fontTools Documentation
-
-The fontTools project documentation updates continuously on Read the Docs as the project source changes.  
-
-The documentation is hosted at https://fonttools.readthedocs.io/.
-
-## Contents
-
-- [How to Build Local Documentation](#how-to-build-local-documentation)
-- [Contributing to the fontTools Documentation](#contributing-to-the-documentation)
-- [Documentation License](#documentation-license)
-
-## How to Build Local Documentation
-
-### Install Dependencies
-
-You must have a Python 3 interpreter and the `pip` Python package manager installed on your system to build the fontTools documentation.
-
-Pull the fontTools project source files, create a Python virtual environment, and then install fontTools and the documentation build dependencies by executing the following commands in the root of the fontTools source repository:
-
-```
-$ pip install -e . [all]
-$ pip install -r Doc/docs-requirements.txt
-```
-
-### Build Documentation
-
-**With `make`**: execute the following command in the root of the repository:
-
-```
-$ make docs
-```
-
-**Without `make`**: execute the following command in the **`Doc` directory**:
-
-```
-$ sphinx-build -b html source build
-```
-
-Open the `Doc/build/html/index.html` file in your browser to view the documentation home page.
-
-## Contributing to the Documentation
-
-We highly encourage contributions!  Please follow the instructions below to improve the documentation.
-
-### Python Docstring Style
-
-We recommend the use of Python docstrings that follow [the Google Style Guide](https://github.com/google/styleguide/blob/gh-pages/pyguide.md#381-docstrings).  Our documentation build approach parses appropriately formatted docstrings into formatted documentation files.
-
-#### Function Documentation Example
-
-```python
-def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):
-    """Fetches rows from a Bigtable.
-
-    Retrieves rows pertaining to the given keys from the Table instance
-    represented by big_table.  Silly things may happen if
-    other_silly_variable is not None.
-
-    Args:
-        big_table: An open Bigtable Table instance.
-        keys: A sequence of strings representing the key of each table row
-            to fetch.
-        other_silly_variable: Another optional variable, that has a much
-            longer name than the other args, and which does nothing.
-
-    Returns:
-        A dict mapping keys to the corresponding table row data
-        fetched. Each row is represented as a tuple of strings. For
-        example:
-
-        {'Serak': ('Rigel VII', 'Preparer'),
-         'Zim': ('Irk', 'Invader'),
-         'Lrrr': ('Omicron Persei 8', 'Emperor')}
-
-        If a key from the keys argument is missing from the dictionary,
-        then that row was not found in the table.
-
-    Raises:
-        IOError: An error occurred accessing the bigtable.Table object.
-    """
-```
-*Source: [Google Style Guide](https://github.com/google/styleguide/blob/gh-pages/pyguide.md) (CC BY-SA 3.0)*
-
-#### Class Documentation Example
-
-```python
-class SampleClass(object):
-    """Summary of class here.
-
-    Longer class information....
-    Longer class information....
-
-    Attributes:
-        likes_spam: A boolean indicating if we like SPAM or not.
-        eggs: An integer count of the eggs we have laid.
-    """
-
-    def __init__(self, likes_spam=False):
-        """Inits SampleClass with blah."""
-        self.likes_spam = likes_spam
-        self.eggs = 0
-
-    def public_method(self):
-        """Performs operation blah."""
-```
-*Source: [Google Style Guide](https://github.com/google/styleguide/blob/gh-pages/pyguide.md) (CC BY-SA 3.0)*
-
-### Build Local Documentation and Review Your Changes
-
-Build a local set of HTML documentation files with the instructions above and review your changes.
-
-### Submit a Pull Request
-
-Submit a Github pull request with your proposed improvements to the documentation.  
-
-Thanks for your contribution!
-
-## Documentation License
-
-The fontTools documentation is released under a [CC BY-SA 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/).
diff --git a/Doc/docs-requirements.txt b/Doc/docs-requirements.txt
deleted file mode 100644
index c62c8d1..0000000
--- a/Doc/docs-requirements.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-sphinx==3.3.1
-sphinx_rtd_theme==0.5.0
-reportlab==3.5.55
diff --git a/Doc/source/afmLib.rst b/Doc/source/afmLib.rst
index ab9f356..f56d3c1 100644
--- a/Doc/source/afmLib.rst
+++ b/Doc/source/afmLib.rst
@@ -1,8 +1,7 @@
-###########################################
-afmLib: Read/write Adobe Font Metrics files
-###########################################
+######
+afmLib
+######
 
 .. automodule:: fontTools.afmLib
-
-.. autoclass:: fontTools.afmLib.AFM
    :members:
+   :undoc-members:
diff --git a/Doc/source/agl.rst b/Doc/source/agl.rst
index 6e89857..0ecf14d 100644
--- a/Doc/source/agl.rst
+++ b/Doc/source/agl.rst
@@ -1,6 +1,7 @@
-######################################
-agl: Interface to the Adobe Glyph List
-######################################
+###
+agl
+###
 
 .. automodule:: fontTools.agl
-   :members: toUnicode, UV2AGL, AGL2UV
+   :members:
+   :undoc-members:
diff --git a/Doc/source/assets/img/favicon.ico b/Doc/source/assets/img/favicon.ico
deleted file mode 100755
index f55a275..0000000
--- a/Doc/source/assets/img/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/Doc/source/cffLib.rst b/Doc/source/cffLib.rst
new file mode 100644
index 0000000..364824f
--- /dev/null
+++ b/Doc/source/cffLib.rst
@@ -0,0 +1,7 @@
+######
+cffLib
+######
+
+.. automodule:: fontTools.cffLib
+   :members:
+   :undoc-members:
diff --git a/Doc/source/cffLib/index.rst b/Doc/source/cffLib/index.rst
deleted file mode 100644
index 281a0b1..0000000
--- a/Doc/source/cffLib/index.rst
+++ /dev/null
@@ -1,53 +0,0 @@
-##################################
-cffLib: read/write Adobe CFF fonts
-##################################
-
-.. automodule:: fontTools.cffLib
-
-This package also contains two modules for manipulating CFF format glyphs:
-
-.. toctree::
-   :maxdepth: 1
-
-   specializer
-   width
-
-.. autoclass:: fontTools.cffLib.CFFFontSet
-   :inherited-members:
-   :members:
-
-.. autoclass:: fontTools.cffLib.TopDict
-   :members:
-
-.. autoclass:: fontTools.cffLib.CharStrings
-   :members:
-
-.. autoclass:: fontTools.cffLib.Index
-   :members:
-
-.. autoclass:: fontTools.cffLib.GlobalSubrsIndex
-   :members:
-
-.. autoclass:: fontTools.cffLib.TopDictIndex
-   :members:
-
-.. autoclass:: fontTools.cffLib.CFFWriter
-   :members:
-
-.. autoclass:: fontTools.cffLib.IndexCompiler
-   :members:
-
-.. autoclass:: fontTools.cffLib.TopDictIndexCompiler
-   :members:
-
-.. autoclass:: fontTools.cffLib.FDArrayIndexCompiler
-   :members:
-
-.. autoclass:: fontTools.cffLib.GlobalSubrsCompiler
-   :members:
-
-.. autoclass:: fontTools.cffLib.SubrsCompiler
-   :members:
-
-.. autoclass:: fontTools.cffLib.CharStringsCompiler
-   :members:
diff --git a/Doc/source/cffLib/specializer.rst b/Doc/source/cffLib/specializer.rst
deleted file mode 100644
index 016a896..0000000
--- a/Doc/source/cffLib/specializer.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-##############################################################
-specializer: T2CharString operator specializer and generalizer
-##############################################################
-
-.. automodule:: fontTools.cffLib.specializer
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/cffLib/width.rst b/Doc/source/cffLib/width.rst
deleted file mode 100644
index 68944da..0000000
--- a/Doc/source/cffLib/width.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-#########################################
-width: T2CharString glyph width optimizer
-#########################################
-
-.. automodule:: fontTools.cffLib.width
-   :members: optimizeWidths, optimizeWidthsBruteforce
diff --git a/Doc/source/colorLib/index.rst b/Doc/source/colorLib/index.rst
deleted file mode 100644
index d4eb9f8..0000000
--- a/Doc/source/colorLib/index.rst
+++ /dev/null
@@ -1,11 +0,0 @@
-#####################################################
-colorLib.builder: Build COLR/CPAL tables from scratch
-#####################################################
-
-.. automodule:: fontTools.colorLib.builder
-   :members: buildCPAL, buildCOLR, populateCOLRv0
-
-.. autoclass:: fontTools.colorLib.builder.ColorPaletteType
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/conf.py b/Doc/source/conf.py
index 82a5d57..a3b2be2 100644
--- a/Doc/source/conf.py
+++ b/Doc/source/conf.py
@@ -25,43 +25,40 @@
 
 # If your documentation needs a minimal Sphinx version, state it here.
 #
-needs_sphinx = "1.3"
+needs_sphinx = '1.3'
 
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
-extensions = ["sphinx.ext.autodoc", "sphinx.ext.viewcode", "sphinx.ext.napoleon", "sphinx.ext.coverage"]
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
 
-autodoc_mock_imports = ["gtk"]
+autodoc_mock_imports = ['gtk']
 
 # Add any paths that contain templates here, relative to this directory.
-templates_path = ["_templates"]
+templates_path = ['_templates']
 
 # The suffix(es) of source filenames.
 # You can specify multiple suffix as a list of string:
 #
 # source_suffix = ['.rst', '.md']
-source_suffix = ".rst"
+source_suffix = '.rst'
 
 # The master toctree document.
-master_doc = "index"
+master_doc = 'index'
 
 # General information about the project.
-project = u"fontTools"
-copyright = u"2020, Just van Rossum, Behdad Esfahbod, and the fontTools Authors. CC BY-SA 4.0"
-author = u"Just van Rossum, Behdad Esfahbod, and the fontTools Authors"
-
-# HTML page title
-html_title = "fontTools Documentation"
+project = u'fontTools'
+copyright = u'2017, Just van Rossum, Behdad Esfahbod et al.'
+author = u'Just van Rossum, Behdad Esfahbod et al.'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
 # built documents.
 #
 # The short X.Y version.
-version = u"4.0"
+version = u'3.10'
 # The full version, including alpha/beta/rc tags.
-release = u"4.0"
+release = u'3.10'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
@@ -76,11 +73,10 @@
 exclude_patterns = []
 
 # The name of the Pygments (syntax highlighting) style to use.
-# pygments_style = "sphinx" (the default sphinx docs style on RTD)
-pygments_style = "default"
+pygments_style = 'sphinx'
 
 # If true, `todo` and `todoList` produce output, else they produce nothing.
-todo_include_todos = True
+todo_include_todos = False
 
 
 # -- Options for HTML output ----------------------------------------------
@@ -88,29 +84,24 @@
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
 #
-html_theme = "sphinx_rtd_theme"
+html_theme = 'classic'
 
 # Theme options are theme-specific and customize the look and feel of a theme
 # further.  For a list of options available for each theme, see the
 # documentation.
 #
-html_theme_options = {"display_version": False}
+# html_theme_options = {}
 
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ["_static"]
-
-html_favicon = "assets/img/favicon.ico"
-
-# display the Sphinx attribution in the footer
-html_show_sphinx = False
+html_static_path = ['_static']
 
 
 # -- Options for HTMLHelp output ------------------------------------------
 
 # Output file base name for HTML help builder.
-htmlhelp_basename = "fontToolsDoc"
+htmlhelp_basename = 'fontToolsDoc'
 
 
 # -- Options for LaTeX output ---------------------------------------------
@@ -119,12 +110,15 @@
     # The paper size ('letterpaper' or 'a4paper').
     #
     # 'papersize': 'letterpaper',
+
     # The font size ('10pt', '11pt' or '12pt').
     #
     # 'pointsize': '10pt',
+
     # Additional stuff for the LaTeX preamble.
     #
     # 'preamble': '',
+
     # Latex figure (float) alignment
     #
     # 'figure_align': 'htbp',
@@ -134,13 +128,8 @@
 # (source start file, target name, title,
 #  author, documentclass [howto, manual, or own class]).
 latex_documents = [
-    (
-        master_doc,
-        "fontTools.tex",
-        u"fontTools Documentation",
-        u"Just van Rossum, Behdad Esfahbod et al.",
-        "manual",
-    )
+    (master_doc, 'fontTools.tex', u'fontTools Documentation',
+     u'Just van Rossum, Behdad Esfahbod et al.', 'manual'),
 ]
 
 
@@ -148,7 +137,10 @@
 
 # One entry per manual page. List of tuples
 # (source start file, name, description, authors, manual section).
-man_pages = [(master_doc, "fonttools", u"fontTools Documentation", [author], 1)]
+man_pages = [
+    (master_doc, 'fonttools', u'fontTools Documentation',
+     [author], 1)
+]
 
 
 # -- Options for Texinfo output -------------------------------------------
@@ -157,13 +149,8 @@
 # (source start file, target name, title, author,
 #  dir menu entry, description, category)
 texinfo_documents = [
-    (
-        master_doc,
-        "fontTools",
-        u"fontTools Documentation",
-        author,
-        "fontTools",
-        "A library for manipulating fonts, written in Python.",
-        "Typography",
-    )
+    (master_doc, 'fontTools', u'fontTools Documentation',
+     author, 'fontTools', 'A library for manipulating fonts, written in Python.',
+     'Typography'),
 ]
+
diff --git a/Doc/source/cu2qu/index.rst b/Doc/source/cu2qu/index.rst
deleted file mode 100644
index 41730e5..0000000
--- a/Doc/source/cu2qu/index.rst
+++ /dev/null
@@ -1,38 +0,0 @@
-##########################################
-cu2qu: Cubic to quadratic curve conversion
-##########################################
-
-Routines for converting cubic curves to quadratic splines, suitable for use
-in OpenType to TrueType outline conversion.
-
-Conversion is carried out to a degree of tolerance provided by the user. While
-it is relatively easy to find the best *single* quadratic curve to represent a
-given cubic (see for example `this method from CAGD <https://www.sirver.net/blog/2011/08/23/degree-reduction-of-bezier-curves/>`_),
-the best-fit method may not be sufficiently accurate for type design.
-
-Instead, this method chops the cubic curve into multiple segments before
-converting each cubic segment to a quadratic, in order to ensure that the
-resulting spline fits within the given tolerance.
-
-The basic curve conversion routines are implemented in the
-:mod:`fontTools.cu2qu.cu2qu` module; the :mod:`fontTools.cu2qu.ufo` module
-applies these routines to all of the curves in a UFO file or files; while the
-:mod:`fontTools.cu2qu.cli` module implements the ``fonttools cu2qu`` command
-for converting a UFO format font with cubic curves into one with quadratic
-curves.
-
-fontTools.cu2qu.cu2qu
----------------------
-
-.. automodule:: fontTools.cu2qu.cu2qu
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-fontTools.cu2qu.ufo
--------------------
-
-.. automodule:: fontTools.cu2qu.ufo
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/designspaceLib/index.rst b/Doc/source/designspaceLib/index.rst
index 2c33df7..2fb4e52 100644
--- a/Doc/source/designspaceLib/index.rst
+++ b/Doc/source/designspaceLib/index.rst
@@ -13,6 +13,5 @@
    scripting
 
 .. automodule:: fontTools.designspaceLib
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/designspaceLib/readme.rst b/Doc/source/designspaceLib/readme.rst
index c5757a6..2594084 100644
--- a/Doc/source/designspaceLib/readme.rst
+++ b/Doc/source/designspaceLib/readme.rst
@@ -2,22 +2,23 @@
 DesignSpaceDocument Specification
 #################################
 
-An object to read, write and edit interpolation systems for typefaces. Define sources, axes, rules and instances.
+An object to read, write and edit interpolation systems for typefaces.
 
--  `The Python API of the objects <#python-api>`_
--  `The document XML structure <#document-xml-structure>`_
+-  the format was originally written for MutatorMath.
+-  the format is now also used in fontTools.varlib.
+-  Define sources, axes and instances.
+-  Not all values might be required by all applications.
 
+A couple of differences between things that use designspaces:
 
-**********
-Python API
-**********
-
-
-
-.. _designspacedocument-object:
-
-DesignSpaceDocument object
-==========================
+-  Varlib does not support anisotropic interpolations.
+-  MutatorMath and Superpolator will extrapolate over the boundaries of
+   the axes. Varlib can not (at the moment).
+-  Varlib requires much less data to define an instance than
+   MutatorMath.
+-  The goals of Varlib and MutatorMath are different, so not all
+   attributes are always needed.
+-  Need to expand the description of FDK use of designspace files.
 
 The DesignSpaceDocument object can read and write ``.designspace`` data.
 It imports the axes, sources and instances to very basic **descriptor**
@@ -27,75 +28,87 @@
 in different contexts.
 
 The **DesignSpaceDocument** object can be subclassed to work with
-different objects, as long as they have the same attributes. Reader and
-Writer objects can be subclassed as well.
-
-**Note:** Python attribute names are usually camelCased, the
-corresponding `XML <#document-xml-structure>`_ attributes are usually
-all lowercase.
-
-.. example-1:
+different objects, as long as they have the same attributes.
 
 .. code:: python
 
-    from fontTools.designspaceLib import DesignSpaceDocument
+    from designSpaceDocument import DesignSpaceDocument
     doc = DesignSpaceDocument()
     doc.read("some/path/to/my.designspace")
     doc.axes
     doc.sources
     doc.instances
 
-Attributes
-----------
+**********
+Validation
+**********
 
--  ``axes``: list of axisDescriptors
--  ``sources``: list of sourceDescriptors
--  ``instances``: list of instanceDescriptors
--  ``rules``: list if ruleDescriptors
--  ``readerClass``: class of the reader object
--  ``writerClass``: class of the writer object
--  ``lib``: dict for user defined, custom data that needs to be stored
-   in the designspace. Use reverse-DNS notation to identify your own data.
-   Respect the data stored by others.
--  ``rulesProcessingLast``: This flag indicates whether the substitution rules should be applied before or after other glyph substitution features. False: before, True: after.
+Some validation is done when reading.
 
-Methods
--------
+Axes
+====
 
--  ``read(path)``: read a designspace file from ``path``
--  ``write(path)``: write this designspace to ``path``
--  ``addSource(aSourceDescriptor)``: add this sourceDescriptor to 
-   ``doc.sources``.
--  ``addInstance(anInstanceDescriptor)``: add this instanceDescriptor
-   to ``doc.instances``.
--  ``addAxis(anAxisDescriptor)``: add this instanceDescriptor to ``doc.axes``.
--  ``newDefaultLocation()``: returns a dict with the default location
-   in designspace coordinates.
--  ``updateFilenameFromPath(masters=True, instances=True, force=False)``:
-   set a descriptor filename attr from the path and this document.
--  ``newAxisDescriptor()``: return a new axisDescriptor object.
--  ``newSourceDescriptor()``: return a new sourceDescriptor object.
--  ``newInstanceDescriptor()``: return a new instanceDescriptor object.
--  ``getAxisOrder()``: return a list of axisnames
--  ``findDefault()``: return the sourceDescriptor that is on the default
-   location. Returns None if there isn't one.
--  ``normalizeLocation(aLocation)``: return a dict with normalized axis values.
--  ``normalize()``: normalize the geometry of this designspace: scale all the
-   locations of all masters and instances to the ``-1 - 0 - 1`` value.
--  ``loadSourceFonts()``: Ensure SourceDescriptor.font attributes are loaded,
-   and return list of fonts.
--  ``tostring(encoding=None)``: Returns the designspace as a string. Default 
-   encoding `utf-8`.
+-  If the ``axes`` element is available in the document then all
+   locations will check their dimensions against the defined axes. If a
+   location uses an axis that is not defined it will be ignored.
+-  If there are no ``axes`` in the document, locations will accept all
+   axis names, so that we can..
+-  Use ``doc.checkAxes()`` to reconstruct axes definitions based on the
+   ``source.location`` values. If you save the document the axes will be
+   there.
 
-Class Methods
--------------
-- ``fromfile(path)``
-- ``fromstring(string)``
+Default font
+============
 
+-  The source with the ``copyInfo`` flag indicates this is the default
+   font.
+-  In mutatorMath the default font is selected automatically. A warning
+   is printed if the mutatorMath default selection differs from the one
+   set by ``copyInfo``. But the ``copyInfo`` source will be used.
+-  If no source has a ``copyInfo`` flag, mutatorMath will be used to
+   select one. This source gets its ``copyInfo`` flag set. If you save
+   the document this flag will be set.
+-  Use ``doc.checkDefault()`` to set the default font.
 
+************
+Localisation
+************
 
+Some of the descriptors support localised names. The names are stored in
+dictionaries using the language code as key. That means that there are
+now two places to store names: the old attribute and the new localised
+dictionary, ``obj.stylename`` and ``obj.localisedStyleName['en']``.
 
+*****
+Rules
+*****
 
+Rules describe designspace areas in which one glyph should be replaced by another.
+A rule has a name and a number of conditionsets. The rule also contains a list of
+glyphname pairs: the glyphs that need to be substituted. For a rule to be triggered
+**only one** of the conditionsets needs to be true, ``OR``. Within a conditionset 
+**all** conditions need to be true, ``AND``.
+
+The ``sub`` element contains a pair of glyphnames. The ``name`` attribute is the glyph that should be visible when the rule evaluates to **False**. The ``with`` attribute is the glyph that should be visible when the rule evaluates to **True**.
+
+UFO instances
+=============
+
+-  When making instances as UFOs however, we need to swap the glyphs so
+   that the original shape is still available. For instance, if a rule
+   swaps ``a`` for ``a.alt``, but a glyph that references ``a`` in a
+   component would then show the new ``a.alt``.
+-  But that can lead to unexpected results. So, if there are no rules
+   for ``adieresis`` (assuming it references ``a``) then that glyph
+   **should not change appearance**. That means that when the rule swaps
+   ``a`` and ``a.alt`` it also swaps all components that reference these
+   glyphs so they keep their appearance.
+-  The swap function also needs to take care of swapping the names in
+   kerning data.
+
+**********
+Python API
+**********
 
 SourceDescriptor object
 =======================
@@ -125,7 +138,8 @@
 -  ``copyLib``: bool. Indicates if the contents of the font.lib need to
    be copied to the instances. MutatorMath.
 -  ``copyInfo`` bool. Indicates if the non-interpolating font.info needs
-   to be copied to the instances. MutatorMath
+   to be copied to the instances. Also indicates this source is expected
+   to be the default font. MutatorMath + Varlib
 -  ``copyGroups`` bool. Indicates if the groups need to be copied to the
    instances. MutatorMath.
 -  ``copyFeatures`` bool. Indicates if the feature text needs to be
@@ -168,7 +182,6 @@
 
 .. attributes-1:
 
-
 Attributes
 ----------
 
@@ -271,9 +284,10 @@
 -  ``default``: number. The default value for this axis, i.e. when a new
    location is created, this is the value this axis will get in user
    space. MutatorMath + Varlib.
--  ``map``: list of input / output values that can describe a warp
-   of user space to design space coordinates. If no map values are present, it is assumed user space is the same as design space, as
-   in [(minimum, minimum), (maximum, maximum)]. Varlib.
+-  ``map``: list of input / output values that can describe a warp of user space
+   to design space coordinates. If no map values are present, it is assumed user
+   space is the same as design space, as in [(minimum, minimum), (maximum, maximum)].
+   Varlib.
 
 .. code:: python
 
@@ -297,27 +311,15 @@
 -  Each condition is a dict with ``name``, ``minimum`` and ``maximum`` keys.
 -  ``subs``: list of substitutions
 -  Each substitution is stored as tuples of glyphnames, e.g. ("a", "a.alt").
--  Note: By default, rules are applied first, before other text shaping/OpenType layout, as they are part of the `Required Variation Alternates OpenType feature <https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#-tag-rvrn>`_. See `5.0 rules element`_ § Attributes.
-
-Evaluating rules
-----------------
-    
--  ``evaluateRule(rule, location)``: Return True if any of the rule's conditionsets 
-   matches the given location.
--  ``evaluateConditions(conditions, location)``: Return True if all the conditions
-   matches the given location. 
--  ``processRules(rules, location, glyphNames)``: Apply all the rules to the list
-   of glyphNames. Return a new list of glyphNames with substitutions applied.
 
 .. code:: python
 
     r1 = RuleDescriptor()
     r1.name = "unique.rule.name"
-    r1.conditionSets.append([dict(name="weight", minimum=-10, maximum=10), dict(...)])
-    r1.conditionSets.append([dict(...), dict(...)])
+    r1.conditionsSets.append([dict(name="weight", minimum=-10, maximum=10), dict(...)])
+    r1.conditionsSets.append([dict(...), dict(...)])
     r1.subs.append(("a", "a.alt"))
 
-
 .. _subclassing-descriptors:
 
 Subclassing descriptors
@@ -398,9 +400,9 @@
    location elements.
 -  ``tag``: required, string, 4 letters. Some axis tags are registered
    in the OpenType Specification.
--  ``minimum``: required, number. The minimum value for this axis, in user space coordinates.
--  ``maximum``: required, number. The maximum value for this axis, in user space coordinates.
--  ``default``: required, number. The default value for this axis, in user space coordinates.
+-  ``minimum``: required, number. The minimum value for this axis.
+-  ``maximum``: required, number. The maximum value for this axis.
+-  ``default``: required, number. The default value for this axis.
 -  ``hidden``: optional, 0 or 1. Records whether this axis needs to be
    hidden in interfaces.
 
@@ -431,7 +433,7 @@
 
 -  The natural language name of this axis.
 
-.. example-2:
+.. example-1:
 
 Example
 -------
@@ -446,12 +448,12 @@
 1.2 map element
 ===============
 
--  Defines a single node in a series of input value (user space coordinate)
-   to output value (designspace coordinate) pairs.
+-  Defines a single node in a series of input value / output value
+   pairs.
 -  Together these values transform the designspace.
 -  Child of ``axis`` element.
 
-.. example-3:
+.. example-2:
 
 Example
 -------
@@ -505,7 +507,7 @@
 -  ``yvalue``: optional, number. Separate value for anisotropic
    interpolations.
 
-.. example-4:
+.. example-3:
 
 Example
 -------
@@ -522,9 +524,8 @@
 3. source element
 =================
 
--  Defines a single font or layer that contributes to the designspace.
+-  Defines a single font that contributes to the designspace.
 -  Child element of ``sources``
--  Location in designspace coordinates.
 
 .. attributes-5:
 
@@ -583,7 +584,9 @@
 -  Child element of ``source``
 -  Defines if the instances can inherit the non-interpolating font info
    from this source.
--  MutatorMath
+-  MutatorMath + Varlib
+-  NOTE: **This presence of this element indicates this source is to be
+   the default font.**
 
 .. 33-features-element:
 
@@ -635,7 +638,7 @@
    include the kerning of this source in the calculation.
 -  MutatorMath only
 
-.. example-5:
+.. example-4:
 
 Example
 -------
@@ -666,7 +669,6 @@
 -  MutatorMath uses the ``glyphs`` element to describe how certain
    glyphs need different masters, mainly to describe the effects of
    conditional rules in Superpolator.
--  Location in designspace coordinates.
 
 .. attributes-8:
 
@@ -772,7 +774,7 @@
 -  stylemapstylename
 -  stylemapfamilyname
 
-.. example-6:
+.. example-5:
 
 Example
 -------
@@ -796,7 +798,7 @@
 -  ``source``: the identifier name of the source this master glyph needs
    to be loaded from
 
-.. example-7:
+.. example-6:
 
 Example
 -------
@@ -844,21 +846,6 @@
 -  Container for ``rule`` elements
 -  The rules are evaluated in this order.
 
-Rules describe designspace areas in which one glyph should be replaced by another.
-A rule has a name and a number of conditionsets. The rule also contains a list of
-glyphname pairs: the glyphs that need to be substituted. For a rule to be triggered
-**only one** of the conditionsets needs to be true, ``OR``. Within a conditionset 
-**all** conditions need to be true, ``AND``.
-
-.. attributes-11:
-
-Attributes
-----------
-
--  ``processing``: flag, optional. Valid values are [``first``, ``last``]. This flag indicates whether the substitution rules should be applied before or after other glyph substitution features.
--  If no ``processing`` attribute is given, interpret as ``first``, and put the substitution rule in the `rvrn` feature.
--  If ``processing`` is ``last``, put it in `rclt`.
-
 .. 51-rule-element:
 
 5.1 rule element
@@ -866,8 +853,8 @@
 
 -  Defines a named rule.
 -  Each ``rule`` element contains one or more ``conditionset`` elements.
--  **Only one** ``conditionset`` needs to be true to trigger the rule.
--  **All** conditions in a ``conditionset`` must be true to make the ``conditionset`` true.
+-  Only one ``conditionset`` needs to be true to trigger the rule.
+-  All conditions in a ``conditionset`` must be true to make the ``conditionset`` true.
 -  For backwards compatibility a ``rule`` can contain ``condition`` elements outside of a conditionset. These are then understood to be part of a single, implied, ``conditionset``. Note: these conditions should be written wrapped in a conditionset.
 -  A rule element needs to contain one or more ``sub`` elements in order to be compiled to a variable font.
 -  Rules without sub elements should be ignored when compiling a font.
@@ -894,10 +881,9 @@
 =======================
 
 -  Child element of ``conditionset``
--  Between the ``minimum`` and ``maximum`` this condition is ``True``.
--  ``minimum`` and ``maximum`` are in designspace coordinates.
--  If ``minimum`` is not available, assume it is ``axis.minimum``, mapped to designspace coordinates.
--  If ``maximum`` is not available, assume it is ``axis.maximum``, mapped to designspace coordinates.
+-  Between the ``minimum`` and ``maximum`` this rule is ``True``.
+-  If ``minimum`` is not available, assume it is ``axis.minimum``.
+-  If ``maximum`` is not available, assume it is ``axis.maximum``.
 -  The condition must contain at least a minimum or maximum or both.
 
 .. attributes-12:
@@ -907,8 +893,8 @@
 
 -  ``name``: string, required. Must match one of the defined ``axis``
    name attributes.
--  ``minimum``: number, required*. The low value, in designspace coordinates.
--  ``maximum``: number, required*. The high value, in designspace coordinates.
+-  ``minimum``: number, required*. The low value.
+-  ``maximum``: number, required*. The high value.
 
 .. 513-sub-element:
 
@@ -917,9 +903,6 @@
 
 -  Child element of ``rule``.
 -  Defines which glyph to replace when the rule evaluates to **True**.
--  The ``sub`` element contains a pair of glyphnames. The ``name`` attribute is the glyph that should be visible when the rule evaluates to **False**. The ``with`` attribute is the glyph that should be visible when the rule evaluates to **True**.
-
-Axis values in Conditions are in designspace coordinates.
 
 .. attributes-13:
 
@@ -931,7 +914,7 @@
 -  ``with``: string, required. The name of the glyph it is replaced
    with.
 
-.. example-8:
+.. example-7:
 
 Example
 -------
@@ -941,7 +924,7 @@
 
 .. code:: xml
 
-    <rules processing="last">
+    <rules>
         <rule name="named.rule.1">
             <condition minimum="250" maximum="750" name="weight" />
             <condition minimum="50" maximum="100" name="width" />
@@ -1076,75 +1059,9 @@
 glyphs should be exported, regardless of what the same lib key in any of the
 UFOs says.
 
-.. 8-implementation-and-differences:
+.. 8-this-document:
 
-
-8 Implementation and differences
-================================
-
-The designspace format has gone through considerable development. 
-
- -  the format was originally written for MutatorMath.
- -  the format is now also used in fontTools.varlib.
- -  not all values are be required by all implementations.
-
-8.1 Varlib vs. MutatorMath
---------------------------
-
-There are some differences between the way MutatorMath and fontTools.varlib handle designspaces.
-
- -  Varlib does not support anisotropic interpolations.
- -  MutatorMath will extrapolate over the boundaries of
-    the axes. Varlib can not (at the moment).
- -  Varlib requires much less data to define an instance than
-    MutatorMath.
- -  The goals of Varlib and MutatorMath are different, so not all
-    attributes are always needed.
-
-8.2 Older versions
-------------------
-
--  In some implementations that preceed Variable Fonts, the `copyInfo`
-   flag in a source indicated the source was to be treated as the default.
-   This is no longer compatible with the assumption that the default font
-   is located on the default value of each axis.
--  Older implementations did not require axis records to be present in
-   the designspace file. The axis extremes for instance were generated 
-   from the locations used in the sources. This is no longer possible.
-
-8.3 Rules and generating static UFO instances
----------------------------------------------
-
-When making instances as UFOs from a designspace with rules, it can
-be useful to evaluate the rules so that the characterset of the ufo 
-reflects, as much as possible, the state of a variable font when seen
-at the same location. This can be done by some swapping and renaming of
-glyphs.
-
-While useful for proofing or development work, it should be noted that
-swapping and renaming leaves the UFOs with glyphnames that are no longer
-descriptive. For instance, after a swap `dollar.bar` could contain a shape
-without a bar. Also, when the swapped glyphs are part of other GSUB variations
-it can become complex very quickly. So proceed with caution.
-
- -  Assuming `rulesProcessingLast = True`:
- -  We need to swap the glyphs so that the original shape is still available. 
-    For instance, if a rule swaps ``a`` for ``a.alt``, a glyph
-    that references ``a`` in a component would then show the new ``a.alt``.
- -  But that can lead to unexpected results, the two glyphs may have different
-    widths or height. So, glyphs that are not specifically referenced in a rule
-    **should not change appearance**. That means that the implementation that swaps
-    ``a`` and ``a.alt`` also swap all components that reference these
-    glyphs in order to preserve their appearance.
- -  The swap function also needs to take care of swapping the names in
-    kerning data and any GPOS code.
-
-
-.. 9-this-document
-
-9 This document
+8 This document
 ===============
 
--  Changes are to be expected.
-
-
+-  The package is rather new and changes are to be expected.
diff --git a/Doc/source/developer.rst b/Doc/source/developer.rst
deleted file mode 100644
index 3e259f0..0000000
--- a/Doc/source/developer.rst
+++ /dev/null
@@ -1,115 +0,0 @@
-.. _developerinfo:
-.. image:: ../../Icons/FontToolsIconGreenCircle.png
-   :width: 200px
-   :height: 200px
-   :alt: Font Tools
-   :align: center
-
-
-fontTools Developer Information
-===============================
-
-If you would like to contribute to the development of fontTools, you can clone the repository from GitHub, install the package in 'editable' mode and modify the source code in place. We recommend creating a virtual environment, using the Python 3 `venv <https://docs.python.org/3/library/venv.html>`_ module::
-
-    # download the source code to 'fonttools' folder
-    git clone https://github.com/fonttools/fonttools.git
-    cd fonttools
-
-    # create new virtual environment called e.g. 'fonttools-venv', or anything you like
-    python -m venv fonttools-venv
-
-    # source the `activate` shell script to enter the environment (Un*x)
-    . fonttools-venv/bin/activate
-
-    # to activate the virtual environment in Windows `cmd.exe`, do
-    fonttools-venv\Scripts\activate.bat
-
-    # install in 'editable' mode
-    pip install -e .
-
-
-.. note::
-
-    To exit a Python virtual environment, enter the command ``deactivate``.
-
-Testing
--------
-
-To run the test suite, you need to install `pytest <http://docs.pytest.org/en/latest/>`__.
-When you run the ``pytest`` command, the tests will run against the
-installed fontTools package, or the first one found in the
-``PYTHONPATH``.
-
-You can also use `tox <https://tox.readthedocs.io/en/latest/>`__ to
-automatically run tests on different Python versions in isolated virtual
-environments::
-
-    pip install tox
-    tox
-
-
-.. note::
-
-    When you run ``tox`` without arguments, the tests are executed for all the environments listed in the ``tox.ini`` ``envlist``. The Python versions that are not available on your system ``PATH`` will be skipped.
-
-You can specify a particular testing environment list via the ``-e`` option, or the ``TOXENV`` environment variable::
-
-    tox -e py36
-    TOXENV="py36-cov,htmlcov" tox
-
-
-Development Community
----------------------
-
-fontTools development is ongoing in an active community of developers that includes professional developers employed at major software corporations and type foundries as well as hobbyists.
-
-Feature requests and bug reports are always welcome at https://github.com/fonttools/fonttools/issues/
-
-The best place for end-user and developer discussion about the fontTools project is the `fontTools gitter channel <https://gitter.im/fonttools-dev/Lobby>`_. There is also a development https://groups.google.com/d/forum/fonttools-dev mailing list for continuous integration notifications.
-
-
-History
--------
-
-The fontTools project was started by Just van Rossum in 1999, and was
-maintained as an open source project at
-http://sourceforge.net/projects/fonttools/. In 2008, Paul Wise (pabs3)
-began helping Just with stability maintenance. In 2013 Behdad Esfahbod
-began a friendly fork, thoroughly reviewing the codebase and making
-changes at https://github.com/behdad/fonttools to add new features and
-support for new font formats.
-
-
-Acknowledgments
----------------
-
-In alphabetical order:
-
-Olivier Berten, Samyak Bhuta, Erik van Blokland, Petr van Blokland,
-Jelle Bosma, Sascha Brawer, Tom Byrer, Frédéric Coiffier, Vincent
-Connare, Dave Crossland, Simon Daniels, Peter Dekkers, Behdad Esfahbod,
-Behnam Esfahbod, Hannes Famira, Sam Fishman, Matt Fontaine, Yannis
-Haralambous, Greg Hitchcock, Jeremie Hornus, Khaled Hosny, John Hudson,
-Denis Moyogo Jacquerye, Jack Jansen, Tom Kacvinsky, Jens Kutilek,
-Antoine Leca, Werner Lemberg, Tal Leming, Peter Lofting, Cosimo Lupo,
-Masaya Nakamura, Dave Opstad, Laurence Penney, Roozbeh Pournader, Garret
-Rieger, Read Roberts, Guido van Rossum, Just van Rossum, Andreas Seidel,
-Georg Seifert, Chris Simpkins, Miguel Sousa, Adam Twardoch, Adrien Tétar, Vitaly Volkov,
-Paul Wise.
-
-License
--------
-
-`MIT license <https://github.com/fonttools/fonttools/blob/master/LICENSE>`_.  See the full text of the license for details.
-
-.. |Travis Build Status| image:: https://travis-ci.org/fonttools/fonttools.svg
-   :target: https://travis-ci.org/fonttools/fonttools
-.. |Appveyor Build status| image:: https://ci.appveyor.com/api/projects/status/0f7fmee9as744sl7/branch/master?svg=true
-   :target: https://ci.appveyor.com/project/fonttools/fonttools/branch/master
-.. |Coverage Status| image:: https://codecov.io/gh/fonttools/fonttools/branch/master/graph/badge.svg
-   :target: https://codecov.io/gh/fonttools/fonttools
-.. |PyPI| image:: https://img.shields.io/pypi/v/fonttools.svg
-   :target: https://pypi.org/project/FontTools
-.. |Gitter Chat| image:: https://badges.gitter.im/fonttools-dev/Lobby.svg
-   :alt: Join the chat at https://gitter.im/fonttools-dev/Lobby
-   :target: https://gitter.im/fonttools-dev/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
diff --git a/Doc/source/encodings.rst b/Doc/source/encodings.rst
new file mode 100644
index 0000000..8bcd38a
--- /dev/null
+++ b/Doc/source/encodings.rst
@@ -0,0 +1,14 @@
+#########
+encodings
+#########
+
+.. automodule:: fontTools.encodings
+   :members:
+   :undoc-members:
+
+codecs
+------
+
+.. automodule:: fontTools.encodings.codecs
+   :members:
+   :undoc-members:
diff --git a/Doc/source/encodings/index.rst b/Doc/source/encodings/index.rst
deleted file mode 100644
index 32d13c7..0000000
--- a/Doc/source/encodings/index.rst
+++ /dev/null
@@ -1,21 +0,0 @@
-##################################################
-encodings: Support for OpenType-specific encodings
-##################################################
-
-fontTools includes support for some character encodings found in legacy Mac
-TrueType fonts. Many of these legacy encodings have found their way into the
-standard Python ``encodings`` library, but others still remain unimplemented.
-Importing ``fontTools.encodings.codecs`` will therefore add string ``encode``
-and ``decode`` support for the following encodings:
-
-* ``x_mac_japanese_ttx``
-* ``x_mac_trad_chinese_ttx``
-* ``x_mac_korean_ttx``
-* ``x_mac_simp_chinese_ttx``
-
-fontTools also includes a package (``fontTools.encodings.MacRoman``) which
-contains a mapping of glyph IDs to glyph names in the MacRoman character set::
-
-		>>> from fontTools.encodings.MacRoman import MacRoman
-		>>> MacRoman[26]
-		'twosuperior'
diff --git a/Doc/source/feaLib.rst b/Doc/source/feaLib.rst
new file mode 100644
index 0000000..ad69217
--- /dev/null
+++ b/Doc/source/feaLib.rst
@@ -0,0 +1,43 @@
+######
+feaLib
+######
+
+.. automodule:: fontTools.feaLib
+   :members:
+   :undoc-members:
+
+ast
+---
+
+.. automodule:: fontTools.feaLib.ast
+   :members:
+   :undoc-members:
+
+builder
+-------
+
+.. automodule:: fontTools.feaLib.builder
+   :members:
+   :undoc-members:
+
+error
+-----
+
+.. automodule:: fontTools.feaLib.parser
+   :members:
+   :undoc-members:
+
+lexer
+-----
+
+.. automodule:: fontTools.feaLib.lexer
+   :members:
+   :undoc-members:
+
+parser
+------
+
+.. automodule:: fontTools.feaLib.parser
+   :members:
+   :undoc-members:
+
diff --git a/Doc/source/feaLib/index.rst b/Doc/source/feaLib/index.rst
deleted file mode 100644
index 61ac31f..0000000
--- a/Doc/source/feaLib/index.rst
+++ /dev/null
@@ -1,40 +0,0 @@
-#########################################
-feaLib: Read/write OpenType feature files
-#########################################
-
-fontTools' ``feaLib`` allows for the creation and parsing of Adobe
-Font Development Kit for OpenType feature (``.fea``) files. The syntax
-of these files is described `here <https://adobe-type-tools.github.io/afdko/OpenTypeFeatureFileSpecification.html>`_.
-
-The :class:`fontTools.feaLib.parser.Parser` class can be used to parse files
-into an abstract syntax tree, and from there the
-:class:`fontTools.feaLib.builder.Builder` class can add features to an existing
-font file. You can inspect the parsed syntax tree, walk the tree and do clever
-things with it, and also generate your own feature files programmatically, by
-using the classes in the :mod:`fontTools.feaLib.ast` module.
-
-Parsing
--------
-
-.. autoclass:: fontTools.feaLib.parser.Parser
-   :members: parse
-   :member-order: bysource
-
-Building
----------
-
-.. automodule:: fontTools.feaLib.builder
-   :members: addOpenTypeFeatures, addOpenTypeFeaturesFromString
-
-Generation/Interrogation
-------------------------
-
-.. _`glyph-containing object`:
-.. _`glyph-containing objects`:
-
-In the below, a **glyph-containing object** is an object of one of the following
-classes: :class:`GlyphName`, :class:`GlyphClass`, :class:`GlyphClassName`.
-
-.. automodule:: fontTools.feaLib.ast
-   :member-order: bysource
-   :members:
diff --git a/Doc/source/index.rst b/Doc/source/index.rst
index 2162cc1..b3d44cf 100644
--- a/Doc/source/index.rst
+++ b/Doc/source/index.rst
@@ -1,152 +1,28 @@
-.. image:: ../../Icons/FontToolsIconGreenCircle.png
-   :width: 200px
-   :height: 200px
-   :alt: Font Tools
-   :align: center
-
-
 fontTools Docs
 ==============
 
-About
------
-
-fontTools is a family of libraries and utilities for manipulating fonts in Python.
-
-The project has an `MIT open-source license <https://github.com/fonttools/fonttools/blob/master/LICENSE>`_. Among other things this means you can use it free of charge.
-
-Installation
-------------
-
-.. note::
-
-    fontTools requires `Python <http://www.python.org/download/>`_ 3.6 or later.
-
-The package is listed in the Python Package Index (PyPI), so you can install it with `pip <https://pip.pypa.io/>`_::
-
-    pip install fonttools
-
-See the Optional Requirements section below for details about module-specific dependencies that must be installed in select cases.
-
-Utilities
----------
-
-fontTools installs four command-line utilities:
-
-- ``pyftmerge``, a tool for merging fonts; see :py:mod:`fontTools.merge`
-- ``pyftsubset``, a tool for subsetting fonts; see :py:mod:`fontTools.subset`
-- ``ttx``, a tool for converting between OpenType binary fonts (OTF) and an XML representation (TTX); see :py:mod:`fontTools.ttx`
-- ``fonttools``, a "meta-tool" for accessing other components of the fontTools family.
-
-This last utility takes a subcommand, which could be one of:
-
-- ``cffLib.width``: Calculate optimum defaultWidthX/nominalWidthX values
-- ``cu2qu``: Convert a UFO font from cubic to quadratic curves
-- ``feaLib``: Add features from a feature file (.fea) into a OTF font
-- ``help``: Show this help
-- ``merge``: Merge multiple fonts into one
-- ``mtiLib``: Convert a FontDame OTL file to TTX XML
-- ``subset``: OpenType font subsetter and optimizer
-- ``ttLib.woff2``: Compress and decompress WOFF2 fonts
-- ``ttx``: Convert OpenType fonts to XML and back
-- ``varLib``: Build a variable font from a designspace file and masters
-- ``varLib.instancer``: Partially instantiate a variable font.
-- ``varLib.interpolatable``: Test for interpolatability issues between fonts
-- ``varLib.interpolate_layout``: Interpolate GDEF/GPOS/GSUB tables for a point on a designspace
-- ``varLib.models``: Normalize locations on a given designspace
-- ``varLib.mutator``: Instantiate a variation font
-- ``varLib.varStore``: Optimize a font's GDEF variation store
-
-Libraries
----------
-
-The main library you will want to access when using fontTools for font
-engineering is likely to be :py:mod:`fontTools.ttLib`, which is the package
-for handling TrueType/OpenType fonts. However, there are many other
-libraries in the fontTools suite:
-
-- :py:mod:`fontTools.afmLib`: Module for reading and writing AFM files
-- :py:mod:`fontTools.agl`: Access to the Adobe Glyph List
-- :py:mod:`fontTools.cffLib`: Read/write tools for Adobe CFF fonts
-- :py:mod:`fontTools.colorLib`: Module for handling colors in CPAL/COLR fonts
-- :py:mod:`fontTools.cu2qu`: Module for cubic to quadratic conversion
-- :py:mod:`fontTools.designspaceLib`: Read and write designspace files
-- :py:mod:`fontTools.encodings`: Support for font-related character encodings
-- :py:mod:`fontTools.feaLib`: Read and read AFDKO feature files
-- :py:mod:`fontTools.fontBuilder`: Construct TTF/OTF fonts from scratch
-- :py:mod:`fontTools.merge`: Tools for merging font files
-- :py:mod:`fontTools.pens`: Various classes for manipulating glyph outlines
-- :py:mod:`fontTools.subset`: OpenType font subsetting and optimization
-- :py:mod:`fontTools.svgLib.path`: Library for drawing SVG paths onto glyphs
-- :py:mod:`fontTools.t1Lib`: Tools for PostScript Type 1 fonts (Python2 only)
-- :py:mod:`fontTools.ttx`: Module for converting between OTF and XML representation
-- :py:mod:`fontTools.ufoLib`: Module for reading and writing UFO files
-- :py:mod:`fontTools.unicodedata`: Convert between Unicode and OpenType script information
-- :py:mod:`fontTools.varLib`: Module for dealing with 'gvar'-style font variations
-- :py:mod:`fontTools.voltLib`: Module for dealing with Visual OpenType Layout Tool (VOLT) files
-
-A selection of sample Python programs using these libaries can be found in the `Snippets directory <https://github.com/fonttools/fonttools/blob/master/Snippets/>`_ of the fontTools repository.
-
-Optional Dependencies
----------------------
-
-The fontTools package currently has no (required) external dependencies
-besides the modules included in the Python Standard Library.
-However, a few extra dependencies are required to unlock optional features
-in some of the library modules. See the :doc:`optional requirements <./optional>`
-page for more information.
-
-Developer information
----------------------
-
-Information for developers can be found :doc:`here <./developer>`.
-
-License
--------
-
-`MIT license <https://github.com/fonttools/fonttools/blob/master/LICENSE>`_.  See the full text of the license for details.
-
-
-Table of Contents
------------------
-
 .. toctree::
-   :maxdepth: 2
-   :caption: Library
+   :maxdepth: 1
 
    afmLib
    agl
-   cffLib/index
-   colorLib/index
-   cu2qu/index
+   cffLib
    designspaceLib/index
-   encodings/index
-   feaLib/index
+   encodings
+   feaLib
    merge
    misc/index
-   mtiLib
-   otlLib/index
    pens/index
-   subset/index
-   svgLib/index
+   subset
    t1Lib
    ttLib/index
    ttx
-   ufoLib/index
-   unicode
-   unicodedata/index
    varLib/index
    voltLib
 
+Indices and tables
+==================
 
-.. |Travis Build Status| image:: https://travis-ci.org/fonttools/fonttools.svg
-   :target: https://travis-ci.org/fonttools/fonttools
-.. |Appveyor Build status| image:: https://ci.appveyor.com/api/projects/status/0f7fmee9as744sl7/branch/master?svg=true
-   :target: https://ci.appveyor.com/project/fonttools/fonttools/branch/master
-.. |Coverage Status| image:: https://codecov.io/gh/fonttools/fonttools/branch/master/graph/badge.svg
-   :target: https://codecov.io/gh/fonttools/fonttools
-.. |PyPI| image:: https://img.shields.io/pypi/v/fonttools.svg
-   :target: https://pypi.org/project/FontTools
-.. |Gitter Chat| image:: https://badges.gitter.im/fonttools-dev/Lobby.svg
-   :alt: Join the chat at https://gitter.im/fonttools-dev/Lobby
-   :target: https://gitter.im/fonttools-dev/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
\ No newline at end of file
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/Doc/source/merge.rst b/Doc/source/merge.rst
index 3114615..74cf9ad 100644
--- a/Doc/source/merge.rst
+++ b/Doc/source/merge.rst
@@ -1,10 +1,7 @@
-####################################
-merge: Merge multiple fonts into one
-####################################
+#####
+merge
+#####
 
-``fontTools.merge`` provides both a library and a command line interface
-(``fonttools merge``) for merging multiple fonts together.
-
-.. autoclass:: fontTools.merge.Merger
-   :inherited-members:
+.. automodule:: fontTools.merge
    :members:
+   :undoc-members:
diff --git a/Doc/source/misc/arrayTools.rst b/Doc/source/misc/arrayTools.rst
index d996cc2..acb2a51 100644
--- a/Doc/source/misc/arrayTools.rst
+++ b/Doc/source/misc/arrayTools.rst
@@ -1,9 +1,7 @@
-#############################################
-arrayTools: Various array and rectangle tools
-#############################################
+##########
+arrayTools
+##########
 
 .. automodule:: fontTools.misc.arrayTools
-   :member-order: bysource
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/misc/bezierTools.rst b/Doc/source/misc/bezierTools.rst
index 10ddc3a..c5b4d2a 100644
--- a/Doc/source/misc/bezierTools.rst
+++ b/Doc/source/misc/bezierTools.rst
@@ -1,8 +1,7 @@
-####################################################
-bezierTools: Routines for working with Bezier curves
-####################################################
+###########
+bezierTools
+###########
 
 .. automodule:: fontTools.misc.bezierTools
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/misc/classifyTools.rst b/Doc/source/misc/classifyTools.rst
index 38c35d4..b02b350 100644
--- a/Doc/source/misc/classifyTools.rst
+++ b/Doc/source/misc/classifyTools.rst
@@ -3,6 +3,5 @@
 #############
 
 .. automodule:: fontTools.misc.classifyTools
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/misc/cliTools.rst b/Doc/source/misc/cliTools.rst
deleted file mode 100644
index 36b2aeb..0000000
--- a/Doc/source/misc/cliTools.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-###################################################################
-cliTools: Utilities for command-line interfaces and console scripts
-###################################################################
-
-.. automodule:: fontTools.misc.cliTools
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/misc/eexec.rst b/Doc/source/misc/eexec.rst
index b229d58..8506f86 100644
--- a/Doc/source/misc/eexec.rst
+++ b/Doc/source/misc/eexec.rst
@@ -1,8 +1,7 @@
-###############################################################
-eexec: PostScript charstring encryption and decryption routines
-###############################################################
+#####
+eexec
+#####
 
 .. automodule:: fontTools.misc.eexec
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/misc/encodingTools.rst b/Doc/source/misc/encodingTools.rst
index 4e4b719..ff29f66 100644
--- a/Doc/source/misc/encodingTools.rst
+++ b/Doc/source/misc/encodingTools.rst
@@ -3,6 +3,5 @@
 #############
 
 .. automodule:: fontTools.misc.encodingTools
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/misc/etree.rst b/Doc/source/misc/etree.rst
deleted file mode 100644
index 4679a1d..0000000
--- a/Doc/source/misc/etree.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-#####
-etree
-#####
-
-.. automodule:: fontTools.misc.etree
-   :inherited-members:
-   :members:
-   :undoc-members:
\ No newline at end of file
diff --git a/Doc/source/misc/filenames.rst b/Doc/source/misc/filenames.rst
deleted file mode 100644
index 2ebef35..0000000
--- a/Doc/source/misc/filenames.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-##########################################################
-filenames: Implements UFO User Name to File Name Algorithm
-##########################################################
-
-.. automodule:: fontTools.misc.filenames
-   :members: userNameToFileName
-   :undoc-members:
diff --git a/Doc/source/misc/fixedTools.rst b/Doc/source/misc/fixedTools.rst
index d3785f4..30a1f02 100644
--- a/Doc/source/misc/fixedTools.rst
+++ b/Doc/source/misc/fixedTools.rst
@@ -1,8 +1,7 @@
-######################################################
-fixedTools: Tools for working with fixed-point numbers
-######################################################
+##########
+fixedTools
+##########
 
 .. automodule:: fontTools.misc.fixedTools
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/misc/index.rst b/Doc/source/misc/index.rst
index bd7db09..29a7245 100644
--- a/Doc/source/misc/index.rst
+++ b/Doc/source/misc/index.rst
@@ -1,9 +1,6 @@
-##########################################################
-misc: Miscellaneous libraries helpful for font engineering
-##########################################################
-
-This is a collection of packages, most of which are used as internal support
-utilities by fontTools, but some of which may be more generally useful.
+####
+misc
+####
 
 .. toctree::
    :maxdepth: 2
@@ -11,26 +8,16 @@
    arrayTools
    bezierTools
    classifyTools
-   cliTools
    eexec
    encodingTools
-   etree
-   filenames
    fixedTools
-   intTools
    loggingTools
-   macCreatorType
-   macRes
-   plistlib
-   psCharStrings
-   psLib
-   psOperators
-   py23
    sstruct
-   symfont
+   psCharStrings
    testTools
    textTools
    timeTools
    transform
    xmlReader
    xmlWriter
+
diff --git a/Doc/source/misc/intTools.rst b/Doc/source/misc/intTools.rst
deleted file mode 100644
index 24ea231..0000000
--- a/Doc/source/misc/intTools.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-###############################################
-intTools: Tools for working with integer values
-###############################################
-
-.. automodule:: fontTools.misc.intTools
-   :members:
diff --git a/Doc/source/misc/loggingTools.rst b/Doc/source/misc/loggingTools.rst
index 157e020..fb8eab5 100644
--- a/Doc/source/misc/loggingTools.rst
+++ b/Doc/source/misc/loggingTools.rst
@@ -1,6 +1,6 @@
-###################################################################
-loggingTools: tools for interfacing with the Python logging package
-###################################################################
+############
+loggingTools
+############
 
 .. automodule:: fontTools.misc.loggingTools
    :members:
diff --git a/Doc/source/misc/macCreatorType.rst b/Doc/source/misc/macCreatorType.rst
deleted file mode 100644
index 809098d..0000000
--- a/Doc/source/misc/macCreatorType.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-##############################################################
-macCreatorType: Functions for working with Mac file attributes
-##############################################################
-
-This module requires the `xattr <https://pypi.org/project/xattr/>`_ module
-to be installed in order to function correctly.
-
-.. automodule:: fontTools.misc.macCreatorType
-   :members:
diff --git a/Doc/source/misc/macRes.rst b/Doc/source/misc/macRes.rst
deleted file mode 100644
index 6fce8e2..0000000
--- a/Doc/source/misc/macRes.rst
+++ /dev/null
@@ -1,11 +0,0 @@
-############################################
-macRes: Tools for reading Mac resource forks
-############################################
-
-Classic Mac OS files are made up of two parts - the "data fork" which contains the file contents proper, and the "resource fork" which contains a number of structured data items called "resources". Some fonts, such as Mac "font suitcases" and Type 1 LWFN fonts, still use the resource fork for this kind of structured data, and so to read them, fontTools needs to have access to resource forks.
-
-The Inside Macintosh volume `More Macintosh Toolbox <https://developer.apple.com/library/archive/documentation/mac/pdf/MoreMacintoshToolbox.pdf#page=34>`_ explains the structure of resource and data forks.
-
-.. automodule:: fontTools.misc.macRes
-   :members: ResourceReader, Resource
-   :member-order: bysource
\ No newline at end of file
diff --git a/Doc/source/misc/plistlib.rst b/Doc/source/misc/plistlib.rst
deleted file mode 100644
index 6857096..0000000
--- a/Doc/source/misc/plistlib.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-#########################################
-plistlib: Tools for handling .plist files
-#########################################
-
-.. automodule:: fontTools.misc.plistlib
-   :members: totree, fromtree, load, loads, dump, dumps
-
-.. autoclass:: fontTools.misc.plistlib.Data
-   :members:
diff --git a/Doc/source/misc/psCharStrings.rst b/Doc/source/misc/psCharStrings.rst
index 58497f6..3dc0dce 100644
--- a/Doc/source/misc/psCharStrings.rst
+++ b/Doc/source/misc/psCharStrings.rst
@@ -3,6 +3,5 @@
 #############
 
 .. automodule:: fontTools.misc.psCharStrings
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/misc/psLib.rst b/Doc/source/misc/psLib.rst
deleted file mode 100644
index f3afa8b..0000000
--- a/Doc/source/misc/psLib.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-#####
-psLib
-#####
-
-.. automodule:: fontTools.misc.psLib
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/misc/psOperators.rst b/Doc/source/misc/psOperators.rst
deleted file mode 100644
index 432274e..0000000
--- a/Doc/source/misc/psOperators.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-###########
-psOperators
-###########
-
-.. automodule:: fontTools.misc.psOperators
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/misc/py23.rst b/Doc/source/misc/py23.rst
deleted file mode 100644
index 49a76bf..0000000
--- a/Doc/source/misc/py23.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-####
-py23
-####
-
-.. automodule:: fontTools.misc.py23
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/misc/sstruct.rst b/Doc/source/misc/sstruct.rst
index 0544795..482aa23 100644
--- a/Doc/source/misc/sstruct.rst
+++ b/Doc/source/misc/sstruct.rst
@@ -3,6 +3,5 @@
 #######
 
 .. automodule:: fontTools.misc.sstruct
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/misc/symfont.rst b/Doc/source/misc/symfont.rst
deleted file mode 100644
index c189f3d..0000000
--- a/Doc/source/misc/symfont.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-#######
-symfont
-#######
-
-.. automodule:: fontTools.misc.symfont
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/misc/testTools.rst b/Doc/source/misc/testTools.rst
index 0019765..b3215ac 100644
--- a/Doc/source/misc/testTools.rst
+++ b/Doc/source/misc/testTools.rst
@@ -3,6 +3,5 @@
 #########
 
 .. automodule:: fontTools.misc.testTools
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/misc/textTools.rst b/Doc/source/misc/textTools.rst
index 0044c08..754eb67 100644
--- a/Doc/source/misc/textTools.rst
+++ b/Doc/source/misc/textTools.rst
@@ -3,6 +3,5 @@
 #########
 
 .. automodule:: fontTools.misc.textTools
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/misc/timeTools.rst b/Doc/source/misc/timeTools.rst
index c0a7199..f8d1508 100644
--- a/Doc/source/misc/timeTools.rst
+++ b/Doc/source/misc/timeTools.rst
@@ -3,6 +3,5 @@
 #########
 
 .. automodule:: fontTools.misc.timeTools
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/misc/transform.rst b/Doc/source/misc/transform.rst
index 44a3dbd..9517fe0 100644
--- a/Doc/source/misc/transform.rst
+++ b/Doc/source/misc/transform.rst
@@ -3,6 +3,5 @@
 #########
 
 .. automodule:: fontTools.misc.transform
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/misc/xmlReader.rst b/Doc/source/misc/xmlReader.rst
index d0b80f5..6e09354 100644
--- a/Doc/source/misc/xmlReader.rst
+++ b/Doc/source/misc/xmlReader.rst
@@ -3,6 +3,5 @@
 #########
 
 .. automodule:: fontTools.misc.xmlReader
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/misc/xmlWriter.rst b/Doc/source/misc/xmlWriter.rst
index 5f7aaef..f488183 100644
--- a/Doc/source/misc/xmlWriter.rst
+++ b/Doc/source/misc/xmlWriter.rst
@@ -3,6 +3,5 @@
 #########
 
 .. automodule:: fontTools.misc.xmlWriter
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/mtiLib.rst b/Doc/source/mtiLib.rst
deleted file mode 100644
index 1bf74e1..0000000
--- a/Doc/source/mtiLib.rst
+++ /dev/null
@@ -1,14 +0,0 @@
-###########################################
-mtiLib: Read Monotype FontDame source files
-###########################################
-
-FontTools provides support for reading the OpenType layout tables produced by
-Monotype's FontDame and Font Chef font editors. These tables are written in a
-simple textual format. The ``mtiLib`` library parses these text files and creates
-table objects representing their contents.
-
-Additionally, ``fonttools mtiLib`` will convert a text file to TTX XML.
-
-
-.. automodule:: fontTools.mtiLib
-   :members: build, main
diff --git a/Doc/source/optional.rst b/Doc/source/optional.rst
deleted file mode 100644
index 09376a2..0000000
--- a/Doc/source/optional.rst
+++ /dev/null
@@ -1,140 +0,0 @@
-Optional Dependencies
-=====================
-
-The fonttools PyPI distribution also supports so-called "extras", i.e. a
-set of keywords that describe a group of additional dependencies, which can be
-used when installing via pip, or when specifying a requirement.
-For example:
-
-.. code:: sh
-
-    pip install fonttools[ufo,lxml,woff,unicode]
-
-This command will install fonttools, as well as the optional dependencies that
-are required to unlock the extra features named "ufo", etc.
-
-.. note::
-
-    Optional dependencies are detailed by module in the list below with the ``Extra`` setting that automates ``pip`` dependency installation when this is supported.
-
-
-
-:py:mod:`fontTools.misc.etree`
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The module exports a ElementTree-like API for reading/writing XML files, and allows to use as the backend either the built-in ``xml.etree`` module or `lxml <https://lxml.de>`__. The latter is preferred whenever present, as it is generally faster and more secure.
-
-*Extra:* ``lxml``
-
-
-:py:mod:`fontTools.ufoLib`
-^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Package for reading and writing UFO source files; it requires:
-
-* `fs <https://pypi.org/pypi/fs>`__: (aka ``pyfilesystem2``) filesystem abstraction layer.
-
-* `enum34 <https://pypi.org/pypi/enum34>`__: backport for the built-in ``enum`` module (only required on Python < 3.4).
-
-*Extra:* ``ufo``
-
-
-:py:mod:`fontTools.ttLib.woff2`
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Module to compress/decompress WOFF 2.0 web fonts; it requires:
-
-* `brotli <https://pypi.python.org/pypi/Brotli>`__: Python bindings of the Brotli compression library.
-
-*Extra:* ``woff``
-
-
-:py:mod:`fontTools.unicode`
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-To display the Unicode character names when dumping the ``cmap`` table
-with ``ttx`` we use the ``unicodedata`` module in the Standard Library.
-The version included in there varies between different Python versions.
-To use the latest available data, you can install:
-
-* `unicodedata2 <https://pypi.python.org/pypi/unicodedata2>`__: ``unicodedata`` backport for Python 2.7
-  and 3.x updated to the latest Unicode version 12.0. Note this is not necessary if you use Python 3.8
-  as the latter already comes with an up-to-date ``unicodedata``.
-
-*Extra:* ``unicode``
-
-
-:py:mod:`fontTools.varLib.interpolatable`
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Module for finding wrong contour/component order between different masters.
-It requires one of the following packages in order to solve the so-called
-"minimum weight perfect matching problem in bipartite graphs", or
-the Assignment problem:
-
-* `scipy <https://pypi.python.org/pypi/scipy>`__: the Scientific Library for Python, which internally
-  uses `NumPy <https://pypi.python.org/pypi/numpy>`__ arrays and hence is very fast;
-* `munkres <https://pypi.python.org/pypi/munkres>`__: a pure-Python module that implements the Hungarian
-  or Kuhn-Munkres algorithm.
-
-*Extra:* ``interpolatable``
-
-
-:py:mod:`fontTools.varLib.plot`
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Module for visualizing DesignSpaceDocument and resulting VariationModel.
-
-* `matplotlib <https://pypi.org/pypi/matplotlib>`__: 2D plotting library.
-
-*Extra:* ``plot``
-
-
-:py:mod:`fontTools.misc.symfont`
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Advanced module for symbolic font statistics analysis; it requires:
-
-* `sympy <https://pypi.python.org/pypi/sympy>`__: the Python library for symbolic mathematics.
-
-*Extra:* ``symfont``
-
-
-:py:mod:`fontTools.t1Lib`
-^^^^^^^^^^^^^^^^^^^^^^^^^
-
-To get the file creator and type of Macintosh PostScript Type 1 fonts
-on Python 3 you need to install the following module, as the old ``MacOS``
-module is no longer included in Mac Python:
-
-* `xattr <https://pypi.python.org/pypi/xattr>`__: Python wrapper for extended filesystem attributes
-  (macOS platform only).
-
-*Extra:* ``type1``
-
-
-:py:mod:`fontTools.pens.cocoaPen`
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Pen for drawing glyphs with Cocoa ``NSBezierPath``, requires:
-
-* `PyObjC <https://pypi.python.org/pypi/pyobjc>`__: the bridge between Python and the Objective-C
-  runtime (macOS platform only).
-
-
-:py:mod:`fontTools.pens.qtPen`
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Pen for drawing glyphs with Qt's ``QPainterPath``, requires:
-
-* `PyQt5 <https://pypi.python.org/pypi/PyQt5>`__: Python bindings for the Qt cross platform UI and
-  application toolkit.
-
-
-:py:mod:`fontTools.pens.reportLabPen`
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Pen to drawing glyphs as PNG images, requires:
-
-* `reportlab <https://pypi.python.org/pypi/reportlab>`__: Python toolkit for generating PDFs and
-  graphics.
diff --git a/Doc/source/otlLib/index.rst b/Doc/source/otlLib/index.rst
deleted file mode 100644
index 1984914..0000000
--- a/Doc/source/otlLib/index.rst
+++ /dev/null
@@ -1,74 +0,0 @@
-#################################################
-otlLib: Routines for working with OpenType Layout
-#################################################
-
-The ``fontTools.otlLib`` library provides routines to help you create the
-subtables and other data structures you need when you are editing a font's
-``GSUB`` and ``GPOS`` tables: substitution and positioning rules, anchors,
-lookups, coverage tables and so on.
-
-------------------------------------------
-High-level OpenType Layout Lookup Builders
-------------------------------------------
-
-.. automodule:: fontTools.otlLib.builder
-   :members: AlternateSubstBuilder, ChainContextPosBuilder, ChainContextSubstBuilder, LigatureSubstBuilder, MultipleSubstBuilder, CursivePosBuilder, MarkBasePosBuilder, MarkLigPosBuilder, MarkMarkPosBuilder, ReverseChainSingleSubstBuilder, SingleSubstBuilder, ClassPairPosSubtableBuilder, PairPosBuilder, SinglePosBuilder
-   :member-order: bysource
-
---------------------------------------
-Common OpenType Layout Data Structures
---------------------------------------
-
-.. automodule:: fontTools.otlLib.builder
-   :members: buildCoverage, buildLookup
-
-------------------------------------
-Low-level GSUB Table Lookup Builders
-------------------------------------
-
-These functions deal with the "simple" lookup types. See above for classes to
-help build more complex lookups (contextual and chaining lookups).
-
-.. automodule:: fontTools.otlLib.builder
-   :members: buildSingleSubstSubtable, buildMultipleSubstSubtable, buildAlternateSubstSubtable, buildLigatureSubstSubtable
-
---------------------------
-GPOS Shared Table Builders
---------------------------
-
-The functions help build the `GPOS shared tables <https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#shared-tables-value-record-anchor-table-and-mark-array-table>`_
-as defined in the OpenType spec: value records, anchors, mark arrays and
-mark record tables.
-
-.. automodule:: fontTools.otlLib.builder
-   :members: buildValue, buildAnchor, buildMarkArray, buildDevice, buildBaseArray, buildComponentRecord, buildMarkArray, buildValue
-   :member-order: bysource
-
-------------------------------------
-Low-level GPOS Table Lookup Builders
-------------------------------------
-
-These functions deal with the "simple" lookup types. See above for classes to
-help build more complex lookups (contextual and chaining lookups).
-
-.. automodule:: fontTools.otlLib.builder
-   :members: buildCursivePosSubtable, buildLigatureArray, buildMarkBasePos, buildMarkBasePosSubtable, buildMarkLigPos, buildMarkLigPosSubtable, buildPairPosClassesSubtable, buildPairPosGlyphs, buildPairPosGlyphsSubtable, buildSinglePos, buildSinglePosSubtable
-   :member-order: bysource
-
-----------------------------
-GDEF Table Subtable Builders
-----------------------------
-
-These functions build subtables for elements of the ``GDEF`` table.
-
-.. automodule:: fontTools.otlLib.builder
-   :members: buildAttachList, buildLigCaretList, buildMarkGlyphSetsDef
-   :member-order: bysource
-
-------------------
-STAT Table Builder
-------------------
-
-.. automodule:: fontTools.otlLib.builder
-   :members: buildStatTable
-   :member-order: bysource
diff --git a/Doc/source/pens/areaPen.rst b/Doc/source/pens/areaPen.rst
index f3f21bb..03a751b 100644
--- a/Doc/source/pens/areaPen.rst
+++ b/Doc/source/pens/areaPen.rst
@@ -3,6 +3,5 @@
 #######
 
 .. automodule:: fontTools.pens.areaPen
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/pens/basePen.rst b/Doc/source/pens/basePen.rst
index 87bf832..f5965b1 100644
--- a/Doc/source/pens/basePen.rst
+++ b/Doc/source/pens/basePen.rst
@@ -3,6 +3,5 @@
 #######
 
 .. automodule:: fontTools.pens.basePen
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/pens/boundsPen.rst b/Doc/source/pens/boundsPen.rst
index a0d9ab4..8de5620 100644
--- a/Doc/source/pens/boundsPen.rst
+++ b/Doc/source/pens/boundsPen.rst
@@ -3,6 +3,5 @@
 #########
 
 .. automodule:: fontTools.pens.boundsPen
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/pens/cocoaPen.rst b/Doc/source/pens/cocoaPen.rst
deleted file mode 100644
index bbe8050..0000000
--- a/Doc/source/pens/cocoaPen.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-########
-cocoaPen
-########
-
-.. automodule:: fontTools.pens.cocoaPen
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/pens/cu2quPen.rst b/Doc/source/pens/cu2quPen.rst
deleted file mode 100644
index 4ae0249..0000000
--- a/Doc/source/pens/cu2quPen.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-########
-cu2quPen
-########
-
-.. automodule:: fontTools.pens.cu2quPen
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/pens/filterPen.rst b/Doc/source/pens/filterPen.rst
index c79b944..0b484a4 100644
--- a/Doc/source/pens/filterPen.rst
+++ b/Doc/source/pens/filterPen.rst
@@ -3,6 +3,5 @@
 #########
 
 .. automodule:: fontTools.pens.filterPen
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/pens/index.rst b/Doc/source/pens/index.rst
index 91175cf..7e5a192 100644
--- a/Doc/source/pens/index.rst
+++ b/Doc/source/pens/index.rst
@@ -5,26 +5,14 @@
 .. toctree::
    :maxdepth: 1
 
-   areaPen
    basePen
    boundsPen
-   cocoaPen
-   cu2quPen
-   filterPen
-   momentsPen
-   perimeterPen
    pointInsidePen
-   pointPen
-   qtPen
-   recordingPen
-   reportLabPen
-   reverseContourPen
-   roundingPen
-   statisticsPen
-   svgPathPen
-   t2CharStringPen
-   teePen
+   filterPen
    transformPen
-   ttGlyphPen
-   wxPen
-
+   t2CharStringPen
+   statisticsPen
+   recordingPen
+   teePen
+   areaPen
+   perimeterPen
diff --git a/Doc/source/pens/momentsPen.rst b/Doc/source/pens/momentsPen.rst
deleted file mode 100644
index 4587f75..0000000
--- a/Doc/source/pens/momentsPen.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-##########
-momentsPen
-##########
-
-.. automodule:: fontTools.pens.momentsPen
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/pens/perimeterPen.rst b/Doc/source/pens/perimeterPen.rst
index c625a3d..97fecca 100644
--- a/Doc/source/pens/perimeterPen.rst
+++ b/Doc/source/pens/perimeterPen.rst
@@ -3,6 +3,5 @@
 ############
 
 .. automodule:: fontTools.pens.perimeterPen
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/pens/pointInsidePen.rst b/Doc/source/pens/pointInsidePen.rst
index 81a4b2e..9954e47 100644
--- a/Doc/source/pens/pointInsidePen.rst
+++ b/Doc/source/pens/pointInsidePen.rst
@@ -3,6 +3,5 @@
 ##############
 
 .. automodule:: fontTools.pens.pointInsidePen
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/pens/pointPen.rst b/Doc/source/pens/pointPen.rst
deleted file mode 100644
index 09b9897..0000000
--- a/Doc/source/pens/pointPen.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-########
-pointPen
-########
-
-.. automodule:: fontTools.pens.pointPen
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/pens/qtPen.rst b/Doc/source/pens/qtPen.rst
deleted file mode 100644
index bfaa9b5..0000000
--- a/Doc/source/pens/qtPen.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-#####
-qtPen
-#####
-
-.. automodule:: fontTools.pens.qtPen
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/pens/recordingPen.rst b/Doc/source/pens/recordingPen.rst
index ee9178c..69e7ceb 100644
--- a/Doc/source/pens/recordingPen.rst
+++ b/Doc/source/pens/recordingPen.rst
@@ -3,6 +3,5 @@
 ############
 
 .. automodule:: fontTools.pens.recordingPen
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/pens/reportLabPen.rst b/Doc/source/pens/reportLabPen.rst
deleted file mode 100644
index 7fe8784..0000000
--- a/Doc/source/pens/reportLabPen.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-############
-reportLabPen
-############
-
-.. automodule:: fontTools.pens.reportLabPen
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/pens/reverseContourPen.rst b/Doc/source/pens/reverseContourPen.rst
deleted file mode 100644
index 8178e2c..0000000
--- a/Doc/source/pens/reverseContourPen.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-#################
-reverseContourPen
-#################
-
-.. automodule:: fontTools.pens.reverseContourPen
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/pens/roundingPen.rst b/Doc/source/pens/roundingPen.rst
deleted file mode 100644
index 7eb4214..0000000
--- a/Doc/source/pens/roundingPen.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-###########
-roundingPen
-###########
-
-.. automodule:: fontTools.pens.roundingPen
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/pens/statisticsPen.rst b/Doc/source/pens/statisticsPen.rst
index e06e322..efa1608 100644
--- a/Doc/source/pens/statisticsPen.rst
+++ b/Doc/source/pens/statisticsPen.rst
@@ -3,6 +3,5 @@
 #############
 
 .. automodule:: fontTools.pens.statisticsPen
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/pens/svgPathPen.rst b/Doc/source/pens/svgPathPen.rst
deleted file mode 100644
index 45bf151..0000000
--- a/Doc/source/pens/svgPathPen.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-##########
-svgPathPen
-##########
-
-.. automodule:: fontTools.pens.svgPathPen
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/pens/t2CharStringPen.rst b/Doc/source/pens/t2CharStringPen.rst
index 9d55391..d58c67a 100644
--- a/Doc/source/pens/t2CharStringPen.rst
+++ b/Doc/source/pens/t2CharStringPen.rst
@@ -3,6 +3,5 @@
 ###############
 
 .. automodule:: fontTools.pens.t2CharStringPen
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/pens/teePen.rst b/Doc/source/pens/teePen.rst
index 2a4558d..7a0313c 100644
--- a/Doc/source/pens/teePen.rst
+++ b/Doc/source/pens/teePen.rst
@@ -3,6 +3,5 @@
 ######
 
 .. automodule:: fontTools.pens.teePen
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/pens/transformPen.rst b/Doc/source/pens/transformPen.rst
index 3bb802a..5b414f8 100644
--- a/Doc/source/pens/transformPen.rst
+++ b/Doc/source/pens/transformPen.rst
@@ -3,6 +3,5 @@
 ############
 
 .. automodule:: fontTools.pens.transformPen
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/pens/ttGlyphPen.rst b/Doc/source/pens/ttGlyphPen.rst
deleted file mode 100644
index e1bf701..0000000
--- a/Doc/source/pens/ttGlyphPen.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-##########
-ttGlyphPen
-##########
-
-.. automodule:: fontTools.pens.ttGlyphPen
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/pens/wxPen.rst b/Doc/source/pens/wxPen.rst
deleted file mode 100644
index 37ce50a..0000000
--- a/Doc/source/pens/wxPen.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-#####
-wxPen
-#####
-
-.. automodule:: fontTools.pens.wxPen
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/subset.rst b/Doc/source/subset.rst
new file mode 100644
index 0000000..a8fff95
--- /dev/null
+++ b/Doc/source/subset.rst
@@ -0,0 +1,7 @@
+######
+subset
+######
+
+.. automodule:: fontTools.subset
+   :members:
+   :undoc-members:
diff --git a/Doc/source/subset/cff.rst b/Doc/source/subset/cff.rst
deleted file mode 100644
index 8c21c39..0000000
--- a/Doc/source/subset/cff.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-cff
-###
-
-.. automodule:: fontTools.subset.cff
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/subset/index.rst b/Doc/source/subset/index.rst
deleted file mode 100644
index f32e0d4..0000000
--- a/Doc/source/subset/index.rst
+++ /dev/null
@@ -1,13 +0,0 @@
-######
-subset
-######
-
-.. toctree::
-   :maxdepth: 1
-
-   cff
-
-.. automodule:: fontTools.subset
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/svgLib/index.rst b/Doc/source/svgLib/index.rst
deleted file mode 100644
index f86ff0a..0000000
--- a/Doc/source/svgLib/index.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-######
-svgLib
-######
-
-.. toctree::
-   :maxdepth: 1
-
-   path/index
diff --git a/Doc/source/svgLib/path/index.rst b/Doc/source/svgLib/path/index.rst
deleted file mode 100644
index 0d7551b..0000000
--- a/Doc/source/svgLib/path/index.rst
+++ /dev/null
@@ -1,13 +0,0 @@
-####
-path
-####
-
-.. toctree::
-   :maxdepth: 1
-
-   parser
-
-.. automodule:: fontTools.svgLib.path
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/svgLib/path/parser.rst b/Doc/source/svgLib/path/parser.rst
deleted file mode 100644
index fc7e7ff..0000000
--- a/Doc/source/svgLib/path/parser.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-######
-parser
-######
-
-.. automodule:: fontTools.svgLib.path.parser
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/t1Lib.rst b/Doc/source/t1Lib.rst
index 4436086..dcc0438 100644
--- a/Doc/source/t1Lib.rst
+++ b/Doc/source/t1Lib.rst
@@ -3,6 +3,5 @@
 #####
 
 .. automodule:: fontTools.t1Lib
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/ttLib/index.rst b/Doc/source/ttLib/index.rst
index 4dfa2d6..d273934 100644
--- a/Doc/source/ttLib/index.rst
+++ b/Doc/source/ttLib/index.rst
@@ -7,13 +7,9 @@
 
    macUtils
    sfnt
-   standardGlyphOrder
    tables
-   ttCollection
-   ttFont
    woff2
 
 .. automodule:: fontTools.ttLib
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/ttLib/macUtils.rst b/Doc/source/ttLib/macUtils.rst
index 356a911..cb014d7 100644
--- a/Doc/source/ttLib/macUtils.rst
+++ b/Doc/source/ttLib/macUtils.rst
@@ -3,6 +3,5 @@
 ########
 
 .. automodule:: fontTools.ttLib.macUtils
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/ttLib/sfnt.rst b/Doc/source/ttLib/sfnt.rst
index 29566ab..41e3032 100644
--- a/Doc/source/ttLib/sfnt.rst
+++ b/Doc/source/ttLib/sfnt.rst
@@ -3,6 +3,5 @@
 ####
 
 .. automodule:: fontTools.ttLib.sfnt
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/ttLib/standardGlyphOrder.rst b/Doc/source/ttLib/standardGlyphOrder.rst
deleted file mode 100644
index ca2557b..0000000
--- a/Doc/source/ttLib/standardGlyphOrder.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-##################
-standardGlyphOrder
-##################
-
-.. automodule:: fontTools.ttLib.standardGlyphOrder
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-.. data:: fontTools.ttLib.standardGlyphOrder.standardGlyphOrder
-
-A Python list of "standard" glyphs required by post table formats 1.0 and 2.0.
diff --git a/Doc/source/ttLib/tables.rst b/Doc/source/ttLib/tables.rst
index 45c76b8..6ae705f 100644
--- a/Doc/source/ttLib/tables.rst
+++ b/Doc/source/ttLib/tables.rst
@@ -2,114 +2,7 @@
 tables
 ######
 
-This folder is a subpackage of :py:mod:`fontTools.ttLib`. Each module here is a
-specialized TT/OT table converter: they can convert raw data
-to Python objects and vice versa. Usually you don't need to
-use the modules directly: they are imported and used
-automatically when needed by :py:mod:`fontTools.ttLib`.
-
-If you are writing you own table converter the following is
-important.
-
-The modules here have pretty strange names: this is due to the
-fact that we need to map TT table tags (which are case sensitive)
-to filenames (which on Mac and Win aren't case sensitive) as well
-as to Python identifiers. The latter means it can only contain
-[A-Za-z0-9_] and cannot start with a number.
-
-:py:mod:`fontTools.ttLib` provides functions to expand a tag into the format used here::
-
-    >>> from fontTools import ttLib
-    >>> ttLib.tagToIdentifier("FOO ")
-    'F_O_O_'
-    >>> ttLib.tagToIdentifier("cvt ")
-    '_c_v_t'
-    >>> ttLib.tagToIdentifier("OS/2")
-    'O_S_2f_2'
-    >>> ttLib.tagToIdentifier("glyf")
-    '_g_l_y_f'
-    >>>
-
-And vice versa::
-
-    >>> ttLib.identifierToTag("F_O_O_")
-    'FOO '
-    >>> ttLib.identifierToTag("_c_v_t")
-    'cvt '
-    >>> ttLib.identifierToTag("O_S_2f_2")
-    'OS/2'
-    >>> ttLib.identifierToTag("_g_l_y_f")
-    'glyf'
-    >>>
-
-Eg. the 'glyf' table converter lives in a Python file called::
-
-	_g_l_y_f.py
-
-The converter itself is a class, named "table_" + expandedtag. Eg::
-
-
-	class table__g_l_y_f:
-		etc.
-
-
-Note that if you _do_ need to use such modules or classes manually,
-there are two convenient API functions that let you find them by tag::
-
-    >>> ttLib.getTableModule('glyf')
-    <module 'ttLib.tables._g_l_y_f'>
-    >>> ttLib.getTableClass('glyf')
-    <class ttLib.tables._g_l_y_f.table__g_l_y_f at 645f400>
-    >>
-
-You must subclass from :py:mod:`fontTools.ttLib.tables.DefaultTable.DefaultTable`. It provides some default
-behavior, as well as a constructor method (__init__) that you don't need to
-override.
-
-Your converter should minimally provide two methods::
-
-
-    class table_F_O_O_(DefaultTable.DefaultTable): # converter for table 'FOO '
-
-        def decompile(self, data, ttFont):
-            # 'data' is the raw table data. Unpack it into a
-            # Python data structure.
-            # 'ttFont' is a ttLib.TTfile instance, enabling you to
-            # refer to other tables. Do ***not*** keep a reference to
-            # it: it will cause a circular reference (ttFont saves
-            # a reference to us), and that means we'll be leaking
-            # memory. If you need to use it in other methods, just
-            # pass it around as a method argument.
-
-        def compile(self, ttFont):
-            # Return the raw data, as converted from the Python
-            # data structure.
-            # Again, 'ttFont' is there so you can access other tables.
-            # Same warning applies.
-
-
-If you want to support TTX import/export as well, you need to provide two
-additional methods::
-
-
-	def toXML(self, writer, ttFont):
-		# XXX
-
-	def fromXML(self, (name, attrs, content), ttFont):
-		# XXX
-
-
-
 .. automodule:: fontTools.ttLib.tables
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-_a_n_k_r
---------
-
-.. automodule:: fontTools.ttLib.tables._a_n_k_r
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -117,23 +10,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._a_v_a_r
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-_b_s_l_n
---------
-
-.. automodule:: fontTools.ttLib.tables._b_s_l_n
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-_c_i_d_g
---------
-
-.. automodule:: fontTools.ttLib.tables._c_i_d_g
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -141,7 +17,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._c_m_a_p
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -149,7 +24,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._c_v_a_r
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -157,7 +31,6 @@
 ------
 
 .. automodule:: fontTools.ttLib.tables._c_v_t
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -165,7 +38,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._f_e_a_t
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -173,7 +45,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._f_p_g_m
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -181,7 +52,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._f_v_a_r
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -189,16 +59,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._g_a_s_p
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-
-_g_c_i_d
---------
-
-.. automodule:: fontTools.ttLib.tables._g_c_i_d
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -206,7 +66,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._g_l_y_f
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -214,7 +73,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._g_v_a_r
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -222,7 +80,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._h_d_m_x
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -230,7 +87,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._h_e_a_d
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -238,7 +94,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._h_h_e_a
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -246,7 +101,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._h_m_t_x
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -254,15 +108,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._k_e_r_n
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-_l_c_a_r
---------
-
-.. automodule:: fontTools.ttLib.tables._l_c_a_r
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -270,7 +115,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._l_o_c_a
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -278,7 +122,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._l_t_a_g
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -286,7 +129,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._m_a_x_p
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -294,24 +136,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._m_e_t_a
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-_m_o_r_t
---------
-
-.. automodule:: fontTools.ttLib.tables._m_o_r_t
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-
-_m_o_r_x
---------
-
-.. automodule:: fontTools.ttLib.tables._m_o_r_x
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -319,15 +143,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._n_a_m_e
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-_o_p_b_d
---------
-
-.. automodule:: fontTools.ttLib.tables._o_p_b_d
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -335,7 +150,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._p_o_s_t
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -343,16 +157,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._p_r_e_p
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-
-_p_r_o_p
---------
-
-.. automodule:: fontTools.ttLib.tables._p_r_o_p
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -360,7 +164,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._s_b_i_x
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -368,7 +171,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._t_r_a_k
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -376,7 +178,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._v_h_e_a
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -384,7 +185,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables._v_m_t_x
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -392,7 +192,6 @@
 ----------
 
 .. automodule:: fontTools.ttLib.tables.asciiTable
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -400,7 +199,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.B_A_S_E_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -408,7 +206,6 @@
 ------------------
 
 .. automodule:: fontTools.ttLib.tables.BitmapGlyphMetrics
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -416,7 +213,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.C_B_D_T_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -424,7 +220,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.C_B_L_C_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -432,7 +227,6 @@
 ------
 
 .. automodule:: fontTools.ttLib.tables.C_F_F_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -440,7 +234,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.C_F_F__2
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -448,7 +241,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.C_O_L_R_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -456,7 +248,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.C_P_A_L_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -464,7 +255,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.D_S_I_G_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -472,7 +262,6 @@
 ------------
 
 .. automodule:: fontTools.ttLib.tables.DefaultTable
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -480,7 +269,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.E_B_D_T_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -488,41 +276,13 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.E_B_L_C_
-   :inherited-members:
    :members:
    :undoc-members:
 
-F__e_a_t
---------
-
-.. automodule:: fontTools.ttLib.tables.F__e_a_t
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-
 F_F_T_M_
 --------
 
 .. automodule:: fontTools.ttLib.tables.F_F_T_M_
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-
-G__l_a_t
---------
-
-.. automodule:: fontTools.ttLib.tables.G__l_a_t
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-G__l_o_c
---------
-
-.. automodule:: fontTools.ttLib.tables.G__l_o_c
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -530,7 +290,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.G_D_E_F_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -538,7 +297,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.G_M_A_P_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -546,7 +304,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.G_P_K_G_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -554,7 +311,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.G_P_O_S_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -562,15 +318,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.G_S_U_B_
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-grUtils
--------
-
-.. automodule:: fontTools.ttLib.tables.grUtils
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -578,7 +325,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.H_V_A_R_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -586,7 +332,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.J_S_T_F_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -594,7 +339,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.L_T_S_H_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -602,7 +346,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.M_A_T_H_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -610,7 +353,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.M_E_T_A_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -618,7 +360,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.M_V_A_R_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -626,7 +367,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.O_S_2f_2
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -634,7 +374,6 @@
 ------
 
 .. automodule:: fontTools.ttLib.tables.otBase
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -642,7 +381,6 @@
 ------------
 
 .. automodule:: fontTools.ttLib.tables.otConverters
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -650,7 +388,6 @@
 ------
 
 .. automodule:: fontTools.ttLib.tables.otData
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -658,23 +395,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.otTables
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-S__i_l_f
---------
-
-.. automodule:: fontTools.ttLib.tables.S__i_l_f
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-S__i_l_l
---------
-
-.. automodule:: fontTools.ttLib.tables.S__i_l_l
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -682,7 +402,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.S_I_N_G_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -690,7 +409,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.S_T_A_T_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -698,7 +416,6 @@
 ------
 
 .. automodule:: fontTools.ttLib.tables.S_V_G_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -706,7 +423,6 @@
 ---------
 
 .. automodule:: fontTools.ttLib.tables.sbixGlyph
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -714,7 +430,6 @@
 ----------
 
 .. automodule:: fontTools.ttLib.tables.sbixStrike
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -722,7 +437,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.T_S_I__0
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -730,7 +444,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.T_S_I__1
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -738,7 +451,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.T_S_I__2
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -746,7 +458,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.T_S_I__3
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -754,71 +465,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.T_S_I__5
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-T_S_I_B_
---------
-
-.. automodule:: fontTools.ttLib.tables.T_S_I_B_
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-T_S_I_C_
---------
-
-.. automodule:: fontTools.ttLib.tables.T_S_I_C_
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-T_S_I_D_
---------
-
-.. automodule:: fontTools.ttLib.tables.T_S_I_D_
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-T_S_I_J_
---------
-
-.. automodule:: fontTools.ttLib.tables.T_S_I_J_
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-T_S_I_P_
---------
-
-.. automodule:: fontTools.ttLib.tables.T_S_I_P_
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-T_S_I_S_
---------
-
-.. automodule:: fontTools.ttLib.tables.T_S_I_S_
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-T_S_I_V_
---------
-
-.. automodule:: fontTools.ttLib.tables.T_S_I_V_
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-T_T_F_A_
---------
-
-.. automodule:: fontTools.ttLib.tables.T_T_F_A_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -826,7 +472,6 @@
 ---------
 
 .. automodule:: fontTools.ttLib.tables.ttProgram
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -834,7 +479,6 @@
 --------------
 
 .. automodule:: fontTools.ttLib.tables.TupleVariation
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -842,7 +486,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.V_D_M_X_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -850,7 +493,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.V_O_R_G_
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -858,7 +500,6 @@
 --------
 
 .. automodule:: fontTools.ttLib.tables.V_V_A_R_
-   :inherited-members:
    :members:
    :undoc-members:
 
diff --git a/Doc/source/ttLib/ttCollection.rst b/Doc/source/ttLib/ttCollection.rst
deleted file mode 100644
index 0ca4ebd..0000000
--- a/Doc/source/ttLib/ttCollection.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-############
-ttCollection
-############
-
-.. automodule:: fontTools.ttLib.ttCollection
-   :inherited-members:
-   :members:
-   :undoc-members:
\ No newline at end of file
diff --git a/Doc/source/ttLib/ttFont.rst b/Doc/source/ttLib/ttFont.rst
deleted file mode 100644
index a571050..0000000
--- a/Doc/source/ttLib/ttFont.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-######
-ttFont
-######
-
-.. automodule:: fontTools.ttLib.ttFont
-   :inherited-members:
-   :members:
-   :undoc-members:
-   :private-members:
diff --git a/Doc/source/ttLib/woff2.rst b/Doc/source/ttLib/woff2.rst
index 327bb5b..0c464be 100644
--- a/Doc/source/ttLib/woff2.rst
+++ b/Doc/source/ttLib/woff2.rst
@@ -3,6 +3,5 @@
 #####
 
 .. automodule:: fontTools.ttLib.woff2
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/ttx.rst b/Doc/source/ttx.rst
index b6e43f5..1c90901 100644
--- a/Doc/source/ttx.rst
+++ b/Doc/source/ttx.rst
@@ -2,61 +2,6 @@
 ttx
 ###
 
-
-TTX – From OpenType and TrueType to XML and Back
-------------------------------------------------
-
-Once installed you can use the ttx command to convert binary font files (.otf, .ttf, etc) to the TTX XML format, edit them, and convert them back to binary format. TTX files have a .ttx file extension::
-
-    ttx /path/to/font.otf
-    ttx /path/to/font.ttx
-
-The TTX application can be used in two ways, depending on what platform you run it on:
-
-* As a command line tool (Windows/DOS, Unix, macOS)
-* By dropping files onto the application (Windows, macOS)
-
-TTX detects what kind of files it is fed: it will output a ``.ttx`` file when it sees a ``.ttf`` or ``.otf``, and it will compile a ``.ttf`` or ``.otf`` when the input file is a ``.ttx`` file. By default, the output file is created in the same folder as the input file, and will have the same name as the input file but with a different extension. TTX will never overwrite existing files, but if necessary will append a unique number to the output filename (before the extension) such as ``Arial#1.ttf``.
-
-When using TTX from the command line there are a bunch of extra options. These are explained in the help text, as displayed when typing ``ttx -h`` at the command prompt. These additional options include:
-
-
-* specifying the folder where the output files are created
-* specifying which tables to dump or which tables to exclude
-* merging partial .ttx files with existing .ttf or .otf files
-* listing brief table info instead of dumping to .ttx
-* splitting tables to separate .ttx files
-* disabling TrueType instruction disassembly
-
-The TTX file format
-^^^^^^^^^^^^^^^^^^^
-
-.. begin table list
-
-The following tables are currently supported::
-
-    BASE, CBDT, CBLC, CFF, CFF2, COLR, CPAL, DSIG, Debg, EBDT, EBLC,
-    FFTM, Feat, GDEF, GMAP, GPKG, GPOS, GSUB, Glat, Gloc, HVAR, JSTF,
-    LTSH, MATH, META, MVAR, OS/2, SING, STAT, SVG, Silf, Sill, TSI0,
-    TSI1, TSI2, TSI3, TSI5, TSIB, TSIC, TSID, TSIJ, TSIP, TSIS, TSIV,
-    TTFA, VDMX, VORG, VVAR, ankr, avar, bsln, cidg, cmap, cvar, cvt,
-    feat, fpgm, fvar, gasp, gcid, glyf, gvar, hdmx, head, hhea, hmtx,
-    kern, lcar, loca, ltag, maxp, meta, mort, morx, name, opbd, post,
-    prep, prop, sbix, trak, vhea and vmtx
-
-.. end table list
-
-Other tables are dumped as hexadecimal data.
-
-TrueType fonts use glyph indices (GlyphIDs) to refer to glyphs in most places. While this is fine in binary form, it is really hard to work with for humans. Therefore we use names instead.
-
-The glyph names are either extracted from the ``CFF`` table or the ``post`` table, or are derived from a Unicode ``cmap`` table. In the latter case the Adobe Glyph List is used to calculate names based on Unicode values. If all of these methods fail, names are invented based on GlyphID (eg ``glyph00142``)
-
-It is possible that different glyphs use the same name. If this happens, we force the names to be unique by appending #n to the name (n being an integer number.) The original names are being kept, so this has no influence on a "round tripped" font.
-
-Because the order in which glyphs are stored inside the binary font is important, we maintain an ordered list of glyph names in the font.
-
 .. automodule:: fontTools.ttx
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/ufoLib/converters.rst b/Doc/source/ufoLib/converters.rst
index 2b37e56..74aafbf 100644
--- a/Doc/source/ufoLib/converters.rst
+++ b/Doc/source/ufoLib/converters.rst
@@ -1,9 +1,9 @@
+.. highlight:: python
 
-##########
+==========
 converters
-##########
+==========
 
-.. automodule:: fontTools.ufoLib.converters
+.. automodule:: ufoLib.converters
    :inherited-members:
    :members:
-   :undoc-members:
diff --git a/Doc/source/ufoLib/errors.rst b/Doc/source/ufoLib/errors.rst
deleted file mode 100644
index ba079ab..0000000
--- a/Doc/source/ufoLib/errors.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-
-######
-errors
-######
-
-.. automodule:: fontTools.ufoLib.errors
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/ufoLib/filenames.rst b/Doc/source/ufoLib/filenames.rst
index 33a3c1b..d604c4c 100644
--- a/Doc/source/ufoLib/filenames.rst
+++ b/Doc/source/ufoLib/filenames.rst
@@ -1,9 +1,9 @@
+.. highlight:: python
 
-#########
+=========
 filenames
-#########
+=========
 
-.. automodule:: fontTools.ufoLib.filenames
+.. automodule:: ufoLib.filenames
    :inherited-members:
    :members:
-   :undoc-members:
diff --git a/Doc/source/ufoLib/glifLib.rst b/Doc/source/ufoLib/glifLib.rst
index 15bde5a..ffe4672 100644
--- a/Doc/source/ufoLib/glifLib.rst
+++ b/Doc/source/ufoLib/glifLib.rst
@@ -1,9 +1,9 @@
+.. highlight:: python
 
-#######
+=======
 glifLib
-#######
+=======
 
-.. automodule:: fontTools.ufoLib.glifLib
+.. automodule:: ufoLib.glifLib
    :inherited-members:
    :members:
-   :undoc-members:
diff --git a/Doc/source/ufoLib/index.rst b/Doc/source/ufoLib/index.rst
deleted file mode 100644
index 514c5c9..0000000
--- a/Doc/source/ufoLib/index.rst
+++ /dev/null
@@ -1,22 +0,0 @@
-
-######
-ufoLib
-######
-
-.. toctree::
-   :maxdepth: 1
-
-   converters
-   errors
-   filenames
-   glifLib
-   kerning
-   plistlib
-   pointpen
-   utils
-   validators
-
-.. automodule:: fontTools.ufoLib
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/ufoLib/kerning.rst b/Doc/source/ufoLib/kerning.rst
deleted file mode 100644
index 4d9d0c1..0000000
--- a/Doc/source/ufoLib/kerning.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-
-#######
-kerning
-#######
-
-.. automodule:: fontTools.ufoLib.kerning
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/ufoLib/plistlib.rst b/Doc/source/ufoLib/plistlib.rst
deleted file mode 100644
index d639947..0000000
--- a/Doc/source/ufoLib/plistlib.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-
-########
-plistlib
-########
-
-.. automodule:: fontTools.ufoLib.plistlib
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/ufoLib/pointPen.rst b/Doc/source/ufoLib/pointPen.rst
new file mode 100644
index 0000000..6cb1ca1
--- /dev/null
+++ b/Doc/source/ufoLib/pointPen.rst
@@ -0,0 +1,9 @@
+.. highlight:: python
+
+========
+pointPen
+========
+
+.. automodule:: ufoLib.pointPen
+   :inherited-members:
+   :members:
diff --git a/Doc/source/ufoLib/pointpen.rst b/Doc/source/ufoLib/pointpen.rst
deleted file mode 100644
index 5fb8c1c..0000000
--- a/Doc/source/ufoLib/pointpen.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-
-########
-pointPen
-########
-
-.. automodule:: fontTools.ufoLib.pointPen
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/ufoLib/ufoLib.rst b/Doc/source/ufoLib/ufoLib.rst
new file mode 100644
index 0000000..3b3b0b1
--- /dev/null
+++ b/Doc/source/ufoLib/ufoLib.rst
@@ -0,0 +1,9 @@
+.. highlight:: python
+
+======
+ufoLib
+======
+
+.. automodule:: ufoLib
+   :inherited-members:
+   :members:
diff --git a/Doc/source/ufoLib/utils.rst b/Doc/source/ufoLib/utils.rst
deleted file mode 100644
index d5ab143..0000000
--- a/Doc/source/ufoLib/utils.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-
-#####
-utils
-#####
-
-.. automodule:: fontTools.ufoLib.utils
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/ufoLib/validators.rst b/Doc/source/ufoLib/validators.rst
deleted file mode 100644
index 363d864..0000000
--- a/Doc/source/ufoLib/validators.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-
-##########
-validators
-##########
-
-.. automodule:: fontTools.ufoLib.validators
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/unicode.rst b/Doc/source/unicode.rst
deleted file mode 100644
index 65481d5..0000000
--- a/Doc/source/unicode.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-#######
-unicode
-#######
-
-.. automodule:: fontTools.unicode
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/unicodedata/Blocks.rst b/Doc/source/unicodedata/Blocks.rst
deleted file mode 100644
index 5d01da7..0000000
--- a/Doc/source/unicodedata/Blocks.rst
+++ /dev/null
@@ -1,13 +0,0 @@
-######
-Blocks
-######
-
-.. automodule:: fontTools.unicodedata.Blocks
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-.. data:: fontTools.unicodedata.Blocks.RANGES
-
-.. data:: fontTools.unicodedata.Blocks.VALUES
-
diff --git a/Doc/source/unicodedata/OTTags.rst b/Doc/source/unicodedata/OTTags.rst
deleted file mode 100644
index a436bdc..0000000
--- a/Doc/source/unicodedata/OTTags.rst
+++ /dev/null
@@ -1,17 +0,0 @@
-######
-OTTags
-######
-
-.. automodule:: fontTools.unicodedata.OTTags
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-.. data:: fontTools.unicodedata.OTTags.DEFAULT_SCRIPT
-
-.. data:: fontTools.unicodedata.OTTags.SCRIPT_EXCEPTIONS
-
-.. data:: fontTools.unicodedata.OTTags.NEW_SCRIPT_TAGS
-
-.. data:: fontTools.unicodedata.OTTags.NEW_SCRIPT_TAGS_REVERSED
-
diff --git a/Doc/source/unicodedata/ScriptExtensions.rst b/Doc/source/unicodedata/ScriptExtensions.rst
deleted file mode 100644
index dce2bbc..0000000
--- a/Doc/source/unicodedata/ScriptExtensions.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-################
-ScriptExtensions
-################
-
-.. automodule:: fontTools.unicodedata.ScriptExtensions
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-.. data:: fontTools.unicodedata.ScriptExtensions.RANGES
-
-.. data:: fontTools.unicodedata.ScriptExtensions.VALUES
diff --git a/Doc/source/unicodedata/Scripts.rst b/Doc/source/unicodedata/Scripts.rst
deleted file mode 100644
index 2ec6e34..0000000
--- a/Doc/source/unicodedata/Scripts.rst
+++ /dev/null
@@ -1,16 +0,0 @@
-#######
-Scripts
-#######
-
-.. automodule:: fontTools.unicodedata.Scripts
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-.. data:: fontTools.unicodedata.Scripts.NAMES
-
-.. data:: fontTools.unicodedata.Scripts.RANGES
-
-.. data:: fontTools.unicodedata.Scripts.VALUES
-
-
diff --git a/Doc/source/unicodedata/index.rst b/Doc/source/unicodedata/index.rst
deleted file mode 100644
index 811d65d..0000000
--- a/Doc/source/unicodedata/index.rst
+++ /dev/null
@@ -1,16 +0,0 @@
-###########
-unicodedata
-###########
-
-.. toctree::
-   :maxdepth: 1
-
-   Blocks
-   OTTags
-   ScriptExtensions
-   Scripts
-
-.. automodule:: fontTools.unicodedata
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/varLib/builder.rst b/Doc/source/varLib/builder.rst
deleted file mode 100644
index 3da3d32..0000000
--- a/Doc/source/varLib/builder.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-#######
-builder
-#######
-
-.. automodule:: fontTools.varLib.builder
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/varLib/cff.rst b/Doc/source/varLib/cff.rst
deleted file mode 100644
index 62e11c7..0000000
--- a/Doc/source/varLib/cff.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-cff
-###
-
-.. automodule:: fontTools.varLib.cff
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/varLib/designspace.rst b/Doc/source/varLib/designspace.rst
new file mode 100644
index 0000000..e3bbdf7
--- /dev/null
+++ b/Doc/source/varLib/designspace.rst
@@ -0,0 +1,7 @@
+###########
+designspace
+###########
+
+.. automodule:: fontTools.varLib.designspace
+   :members:
+   :undoc-members:
diff --git a/Doc/source/varLib/errors.rst b/Doc/source/varLib/errors.rst
deleted file mode 100644
index b761854..0000000
--- a/Doc/source/varLib/errors.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-######
-errors
-######
-
-.. automodule:: fontTools.varLib.errors
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/varLib/featureVars.rst b/Doc/source/varLib/featureVars.rst
deleted file mode 100644
index da73560..0000000
--- a/Doc/source/varLib/featureVars.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-###########
-featureVars
-###########
-
-.. automodule:: fontTools.varLib.featureVars
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/varLib/index.rst b/Doc/source/varLib/index.rst
index 7b22496..0e9f17b 100644
--- a/Doc/source/varLib/index.rst
+++ b/Doc/source/varLib/index.rst
@@ -1,114 +1,17 @@
-##################################
-varLib: OpenType Variation Support
-##################################
-
-The ``fontTools.varLib`` package contains a number of classes and routines
-for handling, building and interpolating variable font data. These routines
-rely on a common set of concepts, many of which are equivalent to concepts
-in the OpenType Specification, but some of which are unique to ``varLib``.
-
-Terminology
------------
-
-axis
-   "A designer-determined variable in a font face design that can be used to
-   derive multiple, variant designs within a family." (OpenType Specification)
-   An axis has a minimum value, a maximum value and a default value.
-
-designspace
-   The n-dimensional space formed by the font's axes. (OpenType Specification
-   calls this the "design-variation space")
-
-scalar
-   A value which is able to be varied at different points in the designspace:
-   for example, the horizontal advance width of the glyph "a" is a scalar.
-   However, see also *support scalar* below.
-
-default location
-   A point in the designspace whose coordinates are the default value of
-   all axes.
-
-location
-   A point in the designspace, specified as a set of coordinates on one or
-   more axes. In the context of ``varLib``, a location is a dictionary with
-   the keys being the axis tags and the values being the coordinates on the
-   respective axis. A ``varLib`` location dictionary may be "sparse", in the
-   sense that axes defined in the font may be omitted from the location's
-   coordinates, in which case the default value of the axis is assumed.
-   For example, given a font having a ``wght`` axis ranging from 200-1000
-   with default 400, and a ``wdth`` axis ranging 100-300 with default 150,
-   the location ``{"wdth": 200}`` represents the point ``wght=400,wdth=200``.
-
-master
-   The value of a scalar at a given location. **Note that this is a
-   considerably more general concept than the usual type design sense of
-   the term "master".**
-
-normalized location
-   While the range of an axis is determined by its minimum and maximum values
-   as set by the designer, locations are specified internally to the font binary
-   in the range -1 to 1, with 0 being the default, -1 being the minimum and
-   1 being the maximum. A normalized location is one which is scaled to the
-   range (-1,1) on all of its axes. Note that as the range from minimum to
-   default and from default to maximum on a given axis may differ (for
-   example, given ``wght min=200 default=500 max=1000``, the difference
-   between a normalized location -1 of a normalized location of 0 represents a
-   difference of 300 units while the difference between a normalized location
-   of 0 and a normalized location of 1 represents a difference of 700 units),
-   a location is scaled by a different factor depending on whether it is above
-   or below the axis' default value.
-
-support
-   While designers tend to think in terms of masters - that is, a precise
-   location having a particular value - OpenType Variations specifies the
-   variation of scalars in terms of deltas which are themselves composed of
-   the combined contributions of a set of triangular regions, each having
-   a contribution value of 0 at its minimum value, rising linearly to its
-   full contribution at the *peak* and falling linearly to zero from the
-   peak to the maximum value. The OpenType Specification calls these "regions",
-   while ``varLib`` calls them "supports" (a mathematical term used in real
-   analysis) and expresses them as a dictionary mapping each axis tag to a
-   tuple ``(min, peak, max)``.
-
-box
-   ``varLib`` uses the term "box" to denote the minimum and maximum "corners" of
-   a support, ignoring its peak value.
-
-delta
-   The term "delta" is used in OpenType Variations in two senses. In the
-   more general sense, a delta is the difference between a scalar at a
-   given location and its value at the default location. Additionally, inside
-   the font, variation data is stored as a mapping between supports and deltas.
-   The delta (in the first sense) is computed by summing the product of the
-   delta of each support by a factor representing the support's contribution
-   at this location (see "support scalar" below).
-
-support scalar
-   When interpolating a set of variation data, the support scalar represents
-   the scalar multiplier of the support's contribution at this location. For
-   example, the support scalar will be 1 at the support's peak location, and
-   0 below its minimum or above its maximum.
-
+######
+varLib
+######
 
 .. toctree::
    :maxdepth: 2
 
-   builder
-   cff
-   errors
-   featureVars
-   instancer
+   designspace
    interpolatable
    interpolate_layout
-   iup
    merger
    models
    mutator
-   mvar
-   plot
-   varStore
 
 .. automodule:: fontTools.varLib
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/varLib/instancer.rst b/Doc/source/varLib/instancer.rst
deleted file mode 100644
index 8776de3..0000000
--- a/Doc/source/varLib/instancer.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-#########
-instancer
-#########
-
-.. automodule:: fontTools.varLib.instancer
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/varLib/interpolatable.rst b/Doc/source/varLib/interpolatable.rst
index 1120a98..969fb61 100644
--- a/Doc/source/varLib/interpolatable.rst
+++ b/Doc/source/varLib/interpolatable.rst
@@ -3,6 +3,5 @@
 ##############
 
 .. automodule:: fontTools.varLib.interpolatable
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/varLib/interpolate_layout.rst b/Doc/source/varLib/interpolate_layout.rst
index a9655b5..752f748 100644
--- a/Doc/source/varLib/interpolate_layout.rst
+++ b/Doc/source/varLib/interpolate_layout.rst
@@ -3,6 +3,5 @@
 ##################
 
 .. automodule:: fontTools.varLib.interpolate_layout
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/varLib/iup.rst b/Doc/source/varLib/iup.rst
deleted file mode 100644
index b096788..0000000
--- a/Doc/source/varLib/iup.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-iup
-###
-
-.. automodule:: fontTools.varLib.iup
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/varLib/merger.rst b/Doc/source/varLib/merger.rst
index cf0a5a1..37383aa 100644
--- a/Doc/source/varLib/merger.rst
+++ b/Doc/source/varLib/merger.rst
@@ -3,6 +3,5 @@
 ######
 
 .. automodule:: fontTools.varLib.merger
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/varLib/models.rst b/Doc/source/varLib/models.rst
index f59f0b8..e6c7fa8 100644
--- a/Doc/source/varLib/models.rst
+++ b/Doc/source/varLib/models.rst
@@ -3,6 +3,5 @@
 ######
 
 .. automodule:: fontTools.varLib.models
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/varLib/mutator.rst b/Doc/source/varLib/mutator.rst
index fffa803..e606ab8 100644
--- a/Doc/source/varLib/mutator.rst
+++ b/Doc/source/varLib/mutator.rst
@@ -3,6 +3,5 @@
 #######
 
 .. automodule:: fontTools.varLib.mutator
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Doc/source/varLib/mvar.rst b/Doc/source/varLib/mvar.rst
deleted file mode 100644
index 8c59a31..0000000
--- a/Doc/source/varLib/mvar.rst
+++ /dev/null
@@ -1,10 +0,0 @@
-####
-mvar
-####
-
-.. automodule:: fontTools.varLib.mvar
-   :inherited-members:
-   :members:
-   :undoc-members:
-
-.. data:: fontTools.varLib.mvar.MVAR_ENTRIES
\ No newline at end of file
diff --git a/Doc/source/varLib/plot.rst b/Doc/source/varLib/plot.rst
deleted file mode 100644
index a722a2d..0000000
--- a/Doc/source/varLib/plot.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-####
-plot
-####
-
-.. automodule:: fontTools.varLib.plot
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/varLib/varStore.rst b/Doc/source/varLib/varStore.rst
deleted file mode 100644
index cc91101..0000000
--- a/Doc/source/varLib/varStore.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-########
-varStore
-########
-
-.. automodule:: fontTools.varLib.varStore
-   :inherited-members:
-   :members:
-   :undoc-members:
diff --git a/Doc/source/voltLib.rst b/Doc/source/voltLib.rst
index 7695db7..5906c4c 100644
--- a/Doc/source/voltLib.rst
+++ b/Doc/source/voltLib.rst
@@ -3,7 +3,6 @@
 #######
 
 .. automodule:: fontTools.voltLib
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -11,7 +10,6 @@
 ---
 
 .. automodule:: fontTools.voltLib.ast
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -19,7 +17,6 @@
 -----
 
 .. automodule:: fontTools.voltLib.parser
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -27,7 +24,6 @@
 -----
 
 .. automodule:: fontTools.voltLib.lexer
-   :inherited-members:
    :members:
    :undoc-members:
 
@@ -35,6 +31,5 @@
 ------
 
 .. automodule:: fontTools.voltLib.parser
-   :inherited-members:
    :members:
    :undoc-members:
diff --git a/Icons/FontToolsIconGreenCircle.pdf b/Icons/FontToolsIconGreenCircle.pdf
deleted file mode 100644
index f36817e..0000000
--- a/Icons/FontToolsIconGreenCircle.pdf
+++ /dev/null
Binary files differ
diff --git a/Icons/FontToolsIconGreenCircle.png b/Icons/FontToolsIconGreenCircle.png
deleted file mode 100644
index 47d5765..0000000
--- a/Icons/FontToolsIconGreenCircle.png
+++ /dev/null
Binary files differ
diff --git a/Icons/FontToolsIconGreenSquare.pdf b/Icons/FontToolsIconGreenSquare.pdf
deleted file mode 100644
index b95057f..0000000
--- a/Icons/FontToolsIconGreenSquare.pdf
+++ /dev/null
Binary files differ
diff --git a/Icons/FontToolsIconGreenSquare.png b/Icons/FontToolsIconGreenSquare.png
deleted file mode 100644
index a686561..0000000
--- a/Icons/FontToolsIconGreenSquare.png
+++ /dev/null
Binary files differ
diff --git a/Icons/FontToolsIconWhiteCircle.pdf b/Icons/FontToolsIconWhiteCircle.pdf
deleted file mode 100644
index c53b81c..0000000
--- a/Icons/FontToolsIconWhiteCircle.pdf
+++ /dev/null
Binary files differ
diff --git a/Icons/FontToolsIconWhiteCircle.png b/Icons/FontToolsIconWhiteCircle.png
deleted file mode 100644
index 33601a5..0000000
--- a/Icons/FontToolsIconWhiteCircle.png
+++ /dev/null
Binary files differ
diff --git a/Icons/FontToolsIconWhiteSquare.pdf b/Icons/FontToolsIconWhiteSquare.pdf
deleted file mode 100644
index 3692e3a..0000000
--- a/Icons/FontToolsIconWhiteSquare.pdf
+++ /dev/null
Binary files differ
diff --git a/Icons/FontToolsIconWhiteSquare.png b/Icons/FontToolsIconWhiteSquare.png
deleted file mode 100644
index 2a2d797..0000000
--- a/Icons/FontToolsIconWhiteSquare.png
+++ /dev/null
Binary files differ
diff --git a/LICENSE.external b/LICENSE.external
index 2bc4dab..4abc7d5 100644
--- a/LICENSE.external
+++ b/LICENSE.external
@@ -26,10 +26,6 @@
 
   This Font Software is licensed under the SIL Open Font License, Version 1.1.
 
-Iosevka
-  Copyright (c) 2015-2020 Belleve Invis (belleve@typeof.net).
-  This Font Software is licensed under the SIL Open Font License, Version 1.1.
-
 This license is copied below, and is also available with a FAQ at:
 http://scripts.sil.org/OFL
 
@@ -150,210 +146,3 @@
 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-=====
-
-FontTools includes cu2qu, which is Copyright 2016 Google Inc. All Rights Reserved.
-Licensed under the Apache License, Version 2.0, a copy of which is reproduced below:
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
diff --git a/Lib/fontTools/Android.bp b/Lib/fontTools/Android.bp
index b7f6139..34ca987 100644
--- a/Lib/fontTools/Android.bp
+++ b/Lib/fontTools/Android.bp
@@ -11,34 +11,17 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
-// *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS.  PLEASE
-//     CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE
-//     DEPENDING ON IT IN YOUR PROJECT. ***
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "external_fonttools_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    //   SPDX-license-identifier-BSD
-    //   SPDX-license-identifier-MIT
-    //   SPDX-license-identifier-OFL (by exception only)
-    //   SPDX-license-identifier-Unicode-DFS
-    //   legacy_unencumbered
-    default_applicable_licenses: ["external_fonttools_license"],
-}
-
 python_defaults {
     name: "fonttools_default",
     version: {
         py2: {
-            enabled: false,
-            embedded_launcher: false,
-        },
-        py3: {
             enabled: true,
             embedded_launcher: true,
         },
+        py3: {
+            enabled: false,
+            embedded_launcher: false,
+        },
     },
 }
 python_library_host {
diff --git a/Lib/fontTools/__init__.py b/Lib/fontTools/__init__.py
index 82da9b7..3d2f79c 100644
--- a/Lib/fontTools/__init__.py
+++ b/Lib/fontTools/__init__.py
@@ -1,8 +1,10 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 import logging
 from fontTools.misc.loggingTools import configLogger
 
 log = logging.getLogger(__name__)
 
-version = __version__ = "4.22.0"
+version = __version__ = "3.44.0"
 
 __all__ = ["version", "log", "configLogger"]
diff --git a/Lib/fontTools/__main__.py b/Lib/fontTools/__main__.py
index 9b978aa..7d45751 100644
--- a/Lib/fontTools/__main__.py
+++ b/Lib/fontTools/__main__.py
@@ -1,3 +1,4 @@
+from __future__ import print_function, division, absolute_import
 import sys
 
 
@@ -5,6 +6,8 @@
 	if args is None:
 		args = sys.argv[1:]
 
+	# TODO Add help output, --help, etc.
+
 	# TODO Handle library-wide options. Eg.:
 	# --unicodedata
 	# --verbose / other logging stuff
@@ -18,10 +21,6 @@
 	# can be added.  Should we just try importing the fonttools
 	# module first and try without if it fails?
 
-	if len(sys.argv) < 2:
-		sys.argv.append("help")
-	if sys.argv[1] == "-h" or sys.argv[1] == "--help":
-		sys.argv[1] = "help"
 	mod = 'fontTools.'+sys.argv[1]
 	sys.argv[1] = sys.argv[0] + ' ' + sys.argv[1]
 	del sys.argv[0]
diff --git a/Lib/fontTools/afmLib.py b/Lib/fontTools/afmLib.py
index 49d9951..db01d34 100644
--- a/Lib/fontTools/afmLib.py
+++ b/Lib/fontTools/afmLib.py
@@ -1,51 +1,11 @@
-"""Module for reading and writing AFM (Adobe Font Metrics) files.
+"""Module for reading and writing AFM files."""
 
-Note that this has been designed to read in AFM files generated by Fontographer
-and has not been tested on many other files. In particular, it does not
-implement the whole Adobe AFM specification [#f1]_ but, it should read most
-"common" AFM files.
+# XXX reads AFM's generated by Fog, not tested with much else.
+# It does not implement the full spec (Adobe Technote 5004, Adobe Font Metrics
+# File Format Specification). Still, it should read most "common" AFM files.
 
-Here is an example of using `afmLib` to read, modify and write an AFM file:
-
-	>>> from fontTools.afmLib import AFM
-	>>> f = AFM("Tests/afmLib/data/TestAFM.afm")
-	>>>
-	>>> # Accessing a pair gets you the kern value
-	>>> f[("V","A")]
-	-60
-	>>>
-	>>> # Accessing a glyph name gets you metrics
-	>>> f["A"]
-	(65, 668, (8, -25, 660, 666))
-	>>> # (charnum, width, bounding box)
-	>>>
-	>>> # Accessing an attribute gets you metadata
-	>>> f.FontName
-	'TestFont-Regular'
-	>>> f.FamilyName
-	'TestFont'
-	>>> f.Weight
-	'Regular'
-	>>> f.XHeight
-	500
-	>>> f.Ascender
-	750
-	>>>
-	>>> # Attributes and items can also be set
-	>>> f[("A","V")] = -150 # Tighten kerning
-	>>> f.FontName = "TestFont Squished"
-	>>>
-	>>> # And the font written out again (remove the # in front)
-	>>> #f.write("testfont-squished.afm")
-
-.. rubric:: Footnotes
-
-.. [#f1] `Adobe Technote 5004 <https://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5004.AFM_Spec.pdf>`_,
-   Adobe Font Metrics File Format Specification.
-
-"""
-
-
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 import re
 
 # every single line starts with a "word"
@@ -138,11 +98,6 @@
 			]
 
 	def __init__(self, path=None):
-		"""AFM file reader.
-
-		Instantiating an object with a path name will cause the file to be opened,
-		read, and parsed. Alternatively the path can be left unspecified, and a
-		file can be parsed later with the :meth:`read` method."""
 		self._attrs = {}
 		self._chars = {}
 		self._kerning = {}
@@ -153,7 +108,6 @@
 			self.read(path)
 
 	def read(self, path):
-		"""Opens, reads and parses a file."""
 		lines = readlines(path)
 		for line in lines:
 			if not line.strip():
@@ -236,7 +190,6 @@
 		self._composites[charname] = components
 
 	def write(self, path, sep='\r'):
-		"""Writes out an AFM font to the given path."""
 		import time
 		lines = [	"StartFontMetrics 2.0",
 				"Comment Generated by afmLib; at %s" % (
@@ -306,40 +259,24 @@
 		writelines(path, lines, sep)
 
 	def has_kernpair(self, pair):
-		"""Returns `True` if the given glyph pair (specified as a tuple) exists
-		in the kerning dictionary."""
 		return pair in self._kerning
 
 	def kernpairs(self):
-		"""Returns a list of all kern pairs in the kerning dictionary."""
 		return list(self._kerning.keys())
 
 	def has_char(self, char):
-		"""Returns `True` if the given glyph exists in the font."""
 		return char in self._chars
 
 	def chars(self):
-		"""Returns a list of all glyph names in the font."""
 		return list(self._chars.keys())
 
 	def comments(self):
-		"""Returns all comments from the file."""
 		return self._comments
 
 	def addComment(self, comment):
-		"""Adds a new comment to the file."""
 		self._comments.append(comment)
 
 	def addComposite(self, glyphName, components):
-		"""Specifies that the glyph `glyphName` is made up of the given components.
-		The components list should be of the following form::
-
-			[
-				(glyphname, xOffset, yOffset),
-				...
-			]
-		
-		"""
 		self._composites[glyphName] = components
 
 	def __getattr__(self, attr):
diff --git a/Lib/fontTools/agl.py b/Lib/fontTools/agl.py
index 4f7ff92..ec1a1b0 100644
--- a/Lib/fontTools/agl.py
+++ b/Lib/fontTools/agl.py
@@ -1,38 +1,17 @@
 # -*- coding: utf-8 -*-
-# The tables below are taken from
-# https://github.com/adobe-type-tools/agl-aglfn/raw/4036a9ca80a62f64f9de4f7321a9a045ad0ecfd6/glyphlist.txt
-# and
-# https://github.com/adobe-type-tools/agl-aglfn/raw/4036a9ca80a62f64f9de4f7321a9a045ad0ecfd6/aglfn.txt
-"""
-Interface to the Adobe Glyph List
+# The table below is taken from
+# http://www.adobe.com/devnet/opentype/archives/aglfn.txt
 
-This module exists to convert glyph names from the Adobe Glyph List
-to their Unicode equivalents. Example usage:
-
-	>>> from fontTools.agl import toUnicode
-	>>> toUnicode("nahiragana")
-	'な'
-
-It also contains two dictionaries, ``UV2AGL`` and ``AGL2UV``, which map from
-Unicode codepoints to AGL names and vice versa:
-
-	>>> import fontTools
-	>>> fontTools.agl.UV2AGL[ord("?")]
-	'question'
-	>>> fontTools.agl.AGL2UV["wcircumflex"]
-	373
-
-This is used by fontTools when it has to construct glyph names for a font which
-doesn't include any (e.g. format 3.0 post tables).
-"""
-
-from fontTools.misc.py23 import tostr
+from __future__ import (print_function, division, absolute_import,
+                        unicode_literals)
+from fontTools.misc.py23 import *
 import re
 
 
 _aglText = """\
 # -----------------------------------------------------------
-# Copyright 2002-2019 Adobe (http://www.adobe.com/).
+# Copyright 2003, 2005-2008, 2010 Adobe Systems Incorporated.
+# All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or
 # without modification, are permitted provided that the
@@ -47,4338 +26,10 @@
 # disclaimer in the documentation and/or other materials
 # provided with the distribution.
 #
-# Neither the name of Adobe nor the names of its contributors
-# may be used to endorse or promote products derived from this
-# software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
-# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
-# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
-# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# -----------------------------------------------------------
-# Name:          Adobe Glyph List
-# Table version: 2.0
-# Date:          September 20, 2002
-# URL:           https://github.com/adobe-type-tools/agl-aglfn
-#
-# Format: two semicolon-delimited fields:
-#   (1) glyph name--upper/lowercase letters and digits
-#   (2) Unicode scalar value--four uppercase hexadecimal digits
-#
-A;0041
-AE;00C6
-AEacute;01FC
-AEmacron;01E2
-AEsmall;F7E6
-Aacute;00C1
-Aacutesmall;F7E1
-Abreve;0102
-Abreveacute;1EAE
-Abrevecyrillic;04D0
-Abrevedotbelow;1EB6
-Abrevegrave;1EB0
-Abrevehookabove;1EB2
-Abrevetilde;1EB4
-Acaron;01CD
-Acircle;24B6
-Acircumflex;00C2
-Acircumflexacute;1EA4
-Acircumflexdotbelow;1EAC
-Acircumflexgrave;1EA6
-Acircumflexhookabove;1EA8
-Acircumflexsmall;F7E2
-Acircumflextilde;1EAA
-Acute;F6C9
-Acutesmall;F7B4
-Acyrillic;0410
-Adblgrave;0200
-Adieresis;00C4
-Adieresiscyrillic;04D2
-Adieresismacron;01DE
-Adieresissmall;F7E4
-Adotbelow;1EA0
-Adotmacron;01E0
-Agrave;00C0
-Agravesmall;F7E0
-Ahookabove;1EA2
-Aiecyrillic;04D4
-Ainvertedbreve;0202
-Alpha;0391
-Alphatonos;0386
-Amacron;0100
-Amonospace;FF21
-Aogonek;0104
-Aring;00C5
-Aringacute;01FA
-Aringbelow;1E00
-Aringsmall;F7E5
-Asmall;F761
-Atilde;00C3
-Atildesmall;F7E3
-Aybarmenian;0531
-B;0042
-Bcircle;24B7
-Bdotaccent;1E02
-Bdotbelow;1E04
-Becyrillic;0411
-Benarmenian;0532
-Beta;0392
-Bhook;0181
-Blinebelow;1E06
-Bmonospace;FF22
-Brevesmall;F6F4
-Bsmall;F762
-Btopbar;0182
-C;0043
-Caarmenian;053E
-Cacute;0106
-Caron;F6CA
-Caronsmall;F6F5
-Ccaron;010C
-Ccedilla;00C7
-Ccedillaacute;1E08
-Ccedillasmall;F7E7
-Ccircle;24B8
-Ccircumflex;0108
-Cdot;010A
-Cdotaccent;010A
-Cedillasmall;F7B8
-Chaarmenian;0549
-Cheabkhasiancyrillic;04BC
-Checyrillic;0427
-Chedescenderabkhasiancyrillic;04BE
-Chedescendercyrillic;04B6
-Chedieresiscyrillic;04F4
-Cheharmenian;0543
-Chekhakassiancyrillic;04CB
-Cheverticalstrokecyrillic;04B8
-Chi;03A7
-Chook;0187
-Circumflexsmall;F6F6
-Cmonospace;FF23
-Coarmenian;0551
-Csmall;F763
-D;0044
-DZ;01F1
-DZcaron;01C4
-Daarmenian;0534
-Dafrican;0189
-Dcaron;010E
-Dcedilla;1E10
-Dcircle;24B9
-Dcircumflexbelow;1E12
-Dcroat;0110
-Ddotaccent;1E0A
-Ddotbelow;1E0C
-Decyrillic;0414
-Deicoptic;03EE
-Delta;2206
-Deltagreek;0394
-Dhook;018A
-Dieresis;F6CB
-DieresisAcute;F6CC
-DieresisGrave;F6CD
-Dieresissmall;F7A8
-Digammagreek;03DC
-Djecyrillic;0402
-Dlinebelow;1E0E
-Dmonospace;FF24
-Dotaccentsmall;F6F7
-Dslash;0110
-Dsmall;F764
-Dtopbar;018B
-Dz;01F2
-Dzcaron;01C5
-Dzeabkhasiancyrillic;04E0
-Dzecyrillic;0405
-Dzhecyrillic;040F
-E;0045
-Eacute;00C9
-Eacutesmall;F7E9
-Ebreve;0114
-Ecaron;011A
-Ecedillabreve;1E1C
-Echarmenian;0535
-Ecircle;24BA
-Ecircumflex;00CA
-Ecircumflexacute;1EBE
-Ecircumflexbelow;1E18
-Ecircumflexdotbelow;1EC6
-Ecircumflexgrave;1EC0
-Ecircumflexhookabove;1EC2
-Ecircumflexsmall;F7EA
-Ecircumflextilde;1EC4
-Ecyrillic;0404
-Edblgrave;0204
-Edieresis;00CB
-Edieresissmall;F7EB
-Edot;0116
-Edotaccent;0116
-Edotbelow;1EB8
-Efcyrillic;0424
-Egrave;00C8
-Egravesmall;F7E8
-Eharmenian;0537
-Ehookabove;1EBA
-Eightroman;2167
-Einvertedbreve;0206
-Eiotifiedcyrillic;0464
-Elcyrillic;041B
-Elevenroman;216A
-Emacron;0112
-Emacronacute;1E16
-Emacrongrave;1E14
-Emcyrillic;041C
-Emonospace;FF25
-Encyrillic;041D
-Endescendercyrillic;04A2
-Eng;014A
-Enghecyrillic;04A4
-Enhookcyrillic;04C7
-Eogonek;0118
-Eopen;0190
-Epsilon;0395
-Epsilontonos;0388
-Ercyrillic;0420
-Ereversed;018E
-Ereversedcyrillic;042D
-Escyrillic;0421
-Esdescendercyrillic;04AA
-Esh;01A9
-Esmall;F765
-Eta;0397
-Etarmenian;0538
-Etatonos;0389
-Eth;00D0
-Ethsmall;F7F0
-Etilde;1EBC
-Etildebelow;1E1A
-Euro;20AC
-Ezh;01B7
-Ezhcaron;01EE
-Ezhreversed;01B8
-F;0046
-Fcircle;24BB
-Fdotaccent;1E1E
-Feharmenian;0556
-Feicoptic;03E4
-Fhook;0191
-Fitacyrillic;0472
-Fiveroman;2164
-Fmonospace;FF26
-Fourroman;2163
-Fsmall;F766
-G;0047
-GBsquare;3387
-Gacute;01F4
-Gamma;0393
-Gammaafrican;0194
-Gangiacoptic;03EA
-Gbreve;011E
-Gcaron;01E6
-Gcedilla;0122
-Gcircle;24BC
-Gcircumflex;011C
-Gcommaaccent;0122
-Gdot;0120
-Gdotaccent;0120
-Gecyrillic;0413
-Ghadarmenian;0542
-Ghemiddlehookcyrillic;0494
-Ghestrokecyrillic;0492
-Gheupturncyrillic;0490
-Ghook;0193
-Gimarmenian;0533
-Gjecyrillic;0403
-Gmacron;1E20
-Gmonospace;FF27
-Grave;F6CE
-Gravesmall;F760
-Gsmall;F767
-Gsmallhook;029B
-Gstroke;01E4
-H;0048
-H18533;25CF
-H18543;25AA
-H18551;25AB
-H22073;25A1
-HPsquare;33CB
-Haabkhasiancyrillic;04A8
-Hadescendercyrillic;04B2
-Hardsigncyrillic;042A
-Hbar;0126
-Hbrevebelow;1E2A
-Hcedilla;1E28
-Hcircle;24BD
-Hcircumflex;0124
-Hdieresis;1E26
-Hdotaccent;1E22
-Hdotbelow;1E24
-Hmonospace;FF28
-Hoarmenian;0540
-Horicoptic;03E8
-Hsmall;F768
-Hungarumlaut;F6CF
-Hungarumlautsmall;F6F8
-Hzsquare;3390
-I;0049
-IAcyrillic;042F
-IJ;0132
-IUcyrillic;042E
-Iacute;00CD
-Iacutesmall;F7ED
-Ibreve;012C
-Icaron;01CF
-Icircle;24BE
-Icircumflex;00CE
-Icircumflexsmall;F7EE
-Icyrillic;0406
-Idblgrave;0208
-Idieresis;00CF
-Idieresisacute;1E2E
-Idieresiscyrillic;04E4
-Idieresissmall;F7EF
-Idot;0130
-Idotaccent;0130
-Idotbelow;1ECA
-Iebrevecyrillic;04D6
-Iecyrillic;0415
-Ifraktur;2111
-Igrave;00CC
-Igravesmall;F7EC
-Ihookabove;1EC8
-Iicyrillic;0418
-Iinvertedbreve;020A
-Iishortcyrillic;0419
-Imacron;012A
-Imacroncyrillic;04E2
-Imonospace;FF29
-Iniarmenian;053B
-Iocyrillic;0401
-Iogonek;012E
-Iota;0399
-Iotaafrican;0196
-Iotadieresis;03AA
-Iotatonos;038A
-Ismall;F769
-Istroke;0197
-Itilde;0128
-Itildebelow;1E2C
-Izhitsacyrillic;0474
-Izhitsadblgravecyrillic;0476
-J;004A
-Jaarmenian;0541
-Jcircle;24BF
-Jcircumflex;0134
-Jecyrillic;0408
-Jheharmenian;054B
-Jmonospace;FF2A
-Jsmall;F76A
-K;004B
-KBsquare;3385
-KKsquare;33CD
-Kabashkircyrillic;04A0
-Kacute;1E30
-Kacyrillic;041A
-Kadescendercyrillic;049A
-Kahookcyrillic;04C3
-Kappa;039A
-Kastrokecyrillic;049E
-Kaverticalstrokecyrillic;049C
-Kcaron;01E8
-Kcedilla;0136
-Kcircle;24C0
-Kcommaaccent;0136
-Kdotbelow;1E32
-Keharmenian;0554
-Kenarmenian;053F
-Khacyrillic;0425
-Kheicoptic;03E6
-Khook;0198
-Kjecyrillic;040C
-Klinebelow;1E34
-Kmonospace;FF2B
-Koppacyrillic;0480
-Koppagreek;03DE
-Ksicyrillic;046E
-Ksmall;F76B
-L;004C
-LJ;01C7
-LL;F6BF
-Lacute;0139
-Lambda;039B
-Lcaron;013D
-Lcedilla;013B
-Lcircle;24C1
-Lcircumflexbelow;1E3C
-Lcommaaccent;013B
-Ldot;013F
-Ldotaccent;013F
-Ldotbelow;1E36
-Ldotbelowmacron;1E38
-Liwnarmenian;053C
-Lj;01C8
-Ljecyrillic;0409
-Llinebelow;1E3A
-Lmonospace;FF2C
-Lslash;0141
-Lslashsmall;F6F9
-Lsmall;F76C
-M;004D
-MBsquare;3386
-Macron;F6D0
-Macronsmall;F7AF
-Macute;1E3E
-Mcircle;24C2
-Mdotaccent;1E40
-Mdotbelow;1E42
-Menarmenian;0544
-Mmonospace;FF2D
-Msmall;F76D
-Mturned;019C
-Mu;039C
-N;004E
-NJ;01CA
-Nacute;0143
-Ncaron;0147
-Ncedilla;0145
-Ncircle;24C3
-Ncircumflexbelow;1E4A
-Ncommaaccent;0145
-Ndotaccent;1E44
-Ndotbelow;1E46
-Nhookleft;019D
-Nineroman;2168
-Nj;01CB
-Njecyrillic;040A
-Nlinebelow;1E48
-Nmonospace;FF2E
-Nowarmenian;0546
-Nsmall;F76E
-Ntilde;00D1
-Ntildesmall;F7F1
-Nu;039D
-O;004F
-OE;0152
-OEsmall;F6FA
-Oacute;00D3
-Oacutesmall;F7F3
-Obarredcyrillic;04E8
-Obarreddieresiscyrillic;04EA
-Obreve;014E
-Ocaron;01D1
-Ocenteredtilde;019F
-Ocircle;24C4
-Ocircumflex;00D4
-Ocircumflexacute;1ED0
-Ocircumflexdotbelow;1ED8
-Ocircumflexgrave;1ED2
-Ocircumflexhookabove;1ED4
-Ocircumflexsmall;F7F4
-Ocircumflextilde;1ED6
-Ocyrillic;041E
-Odblacute;0150
-Odblgrave;020C
-Odieresis;00D6
-Odieresiscyrillic;04E6
-Odieresissmall;F7F6
-Odotbelow;1ECC
-Ogoneksmall;F6FB
-Ograve;00D2
-Ogravesmall;F7F2
-Oharmenian;0555
-Ohm;2126
-Ohookabove;1ECE
-Ohorn;01A0
-Ohornacute;1EDA
-Ohorndotbelow;1EE2
-Ohorngrave;1EDC
-Ohornhookabove;1EDE
-Ohorntilde;1EE0
-Ohungarumlaut;0150
-Oi;01A2
-Oinvertedbreve;020E
-Omacron;014C
-Omacronacute;1E52
-Omacrongrave;1E50
-Omega;2126
-Omegacyrillic;0460
-Omegagreek;03A9
-Omegaroundcyrillic;047A
-Omegatitlocyrillic;047C
-Omegatonos;038F
-Omicron;039F
-Omicrontonos;038C
-Omonospace;FF2F
-Oneroman;2160
-Oogonek;01EA
-Oogonekmacron;01EC
-Oopen;0186
-Oslash;00D8
-Oslashacute;01FE
-Oslashsmall;F7F8
-Osmall;F76F
-Ostrokeacute;01FE
-Otcyrillic;047E
-Otilde;00D5
-Otildeacute;1E4C
-Otildedieresis;1E4E
-Otildesmall;F7F5
-P;0050
-Pacute;1E54
-Pcircle;24C5
-Pdotaccent;1E56
-Pecyrillic;041F
-Peharmenian;054A
-Pemiddlehookcyrillic;04A6
-Phi;03A6
-Phook;01A4
-Pi;03A0
-Piwrarmenian;0553
-Pmonospace;FF30
-Psi;03A8
-Psicyrillic;0470
-Psmall;F770
-Q;0051
-Qcircle;24C6
-Qmonospace;FF31
-Qsmall;F771
-R;0052
-Raarmenian;054C
-Racute;0154
-Rcaron;0158
-Rcedilla;0156
-Rcircle;24C7
-Rcommaaccent;0156
-Rdblgrave;0210
-Rdotaccent;1E58
-Rdotbelow;1E5A
-Rdotbelowmacron;1E5C
-Reharmenian;0550
-Rfraktur;211C
-Rho;03A1
-Ringsmall;F6FC
-Rinvertedbreve;0212
-Rlinebelow;1E5E
-Rmonospace;FF32
-Rsmall;F772
-Rsmallinverted;0281
-Rsmallinvertedsuperior;02B6
-S;0053
-SF010000;250C
-SF020000;2514
-SF030000;2510
-SF040000;2518
-SF050000;253C
-SF060000;252C
-SF070000;2534
-SF080000;251C
-SF090000;2524
-SF100000;2500
-SF110000;2502
-SF190000;2561
-SF200000;2562
-SF210000;2556
-SF220000;2555
-SF230000;2563
-SF240000;2551
-SF250000;2557
-SF260000;255D
-SF270000;255C
-SF280000;255B
-SF360000;255E
-SF370000;255F
-SF380000;255A
-SF390000;2554
-SF400000;2569
-SF410000;2566
-SF420000;2560
-SF430000;2550
-SF440000;256C
-SF450000;2567
-SF460000;2568
-SF470000;2564
-SF480000;2565
-SF490000;2559
-SF500000;2558
-SF510000;2552
-SF520000;2553
-SF530000;256B
-SF540000;256A
-Sacute;015A
-Sacutedotaccent;1E64
-Sampigreek;03E0
-Scaron;0160
-Scarondotaccent;1E66
-Scaronsmall;F6FD
-Scedilla;015E
-Schwa;018F
-Schwacyrillic;04D8
-Schwadieresiscyrillic;04DA
-Scircle;24C8
-Scircumflex;015C
-Scommaaccent;0218
-Sdotaccent;1E60
-Sdotbelow;1E62
-Sdotbelowdotaccent;1E68
-Seharmenian;054D
-Sevenroman;2166
-Shaarmenian;0547
-Shacyrillic;0428
-Shchacyrillic;0429
-Sheicoptic;03E2
-Shhacyrillic;04BA
-Shimacoptic;03EC
-Sigma;03A3
-Sixroman;2165
-Smonospace;FF33
-Softsigncyrillic;042C
-Ssmall;F773
-Stigmagreek;03DA
-T;0054
-Tau;03A4
-Tbar;0166
-Tcaron;0164
-Tcedilla;0162
-Tcircle;24C9
-Tcircumflexbelow;1E70
-Tcommaaccent;0162
-Tdotaccent;1E6A
-Tdotbelow;1E6C
-Tecyrillic;0422
-Tedescendercyrillic;04AC
-Tenroman;2169
-Tetsecyrillic;04B4
-Theta;0398
-Thook;01AC
-Thorn;00DE
-Thornsmall;F7FE
-Threeroman;2162
-Tildesmall;F6FE
-Tiwnarmenian;054F
-Tlinebelow;1E6E
-Tmonospace;FF34
-Toarmenian;0539
-Tonefive;01BC
-Tonesix;0184
-Tonetwo;01A7
-Tretroflexhook;01AE
-Tsecyrillic;0426
-Tshecyrillic;040B
-Tsmall;F774
-Twelveroman;216B
-Tworoman;2161
-U;0055
-Uacute;00DA
-Uacutesmall;F7FA
-Ubreve;016C
-Ucaron;01D3
-Ucircle;24CA
-Ucircumflex;00DB
-Ucircumflexbelow;1E76
-Ucircumflexsmall;F7FB
-Ucyrillic;0423
-Udblacute;0170
-Udblgrave;0214
-Udieresis;00DC
-Udieresisacute;01D7
-Udieresisbelow;1E72
-Udieresiscaron;01D9
-Udieresiscyrillic;04F0
-Udieresisgrave;01DB
-Udieresismacron;01D5
-Udieresissmall;F7FC
-Udotbelow;1EE4
-Ugrave;00D9
-Ugravesmall;F7F9
-Uhookabove;1EE6
-Uhorn;01AF
-Uhornacute;1EE8
-Uhorndotbelow;1EF0
-Uhorngrave;1EEA
-Uhornhookabove;1EEC
-Uhorntilde;1EEE
-Uhungarumlaut;0170
-Uhungarumlautcyrillic;04F2
-Uinvertedbreve;0216
-Ukcyrillic;0478
-Umacron;016A
-Umacroncyrillic;04EE
-Umacrondieresis;1E7A
-Umonospace;FF35
-Uogonek;0172
-Upsilon;03A5
-Upsilon1;03D2
-Upsilonacutehooksymbolgreek;03D3
-Upsilonafrican;01B1
-Upsilondieresis;03AB
-Upsilondieresishooksymbolgreek;03D4
-Upsilonhooksymbol;03D2
-Upsilontonos;038E
-Uring;016E
-Ushortcyrillic;040E
-Usmall;F775
-Ustraightcyrillic;04AE
-Ustraightstrokecyrillic;04B0
-Utilde;0168
-Utildeacute;1E78
-Utildebelow;1E74
-V;0056
-Vcircle;24CB
-Vdotbelow;1E7E
-Vecyrillic;0412
-Vewarmenian;054E
-Vhook;01B2
-Vmonospace;FF36
-Voarmenian;0548
-Vsmall;F776
-Vtilde;1E7C
-W;0057
-Wacute;1E82
-Wcircle;24CC
-Wcircumflex;0174
-Wdieresis;1E84
-Wdotaccent;1E86
-Wdotbelow;1E88
-Wgrave;1E80
-Wmonospace;FF37
-Wsmall;F777
-X;0058
-Xcircle;24CD
-Xdieresis;1E8C
-Xdotaccent;1E8A
-Xeharmenian;053D
-Xi;039E
-Xmonospace;FF38
-Xsmall;F778
-Y;0059
-Yacute;00DD
-Yacutesmall;F7FD
-Yatcyrillic;0462
-Ycircle;24CE
-Ycircumflex;0176
-Ydieresis;0178
-Ydieresissmall;F7FF
-Ydotaccent;1E8E
-Ydotbelow;1EF4
-Yericyrillic;042B
-Yerudieresiscyrillic;04F8
-Ygrave;1EF2
-Yhook;01B3
-Yhookabove;1EF6
-Yiarmenian;0545
-Yicyrillic;0407
-Yiwnarmenian;0552
-Ymonospace;FF39
-Ysmall;F779
-Ytilde;1EF8
-Yusbigcyrillic;046A
-Yusbigiotifiedcyrillic;046C
-Yuslittlecyrillic;0466
-Yuslittleiotifiedcyrillic;0468
-Z;005A
-Zaarmenian;0536
-Zacute;0179
-Zcaron;017D
-Zcaronsmall;F6FF
-Zcircle;24CF
-Zcircumflex;1E90
-Zdot;017B
-Zdotaccent;017B
-Zdotbelow;1E92
-Zecyrillic;0417
-Zedescendercyrillic;0498
-Zedieresiscyrillic;04DE
-Zeta;0396
-Zhearmenian;053A
-Zhebrevecyrillic;04C1
-Zhecyrillic;0416
-Zhedescendercyrillic;0496
-Zhedieresiscyrillic;04DC
-Zlinebelow;1E94
-Zmonospace;FF3A
-Zsmall;F77A
-Zstroke;01B5
-a;0061
-aabengali;0986
-aacute;00E1
-aadeva;0906
-aagujarati;0A86
-aagurmukhi;0A06
-aamatragurmukhi;0A3E
-aarusquare;3303
-aavowelsignbengali;09BE
-aavowelsigndeva;093E
-aavowelsigngujarati;0ABE
-abbreviationmarkarmenian;055F
-abbreviationsigndeva;0970
-abengali;0985
-abopomofo;311A
-abreve;0103
-abreveacute;1EAF
-abrevecyrillic;04D1
-abrevedotbelow;1EB7
-abrevegrave;1EB1
-abrevehookabove;1EB3
-abrevetilde;1EB5
-acaron;01CE
-acircle;24D0
-acircumflex;00E2
-acircumflexacute;1EA5
-acircumflexdotbelow;1EAD
-acircumflexgrave;1EA7
-acircumflexhookabove;1EA9
-acircumflextilde;1EAB
-acute;00B4
-acutebelowcmb;0317
-acutecmb;0301
-acutecomb;0301
-acutedeva;0954
-acutelowmod;02CF
-acutetonecmb;0341
-acyrillic;0430
-adblgrave;0201
-addakgurmukhi;0A71
-adeva;0905
-adieresis;00E4
-adieresiscyrillic;04D3
-adieresismacron;01DF
-adotbelow;1EA1
-adotmacron;01E1
-ae;00E6
-aeacute;01FD
-aekorean;3150
-aemacron;01E3
-afii00208;2015
-afii08941;20A4
-afii10017;0410
-afii10018;0411
-afii10019;0412
-afii10020;0413
-afii10021;0414
-afii10022;0415
-afii10023;0401
-afii10024;0416
-afii10025;0417
-afii10026;0418
-afii10027;0419
-afii10028;041A
-afii10029;041B
-afii10030;041C
-afii10031;041D
-afii10032;041E
-afii10033;041F
-afii10034;0420
-afii10035;0421
-afii10036;0422
-afii10037;0423
-afii10038;0424
-afii10039;0425
-afii10040;0426
-afii10041;0427
-afii10042;0428
-afii10043;0429
-afii10044;042A
-afii10045;042B
-afii10046;042C
-afii10047;042D
-afii10048;042E
-afii10049;042F
-afii10050;0490
-afii10051;0402
-afii10052;0403
-afii10053;0404
-afii10054;0405
-afii10055;0406
-afii10056;0407
-afii10057;0408
-afii10058;0409
-afii10059;040A
-afii10060;040B
-afii10061;040C
-afii10062;040E
-afii10063;F6C4
-afii10064;F6C5
-afii10065;0430
-afii10066;0431
-afii10067;0432
-afii10068;0433
-afii10069;0434
-afii10070;0435
-afii10071;0451
-afii10072;0436
-afii10073;0437
-afii10074;0438
-afii10075;0439
-afii10076;043A
-afii10077;043B
-afii10078;043C
-afii10079;043D
-afii10080;043E
-afii10081;043F
-afii10082;0440
-afii10083;0441
-afii10084;0442
-afii10085;0443
-afii10086;0444
-afii10087;0445
-afii10088;0446
-afii10089;0447
-afii10090;0448
-afii10091;0449
-afii10092;044A
-afii10093;044B
-afii10094;044C
-afii10095;044D
-afii10096;044E
-afii10097;044F
-afii10098;0491
-afii10099;0452
-afii10100;0453
-afii10101;0454
-afii10102;0455
-afii10103;0456
-afii10104;0457
-afii10105;0458
-afii10106;0459
-afii10107;045A
-afii10108;045B
-afii10109;045C
-afii10110;045E
-afii10145;040F
-afii10146;0462
-afii10147;0472
-afii10148;0474
-afii10192;F6C6
-afii10193;045F
-afii10194;0463
-afii10195;0473
-afii10196;0475
-afii10831;F6C7
-afii10832;F6C8
-afii10846;04D9
-afii299;200E
-afii300;200F
-afii301;200D
-afii57381;066A
-afii57388;060C
-afii57392;0660
-afii57393;0661
-afii57394;0662
-afii57395;0663
-afii57396;0664
-afii57397;0665
-afii57398;0666
-afii57399;0667
-afii57400;0668
-afii57401;0669
-afii57403;061B
-afii57407;061F
-afii57409;0621
-afii57410;0622
-afii57411;0623
-afii57412;0624
-afii57413;0625
-afii57414;0626
-afii57415;0627
-afii57416;0628
-afii57417;0629
-afii57418;062A
-afii57419;062B
-afii57420;062C
-afii57421;062D
-afii57422;062E
-afii57423;062F
-afii57424;0630
-afii57425;0631
-afii57426;0632
-afii57427;0633
-afii57428;0634
-afii57429;0635
-afii57430;0636
-afii57431;0637
-afii57432;0638
-afii57433;0639
-afii57434;063A
-afii57440;0640
-afii57441;0641
-afii57442;0642
-afii57443;0643
-afii57444;0644
-afii57445;0645
-afii57446;0646
-afii57448;0648
-afii57449;0649
-afii57450;064A
-afii57451;064B
-afii57452;064C
-afii57453;064D
-afii57454;064E
-afii57455;064F
-afii57456;0650
-afii57457;0651
-afii57458;0652
-afii57470;0647
-afii57505;06A4
-afii57506;067E
-afii57507;0686
-afii57508;0698
-afii57509;06AF
-afii57511;0679
-afii57512;0688
-afii57513;0691
-afii57514;06BA
-afii57519;06D2
-afii57534;06D5
-afii57636;20AA
-afii57645;05BE
-afii57658;05C3
-afii57664;05D0
-afii57665;05D1
-afii57666;05D2
-afii57667;05D3
-afii57668;05D4
-afii57669;05D5
-afii57670;05D6
-afii57671;05D7
-afii57672;05D8
-afii57673;05D9
-afii57674;05DA
-afii57675;05DB
-afii57676;05DC
-afii57677;05DD
-afii57678;05DE
-afii57679;05DF
-afii57680;05E0
-afii57681;05E1
-afii57682;05E2
-afii57683;05E3
-afii57684;05E4
-afii57685;05E5
-afii57686;05E6
-afii57687;05E7
-afii57688;05E8
-afii57689;05E9
-afii57690;05EA
-afii57694;FB2A
-afii57695;FB2B
-afii57700;FB4B
-afii57705;FB1F
-afii57716;05F0
-afii57717;05F1
-afii57718;05F2
-afii57723;FB35
-afii57793;05B4
-afii57794;05B5
-afii57795;05B6
-afii57796;05BB
-afii57797;05B8
-afii57798;05B7
-afii57799;05B0
-afii57800;05B2
-afii57801;05B1
-afii57802;05B3
-afii57803;05C2
-afii57804;05C1
-afii57806;05B9
-afii57807;05BC
-afii57839;05BD
-afii57841;05BF
-afii57842;05C0
-afii57929;02BC
-afii61248;2105
-afii61289;2113
-afii61352;2116
-afii61573;202C
-afii61574;202D
-afii61575;202E
-afii61664;200C
-afii63167;066D
-afii64937;02BD
-agrave;00E0
-agujarati;0A85
-agurmukhi;0A05
-ahiragana;3042
-ahookabove;1EA3
-aibengali;0990
-aibopomofo;311E
-aideva;0910
-aiecyrillic;04D5
-aigujarati;0A90
-aigurmukhi;0A10
-aimatragurmukhi;0A48
-ainarabic;0639
-ainfinalarabic;FECA
-aininitialarabic;FECB
-ainmedialarabic;FECC
-ainvertedbreve;0203
-aivowelsignbengali;09C8
-aivowelsigndeva;0948
-aivowelsigngujarati;0AC8
-akatakana;30A2
-akatakanahalfwidth;FF71
-akorean;314F
-alef;05D0
-alefarabic;0627
-alefdageshhebrew;FB30
-aleffinalarabic;FE8E
-alefhamzaabovearabic;0623
-alefhamzaabovefinalarabic;FE84
-alefhamzabelowarabic;0625
-alefhamzabelowfinalarabic;FE88
-alefhebrew;05D0
-aleflamedhebrew;FB4F
-alefmaddaabovearabic;0622
-alefmaddaabovefinalarabic;FE82
-alefmaksuraarabic;0649
-alefmaksurafinalarabic;FEF0
-alefmaksurainitialarabic;FEF3
-alefmaksuramedialarabic;FEF4
-alefpatahhebrew;FB2E
-alefqamatshebrew;FB2F
-aleph;2135
-allequal;224C
-alpha;03B1
-alphatonos;03AC
-amacron;0101
-amonospace;FF41
-ampersand;0026
-ampersandmonospace;FF06
-ampersandsmall;F726
-amsquare;33C2
-anbopomofo;3122
-angbopomofo;3124
-angkhankhuthai;0E5A
-angle;2220
-anglebracketleft;3008
-anglebracketleftvertical;FE3F
-anglebracketright;3009
-anglebracketrightvertical;FE40
-angleleft;2329
-angleright;232A
-angstrom;212B
-anoteleia;0387
-anudattadeva;0952
-anusvarabengali;0982
-anusvaradeva;0902
-anusvaragujarati;0A82
-aogonek;0105
-apaatosquare;3300
-aparen;249C
-apostrophearmenian;055A
-apostrophemod;02BC
-apple;F8FF
-approaches;2250
-approxequal;2248
-approxequalorimage;2252
-approximatelyequal;2245
-araeaekorean;318E
-araeakorean;318D
-arc;2312
-arighthalfring;1E9A
-aring;00E5
-aringacute;01FB
-aringbelow;1E01
-arrowboth;2194
-arrowdashdown;21E3
-arrowdashleft;21E0
-arrowdashright;21E2
-arrowdashup;21E1
-arrowdblboth;21D4
-arrowdbldown;21D3
-arrowdblleft;21D0
-arrowdblright;21D2
-arrowdblup;21D1
-arrowdown;2193
-arrowdownleft;2199
-arrowdownright;2198
-arrowdownwhite;21E9
-arrowheaddownmod;02C5
-arrowheadleftmod;02C2
-arrowheadrightmod;02C3
-arrowheadupmod;02C4
-arrowhorizex;F8E7
-arrowleft;2190
-arrowleftdbl;21D0
-arrowleftdblstroke;21CD
-arrowleftoverright;21C6
-arrowleftwhite;21E6
-arrowright;2192
-arrowrightdblstroke;21CF
-arrowrightheavy;279E
-arrowrightoverleft;21C4
-arrowrightwhite;21E8
-arrowtableft;21E4
-arrowtabright;21E5
-arrowup;2191
-arrowupdn;2195
-arrowupdnbse;21A8
-arrowupdownbase;21A8
-arrowupleft;2196
-arrowupleftofdown;21C5
-arrowupright;2197
-arrowupwhite;21E7
-arrowvertex;F8E6
-asciicircum;005E
-asciicircummonospace;FF3E
-asciitilde;007E
-asciitildemonospace;FF5E
-ascript;0251
-ascriptturned;0252
-asmallhiragana;3041
-asmallkatakana;30A1
-asmallkatakanahalfwidth;FF67
-asterisk;002A
-asteriskaltonearabic;066D
-asteriskarabic;066D
-asteriskmath;2217
-asteriskmonospace;FF0A
-asterisksmall;FE61
-asterism;2042
-asuperior;F6E9
-asymptoticallyequal;2243
-at;0040
-atilde;00E3
-atmonospace;FF20
-atsmall;FE6B
-aturned;0250
-aubengali;0994
-aubopomofo;3120
-audeva;0914
-augujarati;0A94
-augurmukhi;0A14
-aulengthmarkbengali;09D7
-aumatragurmukhi;0A4C
-auvowelsignbengali;09CC
-auvowelsigndeva;094C
-auvowelsigngujarati;0ACC
-avagrahadeva;093D
-aybarmenian;0561
-ayin;05E2
-ayinaltonehebrew;FB20
-ayinhebrew;05E2
-b;0062
-babengali;09AC
-backslash;005C
-backslashmonospace;FF3C
-badeva;092C
-bagujarati;0AAC
-bagurmukhi;0A2C
-bahiragana;3070
-bahtthai;0E3F
-bakatakana;30D0
-bar;007C
-barmonospace;FF5C
-bbopomofo;3105
-bcircle;24D1
-bdotaccent;1E03
-bdotbelow;1E05
-beamedsixteenthnotes;266C
-because;2235
-becyrillic;0431
-beharabic;0628
-behfinalarabic;FE90
-behinitialarabic;FE91
-behiragana;3079
-behmedialarabic;FE92
-behmeeminitialarabic;FC9F
-behmeemisolatedarabic;FC08
-behnoonfinalarabic;FC6D
-bekatakana;30D9
-benarmenian;0562
-bet;05D1
-beta;03B2
-betasymbolgreek;03D0
-betdagesh;FB31
-betdageshhebrew;FB31
-bethebrew;05D1
-betrafehebrew;FB4C
-bhabengali;09AD
-bhadeva;092D
-bhagujarati;0AAD
-bhagurmukhi;0A2D
-bhook;0253
-bihiragana;3073
-bikatakana;30D3
-bilabialclick;0298
-bindigurmukhi;0A02
-birusquare;3331
-blackcircle;25CF
-blackdiamond;25C6
-blackdownpointingtriangle;25BC
-blackleftpointingpointer;25C4
-blackleftpointingtriangle;25C0
-blacklenticularbracketleft;3010
-blacklenticularbracketleftvertical;FE3B
-blacklenticularbracketright;3011
-blacklenticularbracketrightvertical;FE3C
-blacklowerlefttriangle;25E3
-blacklowerrighttriangle;25E2
-blackrectangle;25AC
-blackrightpointingpointer;25BA
-blackrightpointingtriangle;25B6
-blacksmallsquare;25AA
-blacksmilingface;263B
-blacksquare;25A0
-blackstar;2605
-blackupperlefttriangle;25E4
-blackupperrighttriangle;25E5
-blackuppointingsmalltriangle;25B4
-blackuppointingtriangle;25B2
-blank;2423
-blinebelow;1E07
-block;2588
-bmonospace;FF42
-bobaimaithai;0E1A
-bohiragana;307C
-bokatakana;30DC
-bparen;249D
-bqsquare;33C3
-braceex;F8F4
-braceleft;007B
-braceleftbt;F8F3
-braceleftmid;F8F2
-braceleftmonospace;FF5B
-braceleftsmall;FE5B
-bracelefttp;F8F1
-braceleftvertical;FE37
-braceright;007D
-bracerightbt;F8FE
-bracerightmid;F8FD
-bracerightmonospace;FF5D
-bracerightsmall;FE5C
-bracerighttp;F8FC
-bracerightvertical;FE38
-bracketleft;005B
-bracketleftbt;F8F0
-bracketleftex;F8EF
-bracketleftmonospace;FF3B
-bracketlefttp;F8EE
-bracketright;005D
-bracketrightbt;F8FB
-bracketrightex;F8FA
-bracketrightmonospace;FF3D
-bracketrighttp;F8F9
-breve;02D8
-brevebelowcmb;032E
-brevecmb;0306
-breveinvertedbelowcmb;032F
-breveinvertedcmb;0311
-breveinverteddoublecmb;0361
-bridgebelowcmb;032A
-bridgeinvertedbelowcmb;033A
-brokenbar;00A6
-bstroke;0180
-bsuperior;F6EA
-btopbar;0183
-buhiragana;3076
-bukatakana;30D6
-bullet;2022
-bulletinverse;25D8
-bulletoperator;2219
-bullseye;25CE
-c;0063
-caarmenian;056E
-cabengali;099A
-cacute;0107
-cadeva;091A
-cagujarati;0A9A
-cagurmukhi;0A1A
-calsquare;3388
-candrabindubengali;0981
-candrabinducmb;0310
-candrabindudeva;0901
-candrabindugujarati;0A81
-capslock;21EA
-careof;2105
-caron;02C7
-caronbelowcmb;032C
-caroncmb;030C
-carriagereturn;21B5
-cbopomofo;3118
-ccaron;010D
-ccedilla;00E7
-ccedillaacute;1E09
-ccircle;24D2
-ccircumflex;0109
-ccurl;0255
-cdot;010B
-cdotaccent;010B
-cdsquare;33C5
-cedilla;00B8
-cedillacmb;0327
-cent;00A2
-centigrade;2103
-centinferior;F6DF
-centmonospace;FFE0
-centoldstyle;F7A2
-centsuperior;F6E0
-chaarmenian;0579
-chabengali;099B
-chadeva;091B
-chagujarati;0A9B
-chagurmukhi;0A1B
-chbopomofo;3114
-cheabkhasiancyrillic;04BD
-checkmark;2713
-checyrillic;0447
-chedescenderabkhasiancyrillic;04BF
-chedescendercyrillic;04B7
-chedieresiscyrillic;04F5
-cheharmenian;0573
-chekhakassiancyrillic;04CC
-cheverticalstrokecyrillic;04B9
-chi;03C7
-chieuchacirclekorean;3277
-chieuchaparenkorean;3217
-chieuchcirclekorean;3269
-chieuchkorean;314A
-chieuchparenkorean;3209
-chochangthai;0E0A
-chochanthai;0E08
-chochingthai;0E09
-chochoethai;0E0C
-chook;0188
-cieucacirclekorean;3276
-cieucaparenkorean;3216
-cieuccirclekorean;3268
-cieuckorean;3148
-cieucparenkorean;3208
-cieucuparenkorean;321C
-circle;25CB
-circlemultiply;2297
-circleot;2299
-circleplus;2295
-circlepostalmark;3036
-circlewithlefthalfblack;25D0
-circlewithrighthalfblack;25D1
-circumflex;02C6
-circumflexbelowcmb;032D
-circumflexcmb;0302
-clear;2327
-clickalveolar;01C2
-clickdental;01C0
-clicklateral;01C1
-clickretroflex;01C3
-club;2663
-clubsuitblack;2663
-clubsuitwhite;2667
-cmcubedsquare;33A4
-cmonospace;FF43
-cmsquaredsquare;33A0
-coarmenian;0581
-colon;003A
-colonmonetary;20A1
-colonmonospace;FF1A
-colonsign;20A1
-colonsmall;FE55
-colontriangularhalfmod;02D1
-colontriangularmod;02D0
-comma;002C
-commaabovecmb;0313
-commaaboverightcmb;0315
-commaaccent;F6C3
-commaarabic;060C
-commaarmenian;055D
-commainferior;F6E1
-commamonospace;FF0C
-commareversedabovecmb;0314
-commareversedmod;02BD
-commasmall;FE50
-commasuperior;F6E2
-commaturnedabovecmb;0312
-commaturnedmod;02BB
-compass;263C
-congruent;2245
-contourintegral;222E
-control;2303
-controlACK;0006
-controlBEL;0007
-controlBS;0008
-controlCAN;0018
-controlCR;000D
-controlDC1;0011
-controlDC2;0012
-controlDC3;0013
-controlDC4;0014
-controlDEL;007F
-controlDLE;0010
-controlEM;0019
-controlENQ;0005
-controlEOT;0004
-controlESC;001B
-controlETB;0017
-controlETX;0003
-controlFF;000C
-controlFS;001C
-controlGS;001D
-controlHT;0009
-controlLF;000A
-controlNAK;0015
-controlRS;001E
-controlSI;000F
-controlSO;000E
-controlSOT;0002
-controlSTX;0001
-controlSUB;001A
-controlSYN;0016
-controlUS;001F
-controlVT;000B
-copyright;00A9
-copyrightsans;F8E9
-copyrightserif;F6D9
-cornerbracketleft;300C
-cornerbracketlefthalfwidth;FF62
-cornerbracketleftvertical;FE41
-cornerbracketright;300D
-cornerbracketrighthalfwidth;FF63
-cornerbracketrightvertical;FE42
-corporationsquare;337F
-cosquare;33C7
-coverkgsquare;33C6
-cparen;249E
-cruzeiro;20A2
-cstretched;0297
-curlyand;22CF
-curlyor;22CE
-currency;00A4
-cyrBreve;F6D1
-cyrFlex;F6D2
-cyrbreve;F6D4
-cyrflex;F6D5
-d;0064
-daarmenian;0564
-dabengali;09A6
-dadarabic;0636
-dadeva;0926
-dadfinalarabic;FEBE
-dadinitialarabic;FEBF
-dadmedialarabic;FEC0
-dagesh;05BC
-dageshhebrew;05BC
-dagger;2020
-daggerdbl;2021
-dagujarati;0AA6
-dagurmukhi;0A26
-dahiragana;3060
-dakatakana;30C0
-dalarabic;062F
-dalet;05D3
-daletdagesh;FB33
-daletdageshhebrew;FB33
-dalethatafpatah;05D3 05B2
-dalethatafpatahhebrew;05D3 05B2
-dalethatafsegol;05D3 05B1
-dalethatafsegolhebrew;05D3 05B1
-dalethebrew;05D3
-dalethiriq;05D3 05B4
-dalethiriqhebrew;05D3 05B4
-daletholam;05D3 05B9
-daletholamhebrew;05D3 05B9
-daletpatah;05D3 05B7
-daletpatahhebrew;05D3 05B7
-daletqamats;05D3 05B8
-daletqamatshebrew;05D3 05B8
-daletqubuts;05D3 05BB
-daletqubutshebrew;05D3 05BB
-daletsegol;05D3 05B6
-daletsegolhebrew;05D3 05B6
-daletsheva;05D3 05B0
-daletshevahebrew;05D3 05B0
-dalettsere;05D3 05B5
-dalettserehebrew;05D3 05B5
-dalfinalarabic;FEAA
-dammaarabic;064F
-dammalowarabic;064F
-dammatanaltonearabic;064C
-dammatanarabic;064C
-danda;0964
-dargahebrew;05A7
-dargalefthebrew;05A7
-dasiapneumatacyrilliccmb;0485
-dblGrave;F6D3
-dblanglebracketleft;300A
-dblanglebracketleftvertical;FE3D
-dblanglebracketright;300B
-dblanglebracketrightvertical;FE3E
-dblarchinvertedbelowcmb;032B
-dblarrowleft;21D4
-dblarrowright;21D2
-dbldanda;0965
-dblgrave;F6D6
-dblgravecmb;030F
-dblintegral;222C
-dbllowline;2017
-dbllowlinecmb;0333
-dbloverlinecmb;033F
-dblprimemod;02BA
-dblverticalbar;2016
-dblverticallineabovecmb;030E
-dbopomofo;3109
-dbsquare;33C8
-dcaron;010F
-dcedilla;1E11
-dcircle;24D3
-dcircumflexbelow;1E13
-dcroat;0111
-ddabengali;09A1
-ddadeva;0921
-ddagujarati;0AA1
-ddagurmukhi;0A21
-ddalarabic;0688
-ddalfinalarabic;FB89
-dddhadeva;095C
-ddhabengali;09A2
-ddhadeva;0922
-ddhagujarati;0AA2
-ddhagurmukhi;0A22
-ddotaccent;1E0B
-ddotbelow;1E0D
-decimalseparatorarabic;066B
-decimalseparatorpersian;066B
-decyrillic;0434
-degree;00B0
-dehihebrew;05AD
-dehiragana;3067
-deicoptic;03EF
-dekatakana;30C7
-deleteleft;232B
-deleteright;2326
-delta;03B4
-deltaturned;018D
-denominatorminusonenumeratorbengali;09F8
-dezh;02A4
-dhabengali;09A7
-dhadeva;0927
-dhagujarati;0AA7
-dhagurmukhi;0A27
-dhook;0257
-dialytikatonos;0385
-dialytikatonoscmb;0344
-diamond;2666
-diamondsuitwhite;2662
-dieresis;00A8
-dieresisacute;F6D7
-dieresisbelowcmb;0324
-dieresiscmb;0308
-dieresisgrave;F6D8
-dieresistonos;0385
-dihiragana;3062
-dikatakana;30C2
-dittomark;3003
-divide;00F7
-divides;2223
-divisionslash;2215
-djecyrillic;0452
-dkshade;2593
-dlinebelow;1E0F
-dlsquare;3397
-dmacron;0111
-dmonospace;FF44
-dnblock;2584
-dochadathai;0E0E
-dodekthai;0E14
-dohiragana;3069
-dokatakana;30C9
-dollar;0024
-dollarinferior;F6E3
-dollarmonospace;FF04
-dollaroldstyle;F724
-dollarsmall;FE69
-dollarsuperior;F6E4
-dong;20AB
-dorusquare;3326
-dotaccent;02D9
-dotaccentcmb;0307
-dotbelowcmb;0323
-dotbelowcomb;0323
-dotkatakana;30FB
-dotlessi;0131
-dotlessj;F6BE
-dotlessjstrokehook;0284
-dotmath;22C5
-dottedcircle;25CC
-doubleyodpatah;FB1F
-doubleyodpatahhebrew;FB1F
-downtackbelowcmb;031E
-downtackmod;02D5
-dparen;249F
-dsuperior;F6EB
-dtail;0256
-dtopbar;018C
-duhiragana;3065
-dukatakana;30C5
-dz;01F3
-dzaltone;02A3
-dzcaron;01C6
-dzcurl;02A5
-dzeabkhasiancyrillic;04E1
-dzecyrillic;0455
-dzhecyrillic;045F
-e;0065
-eacute;00E9
-earth;2641
-ebengali;098F
-ebopomofo;311C
-ebreve;0115
-ecandradeva;090D
-ecandragujarati;0A8D
-ecandravowelsigndeva;0945
-ecandravowelsigngujarati;0AC5
-ecaron;011B
-ecedillabreve;1E1D
-echarmenian;0565
-echyiwnarmenian;0587
-ecircle;24D4
-ecircumflex;00EA
-ecircumflexacute;1EBF
-ecircumflexbelow;1E19
-ecircumflexdotbelow;1EC7
-ecircumflexgrave;1EC1
-ecircumflexhookabove;1EC3
-ecircumflextilde;1EC5
-ecyrillic;0454
-edblgrave;0205
-edeva;090F
-edieresis;00EB
-edot;0117
-edotaccent;0117
-edotbelow;1EB9
-eegurmukhi;0A0F
-eematragurmukhi;0A47
-efcyrillic;0444
-egrave;00E8
-egujarati;0A8F
-eharmenian;0567
-ehbopomofo;311D
-ehiragana;3048
-ehookabove;1EBB
-eibopomofo;311F
-eight;0038
-eightarabic;0668
-eightbengali;09EE
-eightcircle;2467
-eightcircleinversesansserif;2791
-eightdeva;096E
-eighteencircle;2471
-eighteenparen;2485
-eighteenperiod;2499
-eightgujarati;0AEE
-eightgurmukhi;0A6E
-eighthackarabic;0668
-eighthangzhou;3028
-eighthnotebeamed;266B
-eightideographicparen;3227
-eightinferior;2088
-eightmonospace;FF18
-eightoldstyle;F738
-eightparen;247B
-eightperiod;248F
-eightpersian;06F8
-eightroman;2177
-eightsuperior;2078
-eightthai;0E58
-einvertedbreve;0207
-eiotifiedcyrillic;0465
-ekatakana;30A8
-ekatakanahalfwidth;FF74
-ekonkargurmukhi;0A74
-ekorean;3154
-elcyrillic;043B
-element;2208
-elevencircle;246A
-elevenparen;247E
-elevenperiod;2492
-elevenroman;217A
-ellipsis;2026
-ellipsisvertical;22EE
-emacron;0113
-emacronacute;1E17
-emacrongrave;1E15
-emcyrillic;043C
-emdash;2014
-emdashvertical;FE31
-emonospace;FF45
-emphasismarkarmenian;055B
-emptyset;2205
-enbopomofo;3123
-encyrillic;043D
-endash;2013
-endashvertical;FE32
-endescendercyrillic;04A3
-eng;014B
-engbopomofo;3125
-enghecyrillic;04A5
-enhookcyrillic;04C8
-enspace;2002
-eogonek;0119
-eokorean;3153
-eopen;025B
-eopenclosed;029A
-eopenreversed;025C
-eopenreversedclosed;025E
-eopenreversedhook;025D
-eparen;24A0
-epsilon;03B5
-epsilontonos;03AD
-equal;003D
-equalmonospace;FF1D
-equalsmall;FE66
-equalsuperior;207C
-equivalence;2261
-erbopomofo;3126
-ercyrillic;0440
-ereversed;0258
-ereversedcyrillic;044D
-escyrillic;0441
-esdescendercyrillic;04AB
-esh;0283
-eshcurl;0286
-eshortdeva;090E
-eshortvowelsigndeva;0946
-eshreversedloop;01AA
-eshsquatreversed;0285
-esmallhiragana;3047
-esmallkatakana;30A7
-esmallkatakanahalfwidth;FF6A
-estimated;212E
-esuperior;F6EC
-eta;03B7
-etarmenian;0568
-etatonos;03AE
-eth;00F0
-etilde;1EBD
-etildebelow;1E1B
-etnahtafoukhhebrew;0591
-etnahtafoukhlefthebrew;0591
-etnahtahebrew;0591
-etnahtalefthebrew;0591
-eturned;01DD
-eukorean;3161
-euro;20AC
-evowelsignbengali;09C7
-evowelsigndeva;0947
-evowelsigngujarati;0AC7
-exclam;0021
-exclamarmenian;055C
-exclamdbl;203C
-exclamdown;00A1
-exclamdownsmall;F7A1
-exclammonospace;FF01
-exclamsmall;F721
-existential;2203
-ezh;0292
-ezhcaron;01EF
-ezhcurl;0293
-ezhreversed;01B9
-ezhtail;01BA
-f;0066
-fadeva;095E
-fagurmukhi;0A5E
-fahrenheit;2109
-fathaarabic;064E
-fathalowarabic;064E
-fathatanarabic;064B
-fbopomofo;3108
-fcircle;24D5
-fdotaccent;1E1F
-feharabic;0641
-feharmenian;0586
-fehfinalarabic;FED2
-fehinitialarabic;FED3
-fehmedialarabic;FED4
-feicoptic;03E5
-female;2640
-ff;FB00
-ffi;FB03
-ffl;FB04
-fi;FB01
-fifteencircle;246E
-fifteenparen;2482
-fifteenperiod;2496
-figuredash;2012
-filledbox;25A0
-filledrect;25AC
-finalkaf;05DA
-finalkafdagesh;FB3A
-finalkafdageshhebrew;FB3A
-finalkafhebrew;05DA
-finalkafqamats;05DA 05B8
-finalkafqamatshebrew;05DA 05B8
-finalkafsheva;05DA 05B0
-finalkafshevahebrew;05DA 05B0
-finalmem;05DD
-finalmemhebrew;05DD
-finalnun;05DF
-finalnunhebrew;05DF
-finalpe;05E3
-finalpehebrew;05E3
-finaltsadi;05E5
-finaltsadihebrew;05E5
-firsttonechinese;02C9
-fisheye;25C9
-fitacyrillic;0473
-five;0035
-fivearabic;0665
-fivebengali;09EB
-fivecircle;2464
-fivecircleinversesansserif;278E
-fivedeva;096B
-fiveeighths;215D
-fivegujarati;0AEB
-fivegurmukhi;0A6B
-fivehackarabic;0665
-fivehangzhou;3025
-fiveideographicparen;3224
-fiveinferior;2085
-fivemonospace;FF15
-fiveoldstyle;F735
-fiveparen;2478
-fiveperiod;248C
-fivepersian;06F5
-fiveroman;2174
-fivesuperior;2075
-fivethai;0E55
-fl;FB02
-florin;0192
-fmonospace;FF46
-fmsquare;3399
-fofanthai;0E1F
-fofathai;0E1D
-fongmanthai;0E4F
-forall;2200
-four;0034
-fourarabic;0664
-fourbengali;09EA
-fourcircle;2463
-fourcircleinversesansserif;278D
-fourdeva;096A
-fourgujarati;0AEA
-fourgurmukhi;0A6A
-fourhackarabic;0664
-fourhangzhou;3024
-fourideographicparen;3223
-fourinferior;2084
-fourmonospace;FF14
-fournumeratorbengali;09F7
-fouroldstyle;F734
-fourparen;2477
-fourperiod;248B
-fourpersian;06F4
-fourroman;2173
-foursuperior;2074
-fourteencircle;246D
-fourteenparen;2481
-fourteenperiod;2495
-fourthai;0E54
-fourthtonechinese;02CB
-fparen;24A1
-fraction;2044
-franc;20A3
-g;0067
-gabengali;0997
-gacute;01F5
-gadeva;0917
-gafarabic;06AF
-gaffinalarabic;FB93
-gafinitialarabic;FB94
-gafmedialarabic;FB95
-gagujarati;0A97
-gagurmukhi;0A17
-gahiragana;304C
-gakatakana;30AC
-gamma;03B3
-gammalatinsmall;0263
-gammasuperior;02E0
-gangiacoptic;03EB
-gbopomofo;310D
-gbreve;011F
-gcaron;01E7
-gcedilla;0123
-gcircle;24D6
-gcircumflex;011D
-gcommaaccent;0123
-gdot;0121
-gdotaccent;0121
-gecyrillic;0433
-gehiragana;3052
-gekatakana;30B2
-geometricallyequal;2251
-gereshaccenthebrew;059C
-gereshhebrew;05F3
-gereshmuqdamhebrew;059D
-germandbls;00DF
-gershayimaccenthebrew;059E
-gershayimhebrew;05F4
-getamark;3013
-ghabengali;0998
-ghadarmenian;0572
-ghadeva;0918
-ghagujarati;0A98
-ghagurmukhi;0A18
-ghainarabic;063A
-ghainfinalarabic;FECE
-ghaininitialarabic;FECF
-ghainmedialarabic;FED0
-ghemiddlehookcyrillic;0495
-ghestrokecyrillic;0493
-gheupturncyrillic;0491
-ghhadeva;095A
-ghhagurmukhi;0A5A
-ghook;0260
-ghzsquare;3393
-gihiragana;304E
-gikatakana;30AE
-gimarmenian;0563
-gimel;05D2
-gimeldagesh;FB32
-gimeldageshhebrew;FB32
-gimelhebrew;05D2
-gjecyrillic;0453
-glottalinvertedstroke;01BE
-glottalstop;0294
-glottalstopinverted;0296
-glottalstopmod;02C0
-glottalstopreversed;0295
-glottalstopreversedmod;02C1
-glottalstopreversedsuperior;02E4
-glottalstopstroke;02A1
-glottalstopstrokereversed;02A2
-gmacron;1E21
-gmonospace;FF47
-gohiragana;3054
-gokatakana;30B4
-gparen;24A2
-gpasquare;33AC
-gradient;2207
-grave;0060
-gravebelowcmb;0316
-gravecmb;0300
-gravecomb;0300
-gravedeva;0953
-gravelowmod;02CE
-gravemonospace;FF40
-gravetonecmb;0340
-greater;003E
-greaterequal;2265
-greaterequalorless;22DB
-greatermonospace;FF1E
-greaterorequivalent;2273
-greaterorless;2277
-greateroverequal;2267
-greatersmall;FE65
-gscript;0261
-gstroke;01E5
-guhiragana;3050
-guillemotleft;00AB
-guillemotright;00BB
-guilsinglleft;2039
-guilsinglright;203A
-gukatakana;30B0
-guramusquare;3318
-gysquare;33C9
-h;0068
-haabkhasiancyrillic;04A9
-haaltonearabic;06C1
-habengali;09B9
-hadescendercyrillic;04B3
-hadeva;0939
-hagujarati;0AB9
-hagurmukhi;0A39
-haharabic;062D
-hahfinalarabic;FEA2
-hahinitialarabic;FEA3
-hahiragana;306F
-hahmedialarabic;FEA4
-haitusquare;332A
-hakatakana;30CF
-hakatakanahalfwidth;FF8A
-halantgurmukhi;0A4D
-hamzaarabic;0621
-hamzadammaarabic;0621 064F
-hamzadammatanarabic;0621 064C
-hamzafathaarabic;0621 064E
-hamzafathatanarabic;0621 064B
-hamzalowarabic;0621
-hamzalowkasraarabic;0621 0650
-hamzalowkasratanarabic;0621 064D
-hamzasukunarabic;0621 0652
-hangulfiller;3164
-hardsigncyrillic;044A
-harpoonleftbarbup;21BC
-harpoonrightbarbup;21C0
-hasquare;33CA
-hatafpatah;05B2
-hatafpatah16;05B2
-hatafpatah23;05B2
-hatafpatah2f;05B2
-hatafpatahhebrew;05B2
-hatafpatahnarrowhebrew;05B2
-hatafpatahquarterhebrew;05B2
-hatafpatahwidehebrew;05B2
-hatafqamats;05B3
-hatafqamats1b;05B3
-hatafqamats28;05B3
-hatafqamats34;05B3
-hatafqamatshebrew;05B3
-hatafqamatsnarrowhebrew;05B3
-hatafqamatsquarterhebrew;05B3
-hatafqamatswidehebrew;05B3
-hatafsegol;05B1
-hatafsegol17;05B1
-hatafsegol24;05B1
-hatafsegol30;05B1
-hatafsegolhebrew;05B1
-hatafsegolnarrowhebrew;05B1
-hatafsegolquarterhebrew;05B1
-hatafsegolwidehebrew;05B1
-hbar;0127
-hbopomofo;310F
-hbrevebelow;1E2B
-hcedilla;1E29
-hcircle;24D7
-hcircumflex;0125
-hdieresis;1E27
-hdotaccent;1E23
-hdotbelow;1E25
-he;05D4
-heart;2665
-heartsuitblack;2665
-heartsuitwhite;2661
-hedagesh;FB34
-hedageshhebrew;FB34
-hehaltonearabic;06C1
-heharabic;0647
-hehebrew;05D4
-hehfinalaltonearabic;FBA7
-hehfinalalttwoarabic;FEEA
-hehfinalarabic;FEEA
-hehhamzaabovefinalarabic;FBA5
-hehhamzaaboveisolatedarabic;FBA4
-hehinitialaltonearabic;FBA8
-hehinitialarabic;FEEB
-hehiragana;3078
-hehmedialaltonearabic;FBA9
-hehmedialarabic;FEEC
-heiseierasquare;337B
-hekatakana;30D8
-hekatakanahalfwidth;FF8D
-hekutaarusquare;3336
-henghook;0267
-herutusquare;3339
-het;05D7
-hethebrew;05D7
-hhook;0266
-hhooksuperior;02B1
-hieuhacirclekorean;327B
-hieuhaparenkorean;321B
-hieuhcirclekorean;326D
-hieuhkorean;314E
-hieuhparenkorean;320D
-hihiragana;3072
-hikatakana;30D2
-hikatakanahalfwidth;FF8B
-hiriq;05B4
-hiriq14;05B4
-hiriq21;05B4
-hiriq2d;05B4
-hiriqhebrew;05B4
-hiriqnarrowhebrew;05B4
-hiriqquarterhebrew;05B4
-hiriqwidehebrew;05B4
-hlinebelow;1E96
-hmonospace;FF48
-hoarmenian;0570
-hohipthai;0E2B
-hohiragana;307B
-hokatakana;30DB
-hokatakanahalfwidth;FF8E
-holam;05B9
-holam19;05B9
-holam26;05B9
-holam32;05B9
-holamhebrew;05B9
-holamnarrowhebrew;05B9
-holamquarterhebrew;05B9
-holamwidehebrew;05B9
-honokhukthai;0E2E
-hookabovecomb;0309
-hookcmb;0309
-hookpalatalizedbelowcmb;0321
-hookretroflexbelowcmb;0322
-hoonsquare;3342
-horicoptic;03E9
-horizontalbar;2015
-horncmb;031B
-hotsprings;2668
-house;2302
-hparen;24A3
-hsuperior;02B0
-hturned;0265
-huhiragana;3075
-huiitosquare;3333
-hukatakana;30D5
-hukatakanahalfwidth;FF8C
-hungarumlaut;02DD
-hungarumlautcmb;030B
-hv;0195
-hyphen;002D
-hypheninferior;F6E5
-hyphenmonospace;FF0D
-hyphensmall;FE63
-hyphensuperior;F6E6
-hyphentwo;2010
-i;0069
-iacute;00ED
-iacyrillic;044F
-ibengali;0987
-ibopomofo;3127
-ibreve;012D
-icaron;01D0
-icircle;24D8
-icircumflex;00EE
-icyrillic;0456
-idblgrave;0209
-ideographearthcircle;328F
-ideographfirecircle;328B
-ideographicallianceparen;323F
-ideographiccallparen;323A
-ideographiccentrecircle;32A5
-ideographicclose;3006
-ideographiccomma;3001
-ideographiccommaleft;FF64
-ideographiccongratulationparen;3237
-ideographiccorrectcircle;32A3
-ideographicearthparen;322F
-ideographicenterpriseparen;323D
-ideographicexcellentcircle;329D
-ideographicfestivalparen;3240
-ideographicfinancialcircle;3296
-ideographicfinancialparen;3236
-ideographicfireparen;322B
-ideographichaveparen;3232
-ideographichighcircle;32A4
-ideographiciterationmark;3005
-ideographiclaborcircle;3298
-ideographiclaborparen;3238
-ideographicleftcircle;32A7
-ideographiclowcircle;32A6
-ideographicmedicinecircle;32A9
-ideographicmetalparen;322E
-ideographicmoonparen;322A
-ideographicnameparen;3234
-ideographicperiod;3002
-ideographicprintcircle;329E
-ideographicreachparen;3243
-ideographicrepresentparen;3239
-ideographicresourceparen;323E
-ideographicrightcircle;32A8
-ideographicsecretcircle;3299
-ideographicselfparen;3242
-ideographicsocietyparen;3233
-ideographicspace;3000
-ideographicspecialparen;3235
-ideographicstockparen;3231
-ideographicstudyparen;323B
-ideographicsunparen;3230
-ideographicsuperviseparen;323C
-ideographicwaterparen;322C
-ideographicwoodparen;322D
-ideographiczero;3007
-ideographmetalcircle;328E
-ideographmooncircle;328A
-ideographnamecircle;3294
-ideographsuncircle;3290
-ideographwatercircle;328C
-ideographwoodcircle;328D
-ideva;0907
-idieresis;00EF
-idieresisacute;1E2F
-idieresiscyrillic;04E5
-idotbelow;1ECB
-iebrevecyrillic;04D7
-iecyrillic;0435
-ieungacirclekorean;3275
-ieungaparenkorean;3215
-ieungcirclekorean;3267
-ieungkorean;3147
-ieungparenkorean;3207
-igrave;00EC
-igujarati;0A87
-igurmukhi;0A07
-ihiragana;3044
-ihookabove;1EC9
-iibengali;0988
-iicyrillic;0438
-iideva;0908
-iigujarati;0A88
-iigurmukhi;0A08
-iimatragurmukhi;0A40
-iinvertedbreve;020B
-iishortcyrillic;0439
-iivowelsignbengali;09C0
-iivowelsigndeva;0940
-iivowelsigngujarati;0AC0
-ij;0133
-ikatakana;30A4
-ikatakanahalfwidth;FF72
-ikorean;3163
-ilde;02DC
-iluyhebrew;05AC
-imacron;012B
-imacroncyrillic;04E3
-imageorapproximatelyequal;2253
-imatragurmukhi;0A3F
-imonospace;FF49
-increment;2206
-infinity;221E
-iniarmenian;056B
-integral;222B
-integralbottom;2321
-integralbt;2321
-integralex;F8F5
-integraltop;2320
-integraltp;2320
-intersection;2229
-intisquare;3305
-invbullet;25D8
-invcircle;25D9
-invsmileface;263B
-iocyrillic;0451
-iogonek;012F
-iota;03B9
-iotadieresis;03CA
-iotadieresistonos;0390
-iotalatin;0269
-iotatonos;03AF
-iparen;24A4
-irigurmukhi;0A72
-ismallhiragana;3043
-ismallkatakana;30A3
-ismallkatakanahalfwidth;FF68
-issharbengali;09FA
-istroke;0268
-isuperior;F6ED
-iterationhiragana;309D
-iterationkatakana;30FD
-itilde;0129
-itildebelow;1E2D
-iubopomofo;3129
-iucyrillic;044E
-ivowelsignbengali;09BF
-ivowelsigndeva;093F
-ivowelsigngujarati;0ABF
-izhitsacyrillic;0475
-izhitsadblgravecyrillic;0477
-j;006A
-jaarmenian;0571
-jabengali;099C
-jadeva;091C
-jagujarati;0A9C
-jagurmukhi;0A1C
-jbopomofo;3110
-jcaron;01F0
-jcircle;24D9
-jcircumflex;0135
-jcrossedtail;029D
-jdotlessstroke;025F
-jecyrillic;0458
-jeemarabic;062C
-jeemfinalarabic;FE9E
-jeeminitialarabic;FE9F
-jeemmedialarabic;FEA0
-jeharabic;0698
-jehfinalarabic;FB8B
-jhabengali;099D
-jhadeva;091D
-jhagujarati;0A9D
-jhagurmukhi;0A1D
-jheharmenian;057B
-jis;3004
-jmonospace;FF4A
-jparen;24A5
-jsuperior;02B2
-k;006B
-kabashkircyrillic;04A1
-kabengali;0995
-kacute;1E31
-kacyrillic;043A
-kadescendercyrillic;049B
-kadeva;0915
-kaf;05DB
-kafarabic;0643
-kafdagesh;FB3B
-kafdageshhebrew;FB3B
-kaffinalarabic;FEDA
-kafhebrew;05DB
-kafinitialarabic;FEDB
-kafmedialarabic;FEDC
-kafrafehebrew;FB4D
-kagujarati;0A95
-kagurmukhi;0A15
-kahiragana;304B
-kahookcyrillic;04C4
-kakatakana;30AB
-kakatakanahalfwidth;FF76
-kappa;03BA
-kappasymbolgreek;03F0
-kapyeounmieumkorean;3171
-kapyeounphieuphkorean;3184
-kapyeounpieupkorean;3178
-kapyeounssangpieupkorean;3179
-karoriisquare;330D
-kashidaautoarabic;0640
-kashidaautonosidebearingarabic;0640
-kasmallkatakana;30F5
-kasquare;3384
-kasraarabic;0650
-kasratanarabic;064D
-kastrokecyrillic;049F
-katahiraprolongmarkhalfwidth;FF70
-kaverticalstrokecyrillic;049D
-kbopomofo;310E
-kcalsquare;3389
-kcaron;01E9
-kcedilla;0137
-kcircle;24DA
-kcommaaccent;0137
-kdotbelow;1E33
-keharmenian;0584
-kehiragana;3051
-kekatakana;30B1
-kekatakanahalfwidth;FF79
-kenarmenian;056F
-kesmallkatakana;30F6
-kgreenlandic;0138
-khabengali;0996
-khacyrillic;0445
-khadeva;0916
-khagujarati;0A96
-khagurmukhi;0A16
-khaharabic;062E
-khahfinalarabic;FEA6
-khahinitialarabic;FEA7
-khahmedialarabic;FEA8
-kheicoptic;03E7
-khhadeva;0959
-khhagurmukhi;0A59
-khieukhacirclekorean;3278
-khieukhaparenkorean;3218
-khieukhcirclekorean;326A
-khieukhkorean;314B
-khieukhparenkorean;320A
-khokhaithai;0E02
-khokhonthai;0E05
-khokhuatthai;0E03
-khokhwaithai;0E04
-khomutthai;0E5B
-khook;0199
-khorakhangthai;0E06
-khzsquare;3391
-kihiragana;304D
-kikatakana;30AD
-kikatakanahalfwidth;FF77
-kiroguramusquare;3315
-kiromeetorusquare;3316
-kirosquare;3314
-kiyeokacirclekorean;326E
-kiyeokaparenkorean;320E
-kiyeokcirclekorean;3260
-kiyeokkorean;3131
-kiyeokparenkorean;3200
-kiyeoksioskorean;3133
-kjecyrillic;045C
-klinebelow;1E35
-klsquare;3398
-kmcubedsquare;33A6
-kmonospace;FF4B
-kmsquaredsquare;33A2
-kohiragana;3053
-kohmsquare;33C0
-kokaithai;0E01
-kokatakana;30B3
-kokatakanahalfwidth;FF7A
-kooposquare;331E
-koppacyrillic;0481
-koreanstandardsymbol;327F
-koroniscmb;0343
-kparen;24A6
-kpasquare;33AA
-ksicyrillic;046F
-ktsquare;33CF
-kturned;029E
-kuhiragana;304F
-kukatakana;30AF
-kukatakanahalfwidth;FF78
-kvsquare;33B8
-kwsquare;33BE
-l;006C
-labengali;09B2
-lacute;013A
-ladeva;0932
-lagujarati;0AB2
-lagurmukhi;0A32
-lakkhangyaothai;0E45
-lamaleffinalarabic;FEFC
-lamalefhamzaabovefinalarabic;FEF8
-lamalefhamzaaboveisolatedarabic;FEF7
-lamalefhamzabelowfinalarabic;FEFA
-lamalefhamzabelowisolatedarabic;FEF9
-lamalefisolatedarabic;FEFB
-lamalefmaddaabovefinalarabic;FEF6
-lamalefmaddaaboveisolatedarabic;FEF5
-lamarabic;0644
-lambda;03BB
-lambdastroke;019B
-lamed;05DC
-lameddagesh;FB3C
-lameddageshhebrew;FB3C
-lamedhebrew;05DC
-lamedholam;05DC 05B9
-lamedholamdagesh;05DC 05B9 05BC
-lamedholamdageshhebrew;05DC 05B9 05BC
-lamedholamhebrew;05DC 05B9
-lamfinalarabic;FEDE
-lamhahinitialarabic;FCCA
-laminitialarabic;FEDF
-lamjeeminitialarabic;FCC9
-lamkhahinitialarabic;FCCB
-lamlamhehisolatedarabic;FDF2
-lammedialarabic;FEE0
-lammeemhahinitialarabic;FD88
-lammeeminitialarabic;FCCC
-lammeemjeeminitialarabic;FEDF FEE4 FEA0
-lammeemkhahinitialarabic;FEDF FEE4 FEA8
-largecircle;25EF
-lbar;019A
-lbelt;026C
-lbopomofo;310C
-lcaron;013E
-lcedilla;013C
-lcircle;24DB
-lcircumflexbelow;1E3D
-lcommaaccent;013C
-ldot;0140
-ldotaccent;0140
-ldotbelow;1E37
-ldotbelowmacron;1E39
-leftangleabovecmb;031A
-lefttackbelowcmb;0318
-less;003C
-lessequal;2264
-lessequalorgreater;22DA
-lessmonospace;FF1C
-lessorequivalent;2272
-lessorgreater;2276
-lessoverequal;2266
-lesssmall;FE64
-lezh;026E
-lfblock;258C
-lhookretroflex;026D
-lira;20A4
-liwnarmenian;056C
-lj;01C9
-ljecyrillic;0459
-ll;F6C0
-lladeva;0933
-llagujarati;0AB3
-llinebelow;1E3B
-llladeva;0934
-llvocalicbengali;09E1
-llvocalicdeva;0961
-llvocalicvowelsignbengali;09E3
-llvocalicvowelsigndeva;0963
-lmiddletilde;026B
-lmonospace;FF4C
-lmsquare;33D0
-lochulathai;0E2C
-logicaland;2227
-logicalnot;00AC
-logicalnotreversed;2310
-logicalor;2228
-lolingthai;0E25
-longs;017F
-lowlinecenterline;FE4E
-lowlinecmb;0332
-lowlinedashed;FE4D
-lozenge;25CA
-lparen;24A7
-lslash;0142
-lsquare;2113
-lsuperior;F6EE
-ltshade;2591
-luthai;0E26
-lvocalicbengali;098C
-lvocalicdeva;090C
-lvocalicvowelsignbengali;09E2
-lvocalicvowelsigndeva;0962
-lxsquare;33D3
-m;006D
-mabengali;09AE
-macron;00AF
-macronbelowcmb;0331
-macroncmb;0304
-macronlowmod;02CD
-macronmonospace;FFE3
-macute;1E3F
-madeva;092E
-magujarati;0AAE
-magurmukhi;0A2E
-mahapakhhebrew;05A4
-mahapakhlefthebrew;05A4
-mahiragana;307E
-maichattawalowleftthai;F895
-maichattawalowrightthai;F894
-maichattawathai;0E4B
-maichattawaupperleftthai;F893
-maieklowleftthai;F88C
-maieklowrightthai;F88B
-maiekthai;0E48
-maiekupperleftthai;F88A
-maihanakatleftthai;F884
-maihanakatthai;0E31
-maitaikhuleftthai;F889
-maitaikhuthai;0E47
-maitholowleftthai;F88F
-maitholowrightthai;F88E
-maithothai;0E49
-maithoupperleftthai;F88D
-maitrilowleftthai;F892
-maitrilowrightthai;F891
-maitrithai;0E4A
-maitriupperleftthai;F890
-maiyamokthai;0E46
-makatakana;30DE
-makatakanahalfwidth;FF8F
-male;2642
-mansyonsquare;3347
-maqafhebrew;05BE
-mars;2642
-masoracirclehebrew;05AF
-masquare;3383
-mbopomofo;3107
-mbsquare;33D4
-mcircle;24DC
-mcubedsquare;33A5
-mdotaccent;1E41
-mdotbelow;1E43
-meemarabic;0645
-meemfinalarabic;FEE2
-meeminitialarabic;FEE3
-meemmedialarabic;FEE4
-meemmeeminitialarabic;FCD1
-meemmeemisolatedarabic;FC48
-meetorusquare;334D
-mehiragana;3081
-meizierasquare;337E
-mekatakana;30E1
-mekatakanahalfwidth;FF92
-mem;05DE
-memdagesh;FB3E
-memdageshhebrew;FB3E
-memhebrew;05DE
-menarmenian;0574
-merkhahebrew;05A5
-merkhakefulahebrew;05A6
-merkhakefulalefthebrew;05A6
-merkhalefthebrew;05A5
-mhook;0271
-mhzsquare;3392
-middledotkatakanahalfwidth;FF65
-middot;00B7
-mieumacirclekorean;3272
-mieumaparenkorean;3212
-mieumcirclekorean;3264
-mieumkorean;3141
-mieumpansioskorean;3170
-mieumparenkorean;3204
-mieumpieupkorean;316E
-mieumsioskorean;316F
-mihiragana;307F
-mikatakana;30DF
-mikatakanahalfwidth;FF90
-minus;2212
-minusbelowcmb;0320
-minuscircle;2296
-minusmod;02D7
-minusplus;2213
-minute;2032
-miribaarusquare;334A
-mirisquare;3349
-mlonglegturned;0270
-mlsquare;3396
-mmcubedsquare;33A3
-mmonospace;FF4D
-mmsquaredsquare;339F
-mohiragana;3082
-mohmsquare;33C1
-mokatakana;30E2
-mokatakanahalfwidth;FF93
-molsquare;33D6
-momathai;0E21
-moverssquare;33A7
-moverssquaredsquare;33A8
-mparen;24A8
-mpasquare;33AB
-mssquare;33B3
-msuperior;F6EF
-mturned;026F
-mu;00B5
-mu1;00B5
-muasquare;3382
-muchgreater;226B
-muchless;226A
-mufsquare;338C
-mugreek;03BC
-mugsquare;338D
-muhiragana;3080
-mukatakana;30E0
-mukatakanahalfwidth;FF91
-mulsquare;3395
-multiply;00D7
-mumsquare;339B
-munahhebrew;05A3
-munahlefthebrew;05A3
-musicalnote;266A
-musicalnotedbl;266B
-musicflatsign;266D
-musicsharpsign;266F
-mussquare;33B2
-muvsquare;33B6
-muwsquare;33BC
-mvmegasquare;33B9
-mvsquare;33B7
-mwmegasquare;33BF
-mwsquare;33BD
-n;006E
-nabengali;09A8
-nabla;2207
-nacute;0144
-nadeva;0928
-nagujarati;0AA8
-nagurmukhi;0A28
-nahiragana;306A
-nakatakana;30CA
-nakatakanahalfwidth;FF85
-napostrophe;0149
-nasquare;3381
-nbopomofo;310B
-nbspace;00A0
-ncaron;0148
-ncedilla;0146
-ncircle;24DD
-ncircumflexbelow;1E4B
-ncommaaccent;0146
-ndotaccent;1E45
-ndotbelow;1E47
-nehiragana;306D
-nekatakana;30CD
-nekatakanahalfwidth;FF88
-newsheqelsign;20AA
-nfsquare;338B
-ngabengali;0999
-ngadeva;0919
-ngagujarati;0A99
-ngagurmukhi;0A19
-ngonguthai;0E07
-nhiragana;3093
-nhookleft;0272
-nhookretroflex;0273
-nieunacirclekorean;326F
-nieunaparenkorean;320F
-nieuncieuckorean;3135
-nieuncirclekorean;3261
-nieunhieuhkorean;3136
-nieunkorean;3134
-nieunpansioskorean;3168
-nieunparenkorean;3201
-nieunsioskorean;3167
-nieuntikeutkorean;3166
-nihiragana;306B
-nikatakana;30CB
-nikatakanahalfwidth;FF86
-nikhahitleftthai;F899
-nikhahitthai;0E4D
-nine;0039
-ninearabic;0669
-ninebengali;09EF
-ninecircle;2468
-ninecircleinversesansserif;2792
-ninedeva;096F
-ninegujarati;0AEF
-ninegurmukhi;0A6F
-ninehackarabic;0669
-ninehangzhou;3029
-nineideographicparen;3228
-nineinferior;2089
-ninemonospace;FF19
-nineoldstyle;F739
-nineparen;247C
-nineperiod;2490
-ninepersian;06F9
-nineroman;2178
-ninesuperior;2079
-nineteencircle;2472
-nineteenparen;2486
-nineteenperiod;249A
-ninethai;0E59
-nj;01CC
-njecyrillic;045A
-nkatakana;30F3
-nkatakanahalfwidth;FF9D
-nlegrightlong;019E
-nlinebelow;1E49
-nmonospace;FF4E
-nmsquare;339A
-nnabengali;09A3
-nnadeva;0923
-nnagujarati;0AA3
-nnagurmukhi;0A23
-nnnadeva;0929
-nohiragana;306E
-nokatakana;30CE
-nokatakanahalfwidth;FF89
-nonbreakingspace;00A0
-nonenthai;0E13
-nonuthai;0E19
-noonarabic;0646
-noonfinalarabic;FEE6
-noonghunnaarabic;06BA
-noonghunnafinalarabic;FB9F
-noonhehinitialarabic;FEE7 FEEC
-nooninitialarabic;FEE7
-noonjeeminitialarabic;FCD2
-noonjeemisolatedarabic;FC4B
-noonmedialarabic;FEE8
-noonmeeminitialarabic;FCD5
-noonmeemisolatedarabic;FC4E
-noonnoonfinalarabic;FC8D
-notcontains;220C
-notelement;2209
-notelementof;2209
-notequal;2260
-notgreater;226F
-notgreaternorequal;2271
-notgreaternorless;2279
-notidentical;2262
-notless;226E
-notlessnorequal;2270
-notparallel;2226
-notprecedes;2280
-notsubset;2284
-notsucceeds;2281
-notsuperset;2285
-nowarmenian;0576
-nparen;24A9
-nssquare;33B1
-nsuperior;207F
-ntilde;00F1
-nu;03BD
-nuhiragana;306C
-nukatakana;30CC
-nukatakanahalfwidth;FF87
-nuktabengali;09BC
-nuktadeva;093C
-nuktagujarati;0ABC
-nuktagurmukhi;0A3C
-numbersign;0023
-numbersignmonospace;FF03
-numbersignsmall;FE5F
-numeralsigngreek;0374
-numeralsignlowergreek;0375
-numero;2116
-nun;05E0
-nundagesh;FB40
-nundageshhebrew;FB40
-nunhebrew;05E0
-nvsquare;33B5
-nwsquare;33BB
-nyabengali;099E
-nyadeva;091E
-nyagujarati;0A9E
-nyagurmukhi;0A1E
-o;006F
-oacute;00F3
-oangthai;0E2D
-obarred;0275
-obarredcyrillic;04E9
-obarreddieresiscyrillic;04EB
-obengali;0993
-obopomofo;311B
-obreve;014F
-ocandradeva;0911
-ocandragujarati;0A91
-ocandravowelsigndeva;0949
-ocandravowelsigngujarati;0AC9
-ocaron;01D2
-ocircle;24DE
-ocircumflex;00F4
-ocircumflexacute;1ED1
-ocircumflexdotbelow;1ED9
-ocircumflexgrave;1ED3
-ocircumflexhookabove;1ED5
-ocircumflextilde;1ED7
-ocyrillic;043E
-odblacute;0151
-odblgrave;020D
-odeva;0913
-odieresis;00F6
-odieresiscyrillic;04E7
-odotbelow;1ECD
-oe;0153
-oekorean;315A
-ogonek;02DB
-ogonekcmb;0328
-ograve;00F2
-ogujarati;0A93
-oharmenian;0585
-ohiragana;304A
-ohookabove;1ECF
-ohorn;01A1
-ohornacute;1EDB
-ohorndotbelow;1EE3
-ohorngrave;1EDD
-ohornhookabove;1EDF
-ohorntilde;1EE1
-ohungarumlaut;0151
-oi;01A3
-oinvertedbreve;020F
-okatakana;30AA
-okatakanahalfwidth;FF75
-okorean;3157
-olehebrew;05AB
-omacron;014D
-omacronacute;1E53
-omacrongrave;1E51
-omdeva;0950
-omega;03C9
-omega1;03D6
-omegacyrillic;0461
-omegalatinclosed;0277
-omegaroundcyrillic;047B
-omegatitlocyrillic;047D
-omegatonos;03CE
-omgujarati;0AD0
-omicron;03BF
-omicrontonos;03CC
-omonospace;FF4F
-one;0031
-onearabic;0661
-onebengali;09E7
-onecircle;2460
-onecircleinversesansserif;278A
-onedeva;0967
-onedotenleader;2024
-oneeighth;215B
-onefitted;F6DC
-onegujarati;0AE7
-onegurmukhi;0A67
-onehackarabic;0661
-onehalf;00BD
-onehangzhou;3021
-oneideographicparen;3220
-oneinferior;2081
-onemonospace;FF11
-onenumeratorbengali;09F4
-oneoldstyle;F731
-oneparen;2474
-oneperiod;2488
-onepersian;06F1
-onequarter;00BC
-oneroman;2170
-onesuperior;00B9
-onethai;0E51
-onethird;2153
-oogonek;01EB
-oogonekmacron;01ED
-oogurmukhi;0A13
-oomatragurmukhi;0A4B
-oopen;0254
-oparen;24AA
-openbullet;25E6
-option;2325
-ordfeminine;00AA
-ordmasculine;00BA
-orthogonal;221F
-oshortdeva;0912
-oshortvowelsigndeva;094A
-oslash;00F8
-oslashacute;01FF
-osmallhiragana;3049
-osmallkatakana;30A9
-osmallkatakanahalfwidth;FF6B
-ostrokeacute;01FF
-osuperior;F6F0
-otcyrillic;047F
-otilde;00F5
-otildeacute;1E4D
-otildedieresis;1E4F
-oubopomofo;3121
-overline;203E
-overlinecenterline;FE4A
-overlinecmb;0305
-overlinedashed;FE49
-overlinedblwavy;FE4C
-overlinewavy;FE4B
-overscore;00AF
-ovowelsignbengali;09CB
-ovowelsigndeva;094B
-ovowelsigngujarati;0ACB
-p;0070
-paampssquare;3380
-paasentosquare;332B
-pabengali;09AA
-pacute;1E55
-padeva;092A
-pagedown;21DF
-pageup;21DE
-pagujarati;0AAA
-pagurmukhi;0A2A
-pahiragana;3071
-paiyannoithai;0E2F
-pakatakana;30D1
-palatalizationcyrilliccmb;0484
-palochkacyrillic;04C0
-pansioskorean;317F
-paragraph;00B6
-parallel;2225
-parenleft;0028
-parenleftaltonearabic;FD3E
-parenleftbt;F8ED
-parenleftex;F8EC
-parenleftinferior;208D
-parenleftmonospace;FF08
-parenleftsmall;FE59
-parenleftsuperior;207D
-parenlefttp;F8EB
-parenleftvertical;FE35
-parenright;0029
-parenrightaltonearabic;FD3F
-parenrightbt;F8F8
-parenrightex;F8F7
-parenrightinferior;208E
-parenrightmonospace;FF09
-parenrightsmall;FE5A
-parenrightsuperior;207E
-parenrighttp;F8F6
-parenrightvertical;FE36
-partialdiff;2202
-paseqhebrew;05C0
-pashtahebrew;0599
-pasquare;33A9
-patah;05B7
-patah11;05B7
-patah1d;05B7
-patah2a;05B7
-patahhebrew;05B7
-patahnarrowhebrew;05B7
-patahquarterhebrew;05B7
-patahwidehebrew;05B7
-pazerhebrew;05A1
-pbopomofo;3106
-pcircle;24DF
-pdotaccent;1E57
-pe;05E4
-pecyrillic;043F
-pedagesh;FB44
-pedageshhebrew;FB44
-peezisquare;333B
-pefinaldageshhebrew;FB43
-peharabic;067E
-peharmenian;057A
-pehebrew;05E4
-pehfinalarabic;FB57
-pehinitialarabic;FB58
-pehiragana;307A
-pehmedialarabic;FB59
-pekatakana;30DA
-pemiddlehookcyrillic;04A7
-perafehebrew;FB4E
-percent;0025
-percentarabic;066A
-percentmonospace;FF05
-percentsmall;FE6A
-period;002E
-periodarmenian;0589
-periodcentered;00B7
-periodhalfwidth;FF61
-periodinferior;F6E7
-periodmonospace;FF0E
-periodsmall;FE52
-periodsuperior;F6E8
-perispomenigreekcmb;0342
-perpendicular;22A5
-perthousand;2030
-peseta;20A7
-pfsquare;338A
-phabengali;09AB
-phadeva;092B
-phagujarati;0AAB
-phagurmukhi;0A2B
-phi;03C6
-phi1;03D5
-phieuphacirclekorean;327A
-phieuphaparenkorean;321A
-phieuphcirclekorean;326C
-phieuphkorean;314D
-phieuphparenkorean;320C
-philatin;0278
-phinthuthai;0E3A
-phisymbolgreek;03D5
-phook;01A5
-phophanthai;0E1E
-phophungthai;0E1C
-phosamphaothai;0E20
-pi;03C0
-pieupacirclekorean;3273
-pieupaparenkorean;3213
-pieupcieuckorean;3176
-pieupcirclekorean;3265
-pieupkiyeokkorean;3172
-pieupkorean;3142
-pieupparenkorean;3205
-pieupsioskiyeokkorean;3174
-pieupsioskorean;3144
-pieupsiostikeutkorean;3175
-pieupthieuthkorean;3177
-pieuptikeutkorean;3173
-pihiragana;3074
-pikatakana;30D4
-pisymbolgreek;03D6
-piwrarmenian;0583
-plus;002B
-plusbelowcmb;031F
-pluscircle;2295
-plusminus;00B1
-plusmod;02D6
-plusmonospace;FF0B
-plussmall;FE62
-plussuperior;207A
-pmonospace;FF50
-pmsquare;33D8
-pohiragana;307D
-pointingindexdownwhite;261F
-pointingindexleftwhite;261C
-pointingindexrightwhite;261E
-pointingindexupwhite;261D
-pokatakana;30DD
-poplathai;0E1B
-postalmark;3012
-postalmarkface;3020
-pparen;24AB
-precedes;227A
-prescription;211E
-primemod;02B9
-primereversed;2035
-product;220F
-projective;2305
-prolongedkana;30FC
-propellor;2318
-propersubset;2282
-propersuperset;2283
-proportion;2237
-proportional;221D
-psi;03C8
-psicyrillic;0471
-psilipneumatacyrilliccmb;0486
-pssquare;33B0
-puhiragana;3077
-pukatakana;30D7
-pvsquare;33B4
-pwsquare;33BA
-q;0071
-qadeva;0958
-qadmahebrew;05A8
-qafarabic;0642
-qaffinalarabic;FED6
-qafinitialarabic;FED7
-qafmedialarabic;FED8
-qamats;05B8
-qamats10;05B8
-qamats1a;05B8
-qamats1c;05B8
-qamats27;05B8
-qamats29;05B8
-qamats33;05B8
-qamatsde;05B8
-qamatshebrew;05B8
-qamatsnarrowhebrew;05B8
-qamatsqatanhebrew;05B8
-qamatsqatannarrowhebrew;05B8
-qamatsqatanquarterhebrew;05B8
-qamatsqatanwidehebrew;05B8
-qamatsquarterhebrew;05B8
-qamatswidehebrew;05B8
-qarneyparahebrew;059F
-qbopomofo;3111
-qcircle;24E0
-qhook;02A0
-qmonospace;FF51
-qof;05E7
-qofdagesh;FB47
-qofdageshhebrew;FB47
-qofhatafpatah;05E7 05B2
-qofhatafpatahhebrew;05E7 05B2
-qofhatafsegol;05E7 05B1
-qofhatafsegolhebrew;05E7 05B1
-qofhebrew;05E7
-qofhiriq;05E7 05B4
-qofhiriqhebrew;05E7 05B4
-qofholam;05E7 05B9
-qofholamhebrew;05E7 05B9
-qofpatah;05E7 05B7
-qofpatahhebrew;05E7 05B7
-qofqamats;05E7 05B8
-qofqamatshebrew;05E7 05B8
-qofqubuts;05E7 05BB
-qofqubutshebrew;05E7 05BB
-qofsegol;05E7 05B6
-qofsegolhebrew;05E7 05B6
-qofsheva;05E7 05B0
-qofshevahebrew;05E7 05B0
-qoftsere;05E7 05B5
-qoftserehebrew;05E7 05B5
-qparen;24AC
-quarternote;2669
-qubuts;05BB
-qubuts18;05BB
-qubuts25;05BB
-qubuts31;05BB
-qubutshebrew;05BB
-qubutsnarrowhebrew;05BB
-qubutsquarterhebrew;05BB
-qubutswidehebrew;05BB
-question;003F
-questionarabic;061F
-questionarmenian;055E
-questiondown;00BF
-questiondownsmall;F7BF
-questiongreek;037E
-questionmonospace;FF1F
-questionsmall;F73F
-quotedbl;0022
-quotedblbase;201E
-quotedblleft;201C
-quotedblmonospace;FF02
-quotedblprime;301E
-quotedblprimereversed;301D
-quotedblright;201D
-quoteleft;2018
-quoteleftreversed;201B
-quotereversed;201B
-quoteright;2019
-quoterightn;0149
-quotesinglbase;201A
-quotesingle;0027
-quotesinglemonospace;FF07
-r;0072
-raarmenian;057C
-rabengali;09B0
-racute;0155
-radeva;0930
-radical;221A
-radicalex;F8E5
-radoverssquare;33AE
-radoverssquaredsquare;33AF
-radsquare;33AD
-rafe;05BF
-rafehebrew;05BF
-ragujarati;0AB0
-ragurmukhi;0A30
-rahiragana;3089
-rakatakana;30E9
-rakatakanahalfwidth;FF97
-ralowerdiagonalbengali;09F1
-ramiddlediagonalbengali;09F0
-ramshorn;0264
-ratio;2236
-rbopomofo;3116
-rcaron;0159
-rcedilla;0157
-rcircle;24E1
-rcommaaccent;0157
-rdblgrave;0211
-rdotaccent;1E59
-rdotbelow;1E5B
-rdotbelowmacron;1E5D
-referencemark;203B
-reflexsubset;2286
-reflexsuperset;2287
-registered;00AE
-registersans;F8E8
-registerserif;F6DA
-reharabic;0631
-reharmenian;0580
-rehfinalarabic;FEAE
-rehiragana;308C
-rehyehaleflamarabic;0631 FEF3 FE8E 0644
-rekatakana;30EC
-rekatakanahalfwidth;FF9A
-resh;05E8
-reshdageshhebrew;FB48
-reshhatafpatah;05E8 05B2
-reshhatafpatahhebrew;05E8 05B2
-reshhatafsegol;05E8 05B1
-reshhatafsegolhebrew;05E8 05B1
-reshhebrew;05E8
-reshhiriq;05E8 05B4
-reshhiriqhebrew;05E8 05B4
-reshholam;05E8 05B9
-reshholamhebrew;05E8 05B9
-reshpatah;05E8 05B7
-reshpatahhebrew;05E8 05B7
-reshqamats;05E8 05B8
-reshqamatshebrew;05E8 05B8
-reshqubuts;05E8 05BB
-reshqubutshebrew;05E8 05BB
-reshsegol;05E8 05B6
-reshsegolhebrew;05E8 05B6
-reshsheva;05E8 05B0
-reshshevahebrew;05E8 05B0
-reshtsere;05E8 05B5
-reshtserehebrew;05E8 05B5
-reversedtilde;223D
-reviahebrew;0597
-reviamugrashhebrew;0597
-revlogicalnot;2310
-rfishhook;027E
-rfishhookreversed;027F
-rhabengali;09DD
-rhadeva;095D
-rho;03C1
-rhook;027D
-rhookturned;027B
-rhookturnedsuperior;02B5
-rhosymbolgreek;03F1
-rhotichookmod;02DE
-rieulacirclekorean;3271
-rieulaparenkorean;3211
-rieulcirclekorean;3263
-rieulhieuhkorean;3140
-rieulkiyeokkorean;313A
-rieulkiyeoksioskorean;3169
-rieulkorean;3139
-rieulmieumkorean;313B
-rieulpansioskorean;316C
-rieulparenkorean;3203
-rieulphieuphkorean;313F
-rieulpieupkorean;313C
-rieulpieupsioskorean;316B
-rieulsioskorean;313D
-rieulthieuthkorean;313E
-rieultikeutkorean;316A
-rieulyeorinhieuhkorean;316D
-rightangle;221F
-righttackbelowcmb;0319
-righttriangle;22BF
-rihiragana;308A
-rikatakana;30EA
-rikatakanahalfwidth;FF98
-ring;02DA
-ringbelowcmb;0325
-ringcmb;030A
-ringhalfleft;02BF
-ringhalfleftarmenian;0559
-ringhalfleftbelowcmb;031C
-ringhalfleftcentered;02D3
-ringhalfright;02BE
-ringhalfrightbelowcmb;0339
-ringhalfrightcentered;02D2
-rinvertedbreve;0213
-rittorusquare;3351
-rlinebelow;1E5F
-rlongleg;027C
-rlonglegturned;027A
-rmonospace;FF52
-rohiragana;308D
-rokatakana;30ED
-rokatakanahalfwidth;FF9B
-roruathai;0E23
-rparen;24AD
-rrabengali;09DC
-rradeva;0931
-rragurmukhi;0A5C
-rreharabic;0691
-rrehfinalarabic;FB8D
-rrvocalicbengali;09E0
-rrvocalicdeva;0960
-rrvocalicgujarati;0AE0
-rrvocalicvowelsignbengali;09C4
-rrvocalicvowelsigndeva;0944
-rrvocalicvowelsigngujarati;0AC4
-rsuperior;F6F1
-rtblock;2590
-rturned;0279
-rturnedsuperior;02B4
-ruhiragana;308B
-rukatakana;30EB
-rukatakanahalfwidth;FF99
-rupeemarkbengali;09F2
-rupeesignbengali;09F3
-rupiah;F6DD
-ruthai;0E24
-rvocalicbengali;098B
-rvocalicdeva;090B
-rvocalicgujarati;0A8B
-rvocalicvowelsignbengali;09C3
-rvocalicvowelsigndeva;0943
-rvocalicvowelsigngujarati;0AC3
-s;0073
-sabengali;09B8
-sacute;015B
-sacutedotaccent;1E65
-sadarabic;0635
-sadeva;0938
-sadfinalarabic;FEBA
-sadinitialarabic;FEBB
-sadmedialarabic;FEBC
-sagujarati;0AB8
-sagurmukhi;0A38
-sahiragana;3055
-sakatakana;30B5
-sakatakanahalfwidth;FF7B
-sallallahoualayhewasallamarabic;FDFA
-samekh;05E1
-samekhdagesh;FB41
-samekhdageshhebrew;FB41
-samekhhebrew;05E1
-saraaathai;0E32
-saraaethai;0E41
-saraaimaimalaithai;0E44
-saraaimaimuanthai;0E43
-saraamthai;0E33
-saraathai;0E30
-saraethai;0E40
-saraiileftthai;F886
-saraiithai;0E35
-saraileftthai;F885
-saraithai;0E34
-saraothai;0E42
-saraueeleftthai;F888
-saraueethai;0E37
-saraueleftthai;F887
-sarauethai;0E36
-sarauthai;0E38
-sarauuthai;0E39
-sbopomofo;3119
-scaron;0161
-scarondotaccent;1E67
-scedilla;015F
-schwa;0259
-schwacyrillic;04D9
-schwadieresiscyrillic;04DB
-schwahook;025A
-scircle;24E2
-scircumflex;015D
-scommaaccent;0219
-sdotaccent;1E61
-sdotbelow;1E63
-sdotbelowdotaccent;1E69
-seagullbelowcmb;033C
-second;2033
-secondtonechinese;02CA
-section;00A7
-seenarabic;0633
-seenfinalarabic;FEB2
-seeninitialarabic;FEB3
-seenmedialarabic;FEB4
-segol;05B6
-segol13;05B6
-segol1f;05B6
-segol2c;05B6
-segolhebrew;05B6
-segolnarrowhebrew;05B6
-segolquarterhebrew;05B6
-segoltahebrew;0592
-segolwidehebrew;05B6
-seharmenian;057D
-sehiragana;305B
-sekatakana;30BB
-sekatakanahalfwidth;FF7E
-semicolon;003B
-semicolonarabic;061B
-semicolonmonospace;FF1B
-semicolonsmall;FE54
-semivoicedmarkkana;309C
-semivoicedmarkkanahalfwidth;FF9F
-sentisquare;3322
-sentosquare;3323
-seven;0037
-sevenarabic;0667
-sevenbengali;09ED
-sevencircle;2466
-sevencircleinversesansserif;2790
-sevendeva;096D
-seveneighths;215E
-sevengujarati;0AED
-sevengurmukhi;0A6D
-sevenhackarabic;0667
-sevenhangzhou;3027
-sevenideographicparen;3226
-seveninferior;2087
-sevenmonospace;FF17
-sevenoldstyle;F737
-sevenparen;247A
-sevenperiod;248E
-sevenpersian;06F7
-sevenroman;2176
-sevensuperior;2077
-seventeencircle;2470
-seventeenparen;2484
-seventeenperiod;2498
-seventhai;0E57
-sfthyphen;00AD
-shaarmenian;0577
-shabengali;09B6
-shacyrillic;0448
-shaddaarabic;0651
-shaddadammaarabic;FC61
-shaddadammatanarabic;FC5E
-shaddafathaarabic;FC60
-shaddafathatanarabic;0651 064B
-shaddakasraarabic;FC62
-shaddakasratanarabic;FC5F
-shade;2592
-shadedark;2593
-shadelight;2591
-shademedium;2592
-shadeva;0936
-shagujarati;0AB6
-shagurmukhi;0A36
-shalshelethebrew;0593
-shbopomofo;3115
-shchacyrillic;0449
-sheenarabic;0634
-sheenfinalarabic;FEB6
-sheeninitialarabic;FEB7
-sheenmedialarabic;FEB8
-sheicoptic;03E3
-sheqel;20AA
-sheqelhebrew;20AA
-sheva;05B0
-sheva115;05B0
-sheva15;05B0
-sheva22;05B0
-sheva2e;05B0
-shevahebrew;05B0
-shevanarrowhebrew;05B0
-shevaquarterhebrew;05B0
-shevawidehebrew;05B0
-shhacyrillic;04BB
-shimacoptic;03ED
-shin;05E9
-shindagesh;FB49
-shindageshhebrew;FB49
-shindageshshindot;FB2C
-shindageshshindothebrew;FB2C
-shindageshsindot;FB2D
-shindageshsindothebrew;FB2D
-shindothebrew;05C1
-shinhebrew;05E9
-shinshindot;FB2A
-shinshindothebrew;FB2A
-shinsindot;FB2B
-shinsindothebrew;FB2B
-shook;0282
-sigma;03C3
-sigma1;03C2
-sigmafinal;03C2
-sigmalunatesymbolgreek;03F2
-sihiragana;3057
-sikatakana;30B7
-sikatakanahalfwidth;FF7C
-siluqhebrew;05BD
-siluqlefthebrew;05BD
-similar;223C
-sindothebrew;05C2
-siosacirclekorean;3274
-siosaparenkorean;3214
-sioscieuckorean;317E
-sioscirclekorean;3266
-sioskiyeokkorean;317A
-sioskorean;3145
-siosnieunkorean;317B
-siosparenkorean;3206
-siospieupkorean;317D
-siostikeutkorean;317C
-six;0036
-sixarabic;0666
-sixbengali;09EC
-sixcircle;2465
-sixcircleinversesansserif;278F
-sixdeva;096C
-sixgujarati;0AEC
-sixgurmukhi;0A6C
-sixhackarabic;0666
-sixhangzhou;3026
-sixideographicparen;3225
-sixinferior;2086
-sixmonospace;FF16
-sixoldstyle;F736
-sixparen;2479
-sixperiod;248D
-sixpersian;06F6
-sixroman;2175
-sixsuperior;2076
-sixteencircle;246F
-sixteencurrencydenominatorbengali;09F9
-sixteenparen;2483
-sixteenperiod;2497
-sixthai;0E56
-slash;002F
-slashmonospace;FF0F
-slong;017F
-slongdotaccent;1E9B
-smileface;263A
-smonospace;FF53
-sofpasuqhebrew;05C3
-softhyphen;00AD
-softsigncyrillic;044C
-sohiragana;305D
-sokatakana;30BD
-sokatakanahalfwidth;FF7F
-soliduslongoverlaycmb;0338
-solidusshortoverlaycmb;0337
-sorusithai;0E29
-sosalathai;0E28
-sosothai;0E0B
-sosuathai;0E2A
-space;0020
-spacehackarabic;0020
-spade;2660
-spadesuitblack;2660
-spadesuitwhite;2664
-sparen;24AE
-squarebelowcmb;033B
-squarecc;33C4
-squarecm;339D
-squarediagonalcrosshatchfill;25A9
-squarehorizontalfill;25A4
-squarekg;338F
-squarekm;339E
-squarekmcapital;33CE
-squareln;33D1
-squarelog;33D2
-squaremg;338E
-squaremil;33D5
-squaremm;339C
-squaremsquared;33A1
-squareorthogonalcrosshatchfill;25A6
-squareupperlefttolowerrightfill;25A7
-squareupperrighttolowerleftfill;25A8
-squareverticalfill;25A5
-squarewhitewithsmallblack;25A3
-srsquare;33DB
-ssabengali;09B7
-ssadeva;0937
-ssagujarati;0AB7
-ssangcieuckorean;3149
-ssanghieuhkorean;3185
-ssangieungkorean;3180
-ssangkiyeokkorean;3132
-ssangnieunkorean;3165
-ssangpieupkorean;3143
-ssangsioskorean;3146
-ssangtikeutkorean;3138
-ssuperior;F6F2
-sterling;00A3
-sterlingmonospace;FFE1
-strokelongoverlaycmb;0336
-strokeshortoverlaycmb;0335
-subset;2282
-subsetnotequal;228A
-subsetorequal;2286
-succeeds;227B
-suchthat;220B
-suhiragana;3059
-sukatakana;30B9
-sukatakanahalfwidth;FF7D
-sukunarabic;0652
-summation;2211
-sun;263C
-superset;2283
-supersetnotequal;228B
-supersetorequal;2287
-svsquare;33DC
-syouwaerasquare;337C
-t;0074
-tabengali;09A4
-tackdown;22A4
-tackleft;22A3
-tadeva;0924
-tagujarati;0AA4
-tagurmukhi;0A24
-taharabic;0637
-tahfinalarabic;FEC2
-tahinitialarabic;FEC3
-tahiragana;305F
-tahmedialarabic;FEC4
-taisyouerasquare;337D
-takatakana;30BF
-takatakanahalfwidth;FF80
-tatweelarabic;0640
-tau;03C4
-tav;05EA
-tavdages;FB4A
-tavdagesh;FB4A
-tavdageshhebrew;FB4A
-tavhebrew;05EA
-tbar;0167
-tbopomofo;310A
-tcaron;0165
-tccurl;02A8
-tcedilla;0163
-tcheharabic;0686
-tchehfinalarabic;FB7B
-tchehinitialarabic;FB7C
-tchehmedialarabic;FB7D
-tchehmeeminitialarabic;FB7C FEE4
-tcircle;24E3
-tcircumflexbelow;1E71
-tcommaaccent;0163
-tdieresis;1E97
-tdotaccent;1E6B
-tdotbelow;1E6D
-tecyrillic;0442
-tedescendercyrillic;04AD
-teharabic;062A
-tehfinalarabic;FE96
-tehhahinitialarabic;FCA2
-tehhahisolatedarabic;FC0C
-tehinitialarabic;FE97
-tehiragana;3066
-tehjeeminitialarabic;FCA1
-tehjeemisolatedarabic;FC0B
-tehmarbutaarabic;0629
-tehmarbutafinalarabic;FE94
-tehmedialarabic;FE98
-tehmeeminitialarabic;FCA4
-tehmeemisolatedarabic;FC0E
-tehnoonfinalarabic;FC73
-tekatakana;30C6
-tekatakanahalfwidth;FF83
-telephone;2121
-telephoneblack;260E
-telishagedolahebrew;05A0
-telishaqetanahebrew;05A9
-tencircle;2469
-tenideographicparen;3229
-tenparen;247D
-tenperiod;2491
-tenroman;2179
-tesh;02A7
-tet;05D8
-tetdagesh;FB38
-tetdageshhebrew;FB38
-tethebrew;05D8
-tetsecyrillic;04B5
-tevirhebrew;059B
-tevirlefthebrew;059B
-thabengali;09A5
-thadeva;0925
-thagujarati;0AA5
-thagurmukhi;0A25
-thalarabic;0630
-thalfinalarabic;FEAC
-thanthakhatlowleftthai;F898
-thanthakhatlowrightthai;F897
-thanthakhatthai;0E4C
-thanthakhatupperleftthai;F896
-theharabic;062B
-thehfinalarabic;FE9A
-thehinitialarabic;FE9B
-thehmedialarabic;FE9C
-thereexists;2203
-therefore;2234
-theta;03B8
-theta1;03D1
-thetasymbolgreek;03D1
-thieuthacirclekorean;3279
-thieuthaparenkorean;3219
-thieuthcirclekorean;326B
-thieuthkorean;314C
-thieuthparenkorean;320B
-thirteencircle;246C
-thirteenparen;2480
-thirteenperiod;2494
-thonangmonthothai;0E11
-thook;01AD
-thophuthaothai;0E12
-thorn;00FE
-thothahanthai;0E17
-thothanthai;0E10
-thothongthai;0E18
-thothungthai;0E16
-thousandcyrillic;0482
-thousandsseparatorarabic;066C
-thousandsseparatorpersian;066C
-three;0033
-threearabic;0663
-threebengali;09E9
-threecircle;2462
-threecircleinversesansserif;278C
-threedeva;0969
-threeeighths;215C
-threegujarati;0AE9
-threegurmukhi;0A69
-threehackarabic;0663
-threehangzhou;3023
-threeideographicparen;3222
-threeinferior;2083
-threemonospace;FF13
-threenumeratorbengali;09F6
-threeoldstyle;F733
-threeparen;2476
-threeperiod;248A
-threepersian;06F3
-threequarters;00BE
-threequartersemdash;F6DE
-threeroman;2172
-threesuperior;00B3
-threethai;0E53
-thzsquare;3394
-tihiragana;3061
-tikatakana;30C1
-tikatakanahalfwidth;FF81
-tikeutacirclekorean;3270
-tikeutaparenkorean;3210
-tikeutcirclekorean;3262
-tikeutkorean;3137
-tikeutparenkorean;3202
-tilde;02DC
-tildebelowcmb;0330
-tildecmb;0303
-tildecomb;0303
-tildedoublecmb;0360
-tildeoperator;223C
-tildeoverlaycmb;0334
-tildeverticalcmb;033E
-timescircle;2297
-tipehahebrew;0596
-tipehalefthebrew;0596
-tippigurmukhi;0A70
-titlocyrilliccmb;0483
-tiwnarmenian;057F
-tlinebelow;1E6F
-tmonospace;FF54
-toarmenian;0569
-tohiragana;3068
-tokatakana;30C8
-tokatakanahalfwidth;FF84
-tonebarextrahighmod;02E5
-tonebarextralowmod;02E9
-tonebarhighmod;02E6
-tonebarlowmod;02E8
-tonebarmidmod;02E7
-tonefive;01BD
-tonesix;0185
-tonetwo;01A8
-tonos;0384
-tonsquare;3327
-topatakthai;0E0F
-tortoiseshellbracketleft;3014
-tortoiseshellbracketleftsmall;FE5D
-tortoiseshellbracketleftvertical;FE39
-tortoiseshellbracketright;3015
-tortoiseshellbracketrightsmall;FE5E
-tortoiseshellbracketrightvertical;FE3A
-totaothai;0E15
-tpalatalhook;01AB
-tparen;24AF
-trademark;2122
-trademarksans;F8EA
-trademarkserif;F6DB
-tretroflexhook;0288
-triagdn;25BC
-triaglf;25C4
-triagrt;25BA
-triagup;25B2
-ts;02A6
-tsadi;05E6
-tsadidagesh;FB46
-tsadidageshhebrew;FB46
-tsadihebrew;05E6
-tsecyrillic;0446
-tsere;05B5
-tsere12;05B5
-tsere1e;05B5
-tsere2b;05B5
-tserehebrew;05B5
-tserenarrowhebrew;05B5
-tserequarterhebrew;05B5
-tserewidehebrew;05B5
-tshecyrillic;045B
-tsuperior;F6F3
-ttabengali;099F
-ttadeva;091F
-ttagujarati;0A9F
-ttagurmukhi;0A1F
-tteharabic;0679
-ttehfinalarabic;FB67
-ttehinitialarabic;FB68
-ttehmedialarabic;FB69
-tthabengali;09A0
-tthadeva;0920
-tthagujarati;0AA0
-tthagurmukhi;0A20
-tturned;0287
-tuhiragana;3064
-tukatakana;30C4
-tukatakanahalfwidth;FF82
-tusmallhiragana;3063
-tusmallkatakana;30C3
-tusmallkatakanahalfwidth;FF6F
-twelvecircle;246B
-twelveparen;247F
-twelveperiod;2493
-twelveroman;217B
-twentycircle;2473
-twentyhangzhou;5344
-twentyparen;2487
-twentyperiod;249B
-two;0032
-twoarabic;0662
-twobengali;09E8
-twocircle;2461
-twocircleinversesansserif;278B
-twodeva;0968
-twodotenleader;2025
-twodotleader;2025
-twodotleadervertical;FE30
-twogujarati;0AE8
-twogurmukhi;0A68
-twohackarabic;0662
-twohangzhou;3022
-twoideographicparen;3221
-twoinferior;2082
-twomonospace;FF12
-twonumeratorbengali;09F5
-twooldstyle;F732
-twoparen;2475
-twoperiod;2489
-twopersian;06F2
-tworoman;2171
-twostroke;01BB
-twosuperior;00B2
-twothai;0E52
-twothirds;2154
-u;0075
-uacute;00FA
-ubar;0289
-ubengali;0989
-ubopomofo;3128
-ubreve;016D
-ucaron;01D4
-ucircle;24E4
-ucircumflex;00FB
-ucircumflexbelow;1E77
-ucyrillic;0443
-udattadeva;0951
-udblacute;0171
-udblgrave;0215
-udeva;0909
-udieresis;00FC
-udieresisacute;01D8
-udieresisbelow;1E73
-udieresiscaron;01DA
-udieresiscyrillic;04F1
-udieresisgrave;01DC
-udieresismacron;01D6
-udotbelow;1EE5
-ugrave;00F9
-ugujarati;0A89
-ugurmukhi;0A09
-uhiragana;3046
-uhookabove;1EE7
-uhorn;01B0
-uhornacute;1EE9
-uhorndotbelow;1EF1
-uhorngrave;1EEB
-uhornhookabove;1EED
-uhorntilde;1EEF
-uhungarumlaut;0171
-uhungarumlautcyrillic;04F3
-uinvertedbreve;0217
-ukatakana;30A6
-ukatakanahalfwidth;FF73
-ukcyrillic;0479
-ukorean;315C
-umacron;016B
-umacroncyrillic;04EF
-umacrondieresis;1E7B
-umatragurmukhi;0A41
-umonospace;FF55
-underscore;005F
-underscoredbl;2017
-underscoremonospace;FF3F
-underscorevertical;FE33
-underscorewavy;FE4F
-union;222A
-universal;2200
-uogonek;0173
-uparen;24B0
-upblock;2580
-upperdothebrew;05C4
-upsilon;03C5
-upsilondieresis;03CB
-upsilondieresistonos;03B0
-upsilonlatin;028A
-upsilontonos;03CD
-uptackbelowcmb;031D
-uptackmod;02D4
-uragurmukhi;0A73
-uring;016F
-ushortcyrillic;045E
-usmallhiragana;3045
-usmallkatakana;30A5
-usmallkatakanahalfwidth;FF69
-ustraightcyrillic;04AF
-ustraightstrokecyrillic;04B1
-utilde;0169
-utildeacute;1E79
-utildebelow;1E75
-uubengali;098A
-uudeva;090A
-uugujarati;0A8A
-uugurmukhi;0A0A
-uumatragurmukhi;0A42
-uuvowelsignbengali;09C2
-uuvowelsigndeva;0942
-uuvowelsigngujarati;0AC2
-uvowelsignbengali;09C1
-uvowelsigndeva;0941
-uvowelsigngujarati;0AC1
-v;0076
-vadeva;0935
-vagujarati;0AB5
-vagurmukhi;0A35
-vakatakana;30F7
-vav;05D5
-vavdagesh;FB35
-vavdagesh65;FB35
-vavdageshhebrew;FB35
-vavhebrew;05D5
-vavholam;FB4B
-vavholamhebrew;FB4B
-vavvavhebrew;05F0
-vavyodhebrew;05F1
-vcircle;24E5
-vdotbelow;1E7F
-vecyrillic;0432
-veharabic;06A4
-vehfinalarabic;FB6B
-vehinitialarabic;FB6C
-vehmedialarabic;FB6D
-vekatakana;30F9
-venus;2640
-verticalbar;007C
-verticallineabovecmb;030D
-verticallinebelowcmb;0329
-verticallinelowmod;02CC
-verticallinemod;02C8
-vewarmenian;057E
-vhook;028B
-vikatakana;30F8
-viramabengali;09CD
-viramadeva;094D
-viramagujarati;0ACD
-visargabengali;0983
-visargadeva;0903
-visargagujarati;0A83
-vmonospace;FF56
-voarmenian;0578
-voicediterationhiragana;309E
-voicediterationkatakana;30FE
-voicedmarkkana;309B
-voicedmarkkanahalfwidth;FF9E
-vokatakana;30FA
-vparen;24B1
-vtilde;1E7D
-vturned;028C
-vuhiragana;3094
-vukatakana;30F4
-w;0077
-wacute;1E83
-waekorean;3159
-wahiragana;308F
-wakatakana;30EF
-wakatakanahalfwidth;FF9C
-wakorean;3158
-wasmallhiragana;308E
-wasmallkatakana;30EE
-wattosquare;3357
-wavedash;301C
-wavyunderscorevertical;FE34
-wawarabic;0648
-wawfinalarabic;FEEE
-wawhamzaabovearabic;0624
-wawhamzaabovefinalarabic;FE86
-wbsquare;33DD
-wcircle;24E6
-wcircumflex;0175
-wdieresis;1E85
-wdotaccent;1E87
-wdotbelow;1E89
-wehiragana;3091
-weierstrass;2118
-wekatakana;30F1
-wekorean;315E
-weokorean;315D
-wgrave;1E81
-whitebullet;25E6
-whitecircle;25CB
-whitecircleinverse;25D9
-whitecornerbracketleft;300E
-whitecornerbracketleftvertical;FE43
-whitecornerbracketright;300F
-whitecornerbracketrightvertical;FE44
-whitediamond;25C7
-whitediamondcontainingblacksmalldiamond;25C8
-whitedownpointingsmalltriangle;25BF
-whitedownpointingtriangle;25BD
-whiteleftpointingsmalltriangle;25C3
-whiteleftpointingtriangle;25C1
-whitelenticularbracketleft;3016
-whitelenticularbracketright;3017
-whiterightpointingsmalltriangle;25B9
-whiterightpointingtriangle;25B7
-whitesmallsquare;25AB
-whitesmilingface;263A
-whitesquare;25A1
-whitestar;2606
-whitetelephone;260F
-whitetortoiseshellbracketleft;3018
-whitetortoiseshellbracketright;3019
-whiteuppointingsmalltriangle;25B5
-whiteuppointingtriangle;25B3
-wihiragana;3090
-wikatakana;30F0
-wikorean;315F
-wmonospace;FF57
-wohiragana;3092
-wokatakana;30F2
-wokatakanahalfwidth;FF66
-won;20A9
-wonmonospace;FFE6
-wowaenthai;0E27
-wparen;24B2
-wring;1E98
-wsuperior;02B7
-wturned;028D
-wynn;01BF
-x;0078
-xabovecmb;033D
-xbopomofo;3112
-xcircle;24E7
-xdieresis;1E8D
-xdotaccent;1E8B
-xeharmenian;056D
-xi;03BE
-xmonospace;FF58
-xparen;24B3
-xsuperior;02E3
-y;0079
-yaadosquare;334E
-yabengali;09AF
-yacute;00FD
-yadeva;092F
-yaekorean;3152
-yagujarati;0AAF
-yagurmukhi;0A2F
-yahiragana;3084
-yakatakana;30E4
-yakatakanahalfwidth;FF94
-yakorean;3151
-yamakkanthai;0E4E
-yasmallhiragana;3083
-yasmallkatakana;30E3
-yasmallkatakanahalfwidth;FF6C
-yatcyrillic;0463
-ycircle;24E8
-ycircumflex;0177
-ydieresis;00FF
-ydotaccent;1E8F
-ydotbelow;1EF5
-yeharabic;064A
-yehbarreearabic;06D2
-yehbarreefinalarabic;FBAF
-yehfinalarabic;FEF2
-yehhamzaabovearabic;0626
-yehhamzaabovefinalarabic;FE8A
-yehhamzaaboveinitialarabic;FE8B
-yehhamzaabovemedialarabic;FE8C
-yehinitialarabic;FEF3
-yehmedialarabic;FEF4
-yehmeeminitialarabic;FCDD
-yehmeemisolatedarabic;FC58
-yehnoonfinalarabic;FC94
-yehthreedotsbelowarabic;06D1
-yekorean;3156
-yen;00A5
-yenmonospace;FFE5
-yeokorean;3155
-yeorinhieuhkorean;3186
-yerahbenyomohebrew;05AA
-yerahbenyomolefthebrew;05AA
-yericyrillic;044B
-yerudieresiscyrillic;04F9
-yesieungkorean;3181
-yesieungpansioskorean;3183
-yesieungsioskorean;3182
-yetivhebrew;059A
-ygrave;1EF3
-yhook;01B4
-yhookabove;1EF7
-yiarmenian;0575
-yicyrillic;0457
-yikorean;3162
-yinyang;262F
-yiwnarmenian;0582
-ymonospace;FF59
-yod;05D9
-yoddagesh;FB39
-yoddageshhebrew;FB39
-yodhebrew;05D9
-yodyodhebrew;05F2
-yodyodpatahhebrew;FB1F
-yohiragana;3088
-yoikorean;3189
-yokatakana;30E8
-yokatakanahalfwidth;FF96
-yokorean;315B
-yosmallhiragana;3087
-yosmallkatakana;30E7
-yosmallkatakanahalfwidth;FF6E
-yotgreek;03F3
-yoyaekorean;3188
-yoyakorean;3187
-yoyakthai;0E22
-yoyingthai;0E0D
-yparen;24B4
-ypogegrammeni;037A
-ypogegrammenigreekcmb;0345
-yr;01A6
-yring;1E99
-ysuperior;02B8
-ytilde;1EF9
-yturned;028E
-yuhiragana;3086
-yuikorean;318C
-yukatakana;30E6
-yukatakanahalfwidth;FF95
-yukorean;3160
-yusbigcyrillic;046B
-yusbigiotifiedcyrillic;046D
-yuslittlecyrillic;0467
-yuslittleiotifiedcyrillic;0469
-yusmallhiragana;3085
-yusmallkatakana;30E5
-yusmallkatakanahalfwidth;FF6D
-yuyekorean;318B
-yuyeokorean;318A
-yyabengali;09DF
-yyadeva;095F
-z;007A
-zaarmenian;0566
-zacute;017A
-zadeva;095B
-zagurmukhi;0A5B
-zaharabic;0638
-zahfinalarabic;FEC6
-zahinitialarabic;FEC7
-zahiragana;3056
-zahmedialarabic;FEC8
-zainarabic;0632
-zainfinalarabic;FEB0
-zakatakana;30B6
-zaqefgadolhebrew;0595
-zaqefqatanhebrew;0594
-zarqahebrew;0598
-zayin;05D6
-zayindagesh;FB36
-zayindageshhebrew;FB36
-zayinhebrew;05D6
-zbopomofo;3117
-zcaron;017E
-zcircle;24E9
-zcircumflex;1E91
-zcurl;0291
-zdot;017C
-zdotaccent;017C
-zdotbelow;1E93
-zecyrillic;0437
-zedescendercyrillic;0499
-zedieresiscyrillic;04DF
-zehiragana;305C
-zekatakana;30BC
-zero;0030
-zeroarabic;0660
-zerobengali;09E6
-zerodeva;0966
-zerogujarati;0AE6
-zerogurmukhi;0A66
-zerohackarabic;0660
-zeroinferior;2080
-zeromonospace;FF10
-zerooldstyle;F730
-zeropersian;06F0
-zerosuperior;2070
-zerothai;0E50
-zerowidthjoiner;FEFF
-zerowidthnonjoiner;200C
-zerowidthspace;200B
-zeta;03B6
-zhbopomofo;3113
-zhearmenian;056A
-zhebrevecyrillic;04C2
-zhecyrillic;0436
-zhedescendercyrillic;0497
-zhedieresiscyrillic;04DD
-zihiragana;3058
-zikatakana;30B8
-zinorhebrew;05AE
-zlinebelow;1E95
-zmonospace;FF5A
-zohiragana;305E
-zokatakana;30BE
-zparen;24B5
-zretroflexhook;0290
-zstroke;01B6
-zuhiragana;305A
-zukatakana;30BA
-# END
-"""
-
-
-_aglfnText = """\
-# -----------------------------------------------------------
-# Copyright 2002-2019 Adobe (http://www.adobe.com/).
-#
-# Redistribution and use in source and binary forms, with or
-# without modification, are permitted provided that the
-# following conditions are met:
-#
-# Redistributions of source code must retain the above
-# copyright notice, this list of conditions and the following
-# disclaimer.
-#
-# Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials
-# provided with the distribution.
-#
-# Neither the name of Adobe nor the names of its contributors
-# may be used to endorse or promote products derived from this
-# software without specific prior written permission.
+# Neither the name of Adobe Systems Incorporated nor the names
+# of its contributors may be used to endorse or promote
+# products derived from this software without specific prior
+# written permission.
 #
 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
@@ -4397,7 +48,7 @@
 # Name:          Adobe Glyph List For New Fonts
 # Table version: 1.7
 # Date:          November 6, 2008
-# URL:           https://github.com/adobe-type-tools/agl-aglfn
+# URL:           http://sourceforge.net/adobe/aglfn/
 #
 # Description:
 #
@@ -5054,14 +705,13 @@
 017C;zdotaccent;LATIN SMALL LETTER Z WITH DOT ABOVE
 0030;zero;DIGIT ZERO
 03B6;zeta;GREEK SMALL LETTER ZETA
-# END
+#END
 """
 
 
 class AGLError(Exception):
 	pass
 
-LEGACY_AGL2UV = {}
 AGL2UV = {}
 UV2AGL = {}
 
@@ -5070,7 +720,7 @@
 
 	lines = _aglText.splitlines()
 
-	parseAGL_RE = re.compile("([A-Za-z0-9]+);((?:[0-9A-F]{4})(?: (?:[0-9A-F]{4}))*)$")
+	parseAGL_RE = re.compile("([0-9A-F]{4});([A-Za-z_0-9.]+);.*?$")
 
 	for line in lines:
 		if not line or line[:1] == '#':
@@ -5078,36 +728,24 @@
 		m = parseAGL_RE.match(line)
 		if not m:
 			raise AGLError("syntax error in glyphlist.txt: %s" % repr(line[:20]))
-		unicodes = m.group(2)
-		assert len(unicodes) % 5 == 4
-		unicodes = [int(unicode, 16) for unicode in unicodes.split()]
-		glyphName = tostr(m.group(1))
-		LEGACY_AGL2UV[glyphName] = unicodes
-
-	lines = _aglfnText.splitlines()
-
-	parseAGLFN_RE = re.compile("([0-9A-F]{4});([A-Za-z0-9]+);.*?$")
-
-	for line in lines:
-		if not line or line[:1] == '#':
-			continue
-		m = parseAGLFN_RE.match(line)
-		if not m:
-			raise AGLError("syntax error in aglfn.txt: %s" % repr(line[:20]))
 		unicode = m.group(1)
 		assert len(unicode) == 4
 		unicode = int(unicode, 16)
 		glyphName = tostr(m.group(2))
-		AGL2UV[glyphName] = unicode
+		if glyphName in AGL2UV:
+			# the above table contains identical duplicates
+			assert AGL2UV[glyphName] == unicode
+		else:
+			AGL2UV[glyphName] = unicode
 		UV2AGL[unicode] = glyphName
 
 _builddicts()
 
 
 def toUnicode(glyph, isZapfDingbats=False):
-	"""Convert glyph names to Unicode, such as ``'longs_t.oldstyle'`` --> ``u'ſt'``
+	"""Convert glyph names to Unicode, such as 'longs_t.oldstyle' --> u'ſt'
 
-	If ``isZapfDingbats`` is ``True``, the implementation recognizes additional
+	If isZapfDingbats is True, the implementation recognizes additional
 	glyph names (as required by the AGL specification).
 	"""
 	# https://github.com/adobe-type-tools/agl-specification#2-the-mapping
@@ -5138,9 +776,14 @@
 
 	# Otherwise, if the component is in AGL, then map it
 	# to the corresponding character in that list.
-	uchars = LEGACY_AGL2UV.get(component)
-	if uchars:
-		return "".join(map(chr, uchars))
+	#
+	# TODO: We currently use the AGLFN (Adobe glyph list for new fonts),
+	# although the spec actually mandates the legacy AGL which is
+	# a superset of the AGLFN.
+	# https://github.com/fonttools/fonttools/issues/775
+	uchar = AGL2UV.get(component)
+	if uchar:
+		return unichr(uchar)
 
 	# Otherwise, if the component is of the form "uni" (U+0075,
 	# U+006E, and U+0069) followed by a sequence of uppercase
@@ -5210,7 +853,7 @@
 	if any(c >= 0xD800 and c <= 0xDFFF for c in chars):
 		# The AGL specification explicitly excluded surrogate pairs.
 		return None
-	return ''.join([chr(c) for c in chars])
+	return ''.join([unichr(c) for c in chars])
 
 
 _re_u = re.compile("^u([0-9A-F]{4,6})$")
@@ -5228,5 +871,5 @@
 		return None
 	if ((value >= 0x0000 and value <= 0xD7FF) or
 	    (value >= 0xE000 and value <= 0x10FFFF)):
-		return chr(value)
+		return unichr(value)
 	return None
diff --git a/Lib/fontTools/cffLib/__init__.py b/Lib/fontTools/cffLib/__init__.py
index d4cd7a1..e906540 100644
--- a/Lib/fontTools/cffLib/__init__.py
+++ b/Lib/fontTools/cffLib/__init__.py
@@ -1,17 +1,7 @@
-"""cffLib: read/write Adobe CFF fonts
+"""cffLib.py -- read/write tools for Adobe CFF fonts."""
 
-OpenType fonts with PostScript outlines contain a completely independent
-font file, Adobe's *Compact Font Format*. So dealing with OpenType fonts
-requires also dealing with CFF. This module allows you to read and write
-fonts written in the CFF format.
-
-In 2016, OpenType 1.8 introduced the `CFF2 <https://docs.microsoft.com/en-us/typography/opentype/spec/cff2>`_
-format which, along with other changes, extended the CFF format to deal with
-the demands of variable fonts. This module parses both original CFF and CFF2.
-
-"""
-
-from fontTools.misc.py23 import bytechr, byteord, bytesjoin, tobytes, tostr
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from fontTools.misc import psCharStrings
 from fontTools.misc.arrayTools import unionRect, intRect
@@ -20,7 +10,6 @@
 from fontTools.ttLib.tables.otBase import OTTableWriter
 from fontTools.ttLib.tables.otBase import OTTableReader
 from fontTools.ttLib.tables import otTables as ot
-from io import BytesIO
 import struct
 import logging
 import re
@@ -40,37 +29,8 @@
 
 
 class CFFFontSet(object):
-	"""A CFF font "file" can contain more than one font, although this is
-	extremely rare (and not allowed within OpenType fonts).
-
-	This class is the entry point for parsing a CFF table. To actually
-	manipulate the data inside the CFF font, you will want to access the
-	``CFFFontSet``'s :class:`TopDict` object. To do this, a ``CFFFontSet``
-	object can either be treated as a dictionary (with appropriate
-	``keys()`` and ``values()`` methods) mapping font names to :class:`TopDict`
-	objects, or as a list.
-
-	.. code:: python
-
-		from fontTools import ttLib
-		tt = ttLib.TTFont("Tests/cffLib/data/LinLibertine_RBI.otf")
-		tt["CFF "].cff
-		# <fontTools.cffLib.CFFFontSet object at 0x101e24c90>
-		tt["CFF "].cff[0] # Here's your actual font data
-		# <fontTools.cffLib.TopDict object at 0x1020f1fd0>
-	
-	"""
 
 	def decompile(self, file, otFont, isCFF2=None):
-		"""Parse a binary CFF file into an internal representation. ``file``
-		should be a file handle object. ``otFont`` is the top-level
-		:py:class:`fontTools.ttLib.ttFont.TTFont` object containing this CFF file.
-
-		If ``isCFF2`` is passed and set to ``True`` or ``False``, then the
-		library makes an assertion that the CFF header is of the appropriate
-		version.
-		"""
-
 		self.otFont = otFont
 		sstruct.unpack(cffHeaderFormat, file.read(3), self)
 		if isCFF2 is not None:
@@ -119,7 +79,7 @@
 		"""
 		if hasattr(nameOrIndex, "__index__"):
 			index = nameOrIndex.__index__()
-		elif isinstance(nameOrIndex, str):
+		elif isinstance(nameOrIndex, basestring):
 			name = nameOrIndex
 			try:
 				index = self.fontNames.index(name)
@@ -130,14 +90,6 @@
 		return self.topDictIndex[index]
 
 	def compile(self, file, otFont, isCFF2=None):
-		"""Write the object back into binary representation onto the given file.
-		``file`` should be a file handle object. ``otFont`` is the top-level
-		:py:class:`fontTools.ttLib.ttFont.TTFont` object containing this CFF file.
-
-		If ``isCFF2`` is passed and set to ``True`` or ``False``, then the
-		library makes an assertion that the CFF header is of the appropriate
-		version.
-		"""
 		self.otFont = otFont
 		if isCFF2 is not None:
 			# called from ttLib: assert 'major' value matches expected version
@@ -193,16 +145,6 @@
 		writer.toFile(file)
 
 	def toXML(self, xmlWriter):
-		"""Write the object into XML representation onto the given
-		:class:`fontTools.misc.xmlWriter.XMLWriter`.
-
-		.. code:: python
-
-			writer = xmlWriter.XMLWriter(sys.stdout)
-			tt["CFF "].cff.toXML(writer)
-
-		"""
-
 		xmlWriter.simpletag("major", value=self.major)
 		xmlWriter.newline()
 		xmlWriter.simpletag("minor", value=self.minor)
@@ -222,7 +164,6 @@
 		xmlWriter.newline()
 
 	def fromXML(self, name, attrs, content, otFont=None):
-		"""Reads data from the XML element into the ``CFFFontSet`` object."""
 		self.otFont = otFont
 
 		# set defaults. These will be replaced if there are entries for them
@@ -262,7 +203,7 @@
 				self.topDictIndex = TopDictIndex(None, cff2GetGlyphOrder, None)
 			self.topDictIndex.append(topDict)
 			for element in content:
-				if isinstance(element, str):
+				if isinstance(element, basestring):
 					continue
 				name, attrs, content = element
 				topDict.fromXML(name, attrs, content)
@@ -278,7 +219,7 @@
 			if not hasattr(self, "GlobalSubrs"):
 				self.GlobalSubrs = GlobalSubrsIndex()
 			for element in content:
-				if isinstance(element, str):
+				if isinstance(element, basestring):
 					continue
 				name, attrs, content = element
 				subr = subrCharStringClass()
@@ -290,11 +231,7 @@
 			self.minor = int(attrs['value'])
 
 	def convertCFFToCFF2(self, otFont):
-		"""Converts this object from CFF format to CFF2 format. This conversion
-		is done 'in-place'. The conversion cannot be reversed.
-
-		This assumes a decompiled CFF table. (i.e. that the object has been
-		filled via :meth:`decompile`.)"""
+		# This assumes a decompiled CFF table.
 		self.major = 2
 		cff2GetGlyphOrder = self.otFont.getGlyphOrder
 		topDictData = TopDictIndex(None, cff2GetGlyphOrder, None)
@@ -371,8 +308,7 @@
 
 
 class CFFWriter(object):
-	"""Helper class for serializing CFF data to binary. Used by
-	:meth:`CFFFontSet.compile`."""
+
 	def __init__(self, isCFF2):
 		self.data = []
 		self.isCFF2 = isCFF2
@@ -432,8 +368,6 @@
 
 
 class IndexCompiler(object):
-	"""Base class for writing CFF `INDEX data <https://docs.microsoft.com/en-us/typography/opentype/spec/cff2#5-index-data>`_
-	to binary."""
 
 	def __init__(self, items, strings, parent, isCFF2=None):
 		if isCFF2 is None and hasattr(parent, "isCFF2"):
@@ -513,7 +447,6 @@
 
 
 class TopDictIndexCompiler(IndexCompiler):
-	"""Helper class for writing the TopDict to binary."""
 
 	def getItems(self, items, strings):
 		out = []
@@ -549,9 +482,6 @@
 
 
 class FDArrayIndexCompiler(IndexCompiler):
-	"""Helper class for writing the
-	`Font DICT INDEX <https://docs.microsoft.com/en-us/typography/opentype/spec/cff2#10-font-dict-index-font-dicts-and-fdselect>`_
-	to binary."""
 
 	def getItems(self, items, strings):
 		out = []
@@ -590,8 +520,6 @@
 
 
 class GlobalSubrsCompiler(IndexCompiler):
-	"""Helper class for writing the `global subroutine INDEX <https://docs.microsoft.com/en-us/typography/opentype/spec/cff2#9-local-and-global-subr-indexes>`_
-	to binary."""
 
 	def getItems(self, items, strings):
 		out = []
@@ -602,17 +530,14 @@
 
 
 class SubrsCompiler(GlobalSubrsCompiler):
-	"""Helper class for writing the `local subroutine INDEX <https://docs.microsoft.com/en-us/typography/opentype/spec/cff2#9-local-and-global-subr-indexes>`_
-	to binary."""
-	
+
 	def setPos(self, pos, endPos):
 		offset = pos - self.parent.pos
 		self.parent.rawDict["Subrs"] = offset
 
 
 class CharStringsCompiler(GlobalSubrsCompiler):
-	"""Helper class for writing the `CharStrings INDEX <https://docs.microsoft.com/en-us/typography/opentype/spec/cff2#9-local-and-global-subr-indexes>`_
-	to binary."""
+
 	def getItems(self, items, strings):
 		out = []
 		for cs in items:
@@ -625,9 +550,8 @@
 
 
 class Index(object):
-	"""This class represents what the CFF spec calls an INDEX (an array of
-	variable-sized objects). `Index` items can be addressed and set using
-	Python list indexing."""
+
+	"""This class represents what the CFF spec calls an INDEX."""
 
 	compilerClass = IndexCompiler
 
@@ -685,50 +609,16 @@
 		return data
 
 	def append(self, item):
-		"""Add an item to an INDEX."""
 		self.items.append(item)
 
 	def getCompiler(self, strings, parent, isCFF2=None):
 		return self.compilerClass(self, strings, parent, isCFF2=isCFF2)
 
 	def clear(self):
-		"""Empty the INDEX."""
 		del self.items[:]
 
 
 class GlobalSubrsIndex(Index):
-	"""This index contains all the global subroutines in the font. A global
-	subroutine is a set of ``CharString`` data which is accessible to any
-	glyph in the font, and are used to store repeated instructions - for
-	example, components may be encoded as global subroutines, but so could
-	hinting instructions.
-
-	Remember that when interpreting a ``callgsubr`` instruction (or indeed
-	a ``callsubr`` instruction) that you will need to add the "subroutine
-	number bias" to number given:
-
-	.. code:: python
-
-		tt = ttLib.TTFont("Almendra-Bold.otf")
-		u = tt["CFF "].cff[0].CharStrings["udieresis"]
-		u.decompile()
-
-		u.toXML(XMLWriter(sys.stdout))
-		# <some stuff>
-		# -64 callgsubr <-- Subroutine which implements the dieresis mark
-		# <other stuff>
-
-		tt["CFF "].cff[0].GlobalSubrs[-64] # <-- WRONG
-		# <T2CharString (bytecode) at 103451d10>
-
-		tt["CFF "].cff[0].GlobalSubrs[-64 + 107] # <-- RIGHT
-		# <T2CharString (source) at 103451390>
-
-	("The bias applied depends on the number of subrs (gsubrs). If the number of
-	subrs (gsubrs) is less than 1240, the bias is 107. Otherwise if it is less
-	than 33900, it is 1131; otherwise it is 32768.",
-	`Subroutine Operators <https://docs.microsoft.com/en-us/typography/opentype/otspec180/cff2charstr#section4.4>`)
-	"""
 
 	compilerClass = GlobalSubrsCompiler
 	subrClass = psCharStrings.T2CharString
@@ -758,15 +648,6 @@
 		return self.subrClass(data, private=private, globalSubrs=self.globalSubrs)
 
 	def toXML(self, xmlWriter):
-		"""Write the subroutines index into XML representation onto the given
-		:class:`fontTools.misc.xmlWriter.XMLWriter`.
-
-		.. code:: python
-
-			writer = xmlWriter.XMLWriter(sys.stdout)
-			tt["CFF "].cff[0].GlobalSubrs.toXML(writer)
-
-		"""
 		xmlWriter.comment(
 			"The 'index' attribute is only for humans; "
 			"it is ignored when parsed.")
@@ -797,26 +678,10 @@
 
 
 class SubrsIndex(GlobalSubrsIndex):
-	"""This index contains a glyph's local subroutines. A local subroutine is a
-	private set of ``CharString`` data which is accessible only to the glyph to
-	which the index is attached."""
-
 	compilerClass = SubrsCompiler
 
 
 class TopDictIndex(Index):
-	"""This index represents the array of ``TopDict`` structures in the font
-	(again, usually only one entry is present). Hence the following calls are
-	equivalent:
-
-	.. code:: python
-
-		tt["CFF "].cff[0]
-		# <fontTools.cffLib.TopDict object at 0x102ed6e50>
-		tt["CFF "].cff.topDictIndex[0]
-		# <fontTools.cffLib.TopDict object at 0x102ed6e50>
-
-	"""
 
 	compilerClass = TopDictIndexCompiler
 
@@ -880,7 +745,7 @@
 			return
 		fontDict = FontDict()
 		for element in content:
-			if isinstance(element, str):
+			if isinstance(element, basestring):
 				continue
 			name, attrs, content = element
 			fontDict.fromXML(name, attrs, content)
@@ -1005,20 +870,6 @@
 
 
 class CharStrings(object):
-	"""The ``CharStrings`` in the font represent the instructions for drawing 
-	each glyph. This object presents a dictionary interface to the font's
-	CharStrings, indexed by glyph name:
-
-	.. code:: python
-	
-		tt["CFF "].cff[0].CharStrings["a"]
-		# <T2CharString (bytecode) at 103451e90>
-
-	See :class:`fontTools.misc.psCharStrings.T1CharString` and
-	:class:`fontTools.misc.psCharStrings.T2CharString` for how to decompile,
-	compile and interpret the glyph drawing instructions in the returned objects.
-
-	"""
 
 	def __init__(self, file, charset, globalSubrs, private, fdSelect, fdArray,
 			isCFF2=None):
@@ -1107,7 +958,7 @@
 
 	def fromXML(self, name, attrs, content):
 		for element in content:
-			if isinstance(element, str):
+			if isinstance(element, basestring):
 				continue
 			name, attrs, content = element
 			if name != "CharString":
@@ -1246,7 +1097,7 @@
 		return tobytes(value, encoding='ascii')
 
 	def xmlWrite(self, xmlWriter, name, value):
-		xmlWriter.simpletag(name, value=tostr(value, encoding="ascii"))
+		xmlWriter.simpletag(name, value=tounicode(value, encoding="ascii"))
 		xmlWriter.newline()
 
 	def xmlRead(self, name, attrs, content, parent):
@@ -1262,7 +1113,7 @@
 		return tobytes(value, encoding='latin1')
 
 	def xmlWrite(self, xmlWriter, name, value):
-		value = tostr(value, encoding="latin1")
+		value = tounicode(value, encoding="latin1")
 		if name in ['Notice', 'Copyright']:
 			value = re.sub(r"[\r\n]\s+", " ", value)
 		xmlWriter.simpletag(name, value=value)
@@ -1283,7 +1134,7 @@
 def parseBlendList(s):
 	valueList = []
 	for element in s:
-		if isinstance(element, str):
+		if isinstance(element, basestring):
 			continue
 		name, attrs, content = element
 		blendList = attrs["value"].split()
@@ -1359,7 +1210,7 @@
 	def xmlRead(self, name, attrs, content, parent):
 		ob = self.getClass()()
 		for element in content:
-			if isinstance(element, str):
+			if isinstance(element, basestring):
 				continue
 			name, attrs, content = element
 			ob.fromXML(name, attrs, content)
@@ -1469,20 +1320,6 @@
 				raise NotImplementedError
 			assert len(charset) == numGlyphs
 			log.log(DEBUG, "    charset end at %s", file.tell())
-			# make sure glyph names are unique
-			allNames = {}
-			newCharset = []
-			for glyphName in charset:
-				if glyphName in allNames:
-					# make up a new glyphName that's unique
-					n = allNames[glyphName]
-					while (glyphName + "#" + str(n)) in allNames:
-						n += 1
-					allNames[glyphName] = n + 1
-					glyphName = glyphName + "#" + str(n)
-				allNames[glyphName] = 1
-				newCharset.append(glyphName)
-			charset = newCharset
 		else:  # offset == 0 -> no charset data.
 			if isCID or "CharStrings" not in parent.rawDict:
 				# We get here only when processing fontDicts from the FDArray of
@@ -1651,7 +1488,7 @@
 class EncodingCompiler(object):
 
 	def __init__(self, strings, encoding, parent):
-		assert not isinstance(encoding, str)
+		assert not isinstance(encoding, basestring)
 		data0 = packEncoding0(parent.dictObj.charset, encoding, parent.strings)
 		data1 = packEncoding1(parent.dictObj.charset, encoding, parent.strings)
 		if len(data0) < len(data1):
@@ -1722,7 +1559,7 @@
 			return attrs["name"]
 		encoding = [".notdef"] * 256
 		for element in content:
-			if isinstance(element, str):
+			if isinstance(element, basestring):
 				continue
 			name, attrs, content = element
 			code = safeEval(attrs["code"])
@@ -1834,7 +1671,7 @@
 	def xmlRead(self, name, attrs, content, parent):
 		fdArray = FDArrayIndex()
 		for element in content:
-			if isinstance(element, str):
+			if isinstance(element, basestring):
 				continue
 			name, attrs, content = element
 			fdArray.fromXML(name, attrs, content)
@@ -2106,8 +1943,6 @@
 	(11,		'StdVW',		'number',	None,	None),
 	((12, 12),	'StemSnapH',		'delta',	None,	None),
 	((12, 13),	'StemSnapV',		'delta',	None,	None),
-	((12, 17),	'LanguageGroup',	'number',	0,	None),
-	((12, 18),	'ExpansionFactor',	'number',	0.06,	None),
 	(19,		'Subrs',		'number',	None,	SubrsConverter()),
 ]
 
@@ -2239,33 +2074,27 @@
 
 
 	def arg_delta_blend(self, value):
-		"""A delta list with blend lists has to be *all* blend lists.
-
-		The value is a list is arranged as follows::
-
-			[
-				[V0, d0..dn]
-				[V1, d0..dn]
-				...
-				[Vm, d0..dn]
-			]
-
-		``V`` is the absolute coordinate value from the default font, and ``d0-dn``
-		are the delta values from the *n* regions. Each ``V`` is an absolute
-		coordinate from the default font.
-
-		We want to return a list::
-
-			[
-				[v0, v1..vm]
-				[d0..dn]
-				...
-				[d0..dn]
-				numBlends
-				blendOp
-			]
-
-		where each ``v`` is relative to the previous default font value.
+		""" A delta list with blend lists has to be *all* blend lists.
+		The value is a list is arranged as follows.
+		[
+		   [V0, d0..dn] 
+		   [V1, d0..dn]
+		   ...
+		   [Vm, d0..dn]
+		]
+		V is the absolute coordinate value from the default font, and d0-dn are
+		the delta values from the n regions. Each V is an absolute coordinate
+		from the default font.
+		We want to return a list:
+		[
+		   [v0, v1..vm] 
+		   [d0..dn]
+		   ...
+		   [d0..dn]
+		   numBlends
+		   blendOp
+		]
+		where each v is relative to the previous default font value.
 		"""
 		numMasters = len(value[0])
 		numBlends = len(value)
@@ -2335,7 +2164,7 @@
 					self.rawDict["charset"] = charsetCode
 			if hasattr(self.dictObj, "Encoding") and self.dictObj.Encoding:
 				encoding = self.dictObj.Encoding
-				if not isinstance(encoding, str):
+				if not isinstance(encoding, basestring):
 					children.append(EncodingCompiler(strings, encoding, self))
 		else:
 			if hasattr(self.dictObj, "VarStore"):
@@ -2514,30 +2343,6 @@
 
 
 class TopDict(BaseDict):
-	"""The ``TopDict`` represents the top-level dictionary holding font
-	information. CFF2 tables contain a restricted set of top-level entries
-	as described `here <https://docs.microsoft.com/en-us/typography/opentype/spec/cff2#7-top-dict-data>`_,
-	but CFF tables may contain a wider range of information. This information
-	can be accessed through attributes or through the dictionary returned
-	through the ``rawDict`` property:
-
-	.. code:: python
-
-		font = tt["CFF "].cff[0]
-		font.FamilyName
-		# 'Linux Libertine O'
-		font.rawDict["FamilyName"]
-		# 'Linux Libertine O'
-
-	More information is available in the CFF file's private dictionary, accessed
-	via the ``Private`` property:
-
-	.. code:: python
-
-		tt["CFF "].cff[0].Private.BlueValues
-		# [-15, 0, 515, 515, 666, 666]
-	
-	"""
 
 	defaults = buildDefaults(topDictOperators)
 	converters = buildConverters(topDictOperators)
@@ -2559,7 +2364,6 @@
 			self.order = buildOrder(topDictOperators)
 
 	def getGlyphOrder(self):
-		"""Returns a list of glyph names in the CFF font."""
 		return self.charset
 
 	def postDecompile(self):
diff --git a/Lib/fontTools/cffLib/specializer.py b/Lib/fontTools/cffLib/specializer.py
index fbfefa9..794a2e9 100644
--- a/Lib/fontTools/cffLib/specializer.py
+++ b/Lib/fontTools/cffLib/specializer.py
@@ -1,23 +1,14 @@
 # -*- coding: utf-8 -*-
 
-"""T2CharString operator specializer and generalizer.
+"""T2CharString operator specializer and generalizer."""
 
-PostScript glyph drawing operations can be expressed in multiple different
-ways. For example, as well as the ``lineto`` operator, there is also a
-``hlineto`` operator which draws a horizontal line, removing the need to
-specify a ``dx`` coordinate, and a ``vlineto`` operator which draws a
-vertical line, removing the need to specify a ``dy`` coordinate. As well
-as decompiling :class:`fontTools.misc.psCharStrings.T2CharString` objects
-into lists of operations, this module allows for conversion between general
-and specific forms of the operation.
-
-"""
-
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.cffLib import maxStackLimit
 
 
 def stringToProgram(string):
-	if isinstance(string, str):
+	if isinstance(string, basestring):
 		string = string.split()
 	program = []
 	for token in string:
@@ -69,7 +60,7 @@
 	it = iter(program)
 
 	for token in it:
-		if not isinstance(token, str):
+		if not isinstance(token, basestring):
 			stack.append(token)
 			continue
 
diff --git a/Lib/fontTools/cffLib/width.py b/Lib/fontTools/cffLib/width.py
index 00b859b..a9e5532 100644
--- a/Lib/fontTools/cffLib/width.py
+++ b/Lib/fontTools/cffLib/width.py
@@ -1,16 +1,13 @@
 # -*- coding: utf-8 -*-
 
-"""T2CharString glyph width optimizer.
+"""T2CharString glyph width optimizer."""
 
-CFF glyphs whose width equals the CFF Private dictionary's ``defaultWidthX``
-value do not need to specify their width in their charstring, saving bytes.
-This module determines the optimum ``defaultWidthX`` and ``nominalWidthX``
-values for a font, when provided with a list of glyph widths."""
-
-from fontTools.ttLib import TTFont
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools.ttLib import TTFont, getTableClass
 from collections import defaultdict
 from operator import add
-from functools import reduce
+from functools import partial, reduce
 
 
 class missingdict(dict):
@@ -150,34 +147,17 @@
 
 	return default, nominal
 
-def main(args=None):
-	"""Calculate optimum defaultWidthX/nominalWidthX values"""
-
-	import argparse
-	parser = argparse.ArgumentParser(
-		"fonttools cffLib.width",
-		description=main.__doc__,
-	)
-	parser.add_argument('inputs', metavar='FILE', type=str, nargs='+',
-		help="Input TTF files")
-	parser.add_argument('-b', '--brute-force', dest="brute", action="store_true",
-		help="Use brute-force approach (VERY slow)")
-
-	args = parser.parse_args(args)
-
-	for fontfile in args.inputs:
-		font = TTFont(fontfile)
-		hmtx = font['hmtx']
-		widths = [m[0] for m in hmtx.metrics.values()]
-		if args.brute:
-			default, nominal = optimizeWidthsBruteforce(widths)
-		else:
-			default, nominal = optimizeWidths(widths)
-		print("glyphs=%d default=%d nominal=%d byteCost=%d" % (len(widths), default, nominal, byteCost(widths, default, nominal)))
 
 if __name__ == '__main__':
 	import sys
 	if len(sys.argv) == 1:
 		import doctest
 		sys.exit(doctest.testmod().failed)
-	main()
+	for fontfile in sys.argv[1:]:
+		font = TTFont(fontfile)
+		hmtx = font['hmtx']
+		widths = [m[0] for m in hmtx.metrics.values()]
+		default, nominal = optimizeWidths(widths)
+		print("glyphs=%d default=%d nominal=%d byteCost=%d" % (len(widths), default, nominal, byteCost(widths, default, nominal)))
+		#default, nominal = optimizeWidthsBruteforce(widths)
+		#print("glyphs=%d default=%d nominal=%d byteCost=%d" % (len(widths), default, nominal, byteCost(widths, default, nominal)))
diff --git a/Lib/fontTools/colorLib/__init__.py b/Lib/fontTools/colorLib/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/Lib/fontTools/colorLib/__init__.py
+++ /dev/null
diff --git a/Lib/fontTools/colorLib/builder.py b/Lib/fontTools/colorLib/builder.py
deleted file mode 100644
index 821244a..0000000
--- a/Lib/fontTools/colorLib/builder.py
+++ /dev/null
@@ -1,637 +0,0 @@
-"""
-colorLib.builder: Build COLR/CPAL tables from scratch
-
-"""
-import collections
-import copy
-import enum
-from functools import partial
-from math import ceil, log
-from typing import (
-    Any,
-    Dict,
-    Generator,
-    Iterable,
-    List,
-    Mapping,
-    Optional,
-    Sequence,
-    Tuple,
-    Type,
-    TypeVar,
-    Union,
-)
-from fontTools.misc.fixedTools import fixedToFloat
-from fontTools.ttLib.tables import C_O_L_R_
-from fontTools.ttLib.tables import C_P_A_L_
-from fontTools.ttLib.tables import _n_a_m_e
-from fontTools.ttLib.tables import otTables as ot
-from fontTools.ttLib.tables.otTables import (
-    ExtendMode,
-    CompositeMode,
-    VariableValue,
-    VariableFloat,
-    VariableInt,
-)
-from .errors import ColorLibError
-from .geometry import round_start_circle_stable_containment
-from .table_builder import (
-    convertTupleClass,
-    BuildCallback,
-    TableBuilder,
-)
-
-
-# TODO move type aliases to colorLib.types?
-T = TypeVar("T")
-_Kwargs = Mapping[str, Any]
-_PaintInput = Union[int, _Kwargs, ot.Paint, Tuple[str, "_PaintInput"]]
-_PaintInputList = Sequence[_PaintInput]
-_ColorGlyphsDict = Dict[str, Union[_PaintInputList, _PaintInput]]
-_ColorGlyphsV0Dict = Dict[str, Sequence[Tuple[str, int]]]
-
-
-MAX_PAINT_COLR_LAYER_COUNT = 255
-_DEFAULT_ALPHA = VariableFloat(1.0)
-_MAX_REUSE_LEN = 32
-
-
-def _beforeBuildPaintVarRadialGradient(paint, source, srcMapFn=lambda v: v):
-    # normalize input types (which may or may not specify a varIdx)
-    x0 = convertTupleClass(VariableFloat, source["x0"])
-    y0 = convertTupleClass(VariableFloat, source["y0"])
-    r0 = convertTupleClass(VariableFloat, source["r0"])
-    x1 = convertTupleClass(VariableFloat, source["x1"])
-    y1 = convertTupleClass(VariableFloat, source["y1"])
-    r1 = convertTupleClass(VariableFloat, source["r1"])
-
-    # TODO apparently no builder_test confirms this works (?)
-
-    # avoid abrupt change after rounding when c0 is near c1's perimeter
-    c = round_start_circle_stable_containment(
-        (x0.value, y0.value), r0.value, (x1.value, y1.value), r1.value
-    )
-    x0, y0 = x0._replace(value=c.centre[0]), y0._replace(value=c.centre[1])
-    r0 = r0._replace(value=c.radius)
-
-    # update source to ensure paint is built with corrected values
-    source["x0"] = srcMapFn(x0)
-    source["y0"] = srcMapFn(y0)
-    source["r0"] = srcMapFn(r0)
-    source["x1"] = srcMapFn(x1)
-    source["y1"] = srcMapFn(y1)
-    source["r1"] = srcMapFn(r1)
-
-    return paint, source
-
-
-def _beforeBuildPaintRadialGradient(paint, source):
-    return _beforeBuildPaintVarRadialGradient(paint, source, lambda v: v.value)
-
-
-def _defaultColorIndex():
-    colorIndex = ot.ColorIndex()
-    colorIndex.Alpha = _DEFAULT_ALPHA.value
-    return colorIndex
-
-
-def _defaultVarColorIndex():
-    colorIndex = ot.VarColorIndex()
-    colorIndex.Alpha = _DEFAULT_ALPHA
-    return colorIndex
-
-
-def _defaultColorLine():
-    colorLine = ot.ColorLine()
-    colorLine.Extend = ExtendMode.PAD
-    return colorLine
-
-
-def _defaultVarColorLine():
-    colorLine = ot.VarColorLine()
-    colorLine.Extend = ExtendMode.PAD
-    return colorLine
-
-
-def _buildPaintCallbacks():
-    return {
-        (
-            BuildCallback.BEFORE_BUILD,
-            ot.Paint,
-            ot.PaintFormat.PaintRadialGradient,
-        ): _beforeBuildPaintRadialGradient,
-        (
-            BuildCallback.BEFORE_BUILD,
-            ot.Paint,
-            ot.PaintFormat.PaintVarRadialGradient,
-        ): _beforeBuildPaintVarRadialGradient,
-        (BuildCallback.CREATE_DEFAULT, ot.ColorIndex): _defaultColorIndex,
-        (BuildCallback.CREATE_DEFAULT, ot.VarColorIndex): _defaultVarColorIndex,
-        (BuildCallback.CREATE_DEFAULT, ot.ColorLine): _defaultColorLine,
-        (BuildCallback.CREATE_DEFAULT, ot.VarColorLine): _defaultVarColorLine,
-    }
-
-
-def populateCOLRv0(
-    table: ot.COLR,
-    colorGlyphsV0: _ColorGlyphsV0Dict,
-    glyphMap: Optional[Mapping[str, int]] = None,
-):
-    """Build v0 color layers and add to existing COLR table.
-
-    Args:
-        table: a raw otTables.COLR() object (not ttLib's table_C_O_L_R_).
-        colorGlyphsV0: map of base glyph names to lists of (layer glyph names,
-            color palette index) tuples.
-        glyphMap: a map from glyph names to glyph indices, as returned from
-            TTFont.getReverseGlyphMap(), to optionally sort base records by GID.
-    """
-    if glyphMap is not None:
-        colorGlyphItems = sorted(
-            colorGlyphsV0.items(), key=lambda item: glyphMap[item[0]]
-        )
-    else:
-        colorGlyphItems = colorGlyphsV0.items()
-    baseGlyphRecords = []
-    layerRecords = []
-    for baseGlyph, layers in colorGlyphItems:
-        baseRec = ot.BaseGlyphRecord()
-        baseRec.BaseGlyph = baseGlyph
-        baseRec.FirstLayerIndex = len(layerRecords)
-        baseRec.NumLayers = len(layers)
-        baseGlyphRecords.append(baseRec)
-
-        for layerGlyph, paletteIndex in layers:
-            layerRec = ot.LayerRecord()
-            layerRec.LayerGlyph = layerGlyph
-            layerRec.PaletteIndex = paletteIndex
-            layerRecords.append(layerRec)
-
-    table.BaseGlyphRecordCount = len(baseGlyphRecords)
-    table.BaseGlyphRecordArray = ot.BaseGlyphRecordArray()
-    table.BaseGlyphRecordArray.BaseGlyphRecord = baseGlyphRecords
-    table.LayerRecordArray = ot.LayerRecordArray()
-    table.LayerRecordArray.LayerRecord = layerRecords
-    table.LayerRecordCount = len(layerRecords)
-
-
-def buildCOLR(
-    colorGlyphs: _ColorGlyphsDict,
-    version: Optional[int] = None,
-    glyphMap: Optional[Mapping[str, int]] = None,
-    varStore: Optional[ot.VarStore] = None,
-) -> C_O_L_R_.table_C_O_L_R_:
-    """Build COLR table from color layers mapping.
-    Args:
-        colorGlyphs: map of base glyph name to, either list of (layer glyph name,
-            color palette index) tuples for COLRv0; or a single Paint (dict) or
-            list of Paint for COLRv1.
-        version: the version of COLR table. If None, the version is determined
-            by the presence of COLRv1 paints or variation data (varStore), which
-            require version 1; otherwise, if all base glyphs use only simple color
-            layers, version 0 is used.
-        glyphMap: a map from glyph names to glyph indices, as returned from
-            TTFont.getReverseGlyphMap(), to optionally sort base records by GID.
-        varStore: Optional ItemVarationStore for deltas associated with v1 layer.
-    Return:
-        A new COLR table.
-    """
-    self = C_O_L_R_.table_C_O_L_R_()
-
-    if varStore is not None and version == 0:
-        raise ValueError("Can't add VarStore to COLRv0")
-
-    if version in (None, 0) and not varStore:
-        # split color glyphs into v0 and v1 and encode separately
-        colorGlyphsV0, colorGlyphsV1 = _split_color_glyphs_by_version(colorGlyphs)
-        if version == 0 and colorGlyphsV1:
-            raise ValueError("Can't encode COLRv1 glyphs in COLRv0")
-    else:
-        # unless explicitly requested for v1 or have variations, in which case
-        # we encode all color glyph as v1
-        colorGlyphsV0, colorGlyphsV1 = None, colorGlyphs
-
-    colr = ot.COLR()
-
-    if colorGlyphsV0:
-        populateCOLRv0(colr, colorGlyphsV0, glyphMap)
-    else:
-        colr.BaseGlyphRecordCount = colr.LayerRecordCount = 0
-        colr.BaseGlyphRecordArray = colr.LayerRecordArray = None
-
-    if colorGlyphsV1:
-        colr.LayerV1List, colr.BaseGlyphV1List = buildColrV1(colorGlyphsV1, glyphMap)
-
-    if version is None:
-        version = 1 if (varStore or colorGlyphsV1) else 0
-    elif version not in (0, 1):
-        raise NotImplementedError(version)
-    self.version = colr.Version = version
-
-    if version == 0:
-        self.ColorLayers = self._decompileColorLayersV0(colr)
-    else:
-        colr.VarStore = varStore
-        self.table = colr
-
-    return self
-
-
-class ColorPaletteType(enum.IntFlag):
-    USABLE_WITH_LIGHT_BACKGROUND = 0x0001
-    USABLE_WITH_DARK_BACKGROUND = 0x0002
-
-    @classmethod
-    def _missing_(cls, value):
-        # enforce reserved bits
-        if isinstance(value, int) and (value < 0 or value & 0xFFFC != 0):
-            raise ValueError(f"{value} is not a valid {cls.__name__}")
-        return super()._missing_(value)
-
-
-# None, 'abc' or {'en': 'abc', 'de': 'xyz'}
-_OptionalLocalizedString = Union[None, str, Dict[str, str]]
-
-
-def buildPaletteLabels(
-    labels: Iterable[_OptionalLocalizedString], nameTable: _n_a_m_e.table__n_a_m_e
-) -> List[Optional[int]]:
-    return [
-        nameTable.addMultilingualName(l, mac=False)
-        if isinstance(l, dict)
-        else C_P_A_L_.table_C_P_A_L_.NO_NAME_ID
-        if l is None
-        else nameTable.addMultilingualName({"en": l}, mac=False)
-        for l in labels
-    ]
-
-
-def buildCPAL(
-    palettes: Sequence[Sequence[Tuple[float, float, float, float]]],
-    paletteTypes: Optional[Sequence[ColorPaletteType]] = None,
-    paletteLabels: Optional[Sequence[_OptionalLocalizedString]] = None,
-    paletteEntryLabels: Optional[Sequence[_OptionalLocalizedString]] = None,
-    nameTable: Optional[_n_a_m_e.table__n_a_m_e] = None,
-) -> C_P_A_L_.table_C_P_A_L_:
-    """Build CPAL table from list of color palettes.
-
-    Args:
-        palettes: list of lists of colors encoded as tuples of (R, G, B, A) floats
-            in the range [0..1].
-        paletteTypes: optional list of ColorPaletteType, one for each palette.
-        paletteLabels: optional list of palette labels. Each lable can be either:
-            None (no label), a string (for for default English labels), or a
-            localized string (as a dict keyed with BCP47 language codes).
-        paletteEntryLabels: optional list of palette entry labels, one for each
-            palette entry (see paletteLabels).
-        nameTable: optional name table where to store palette and palette entry
-            labels. Required if either paletteLabels or paletteEntryLabels is set.
-
-    Return:
-        A new CPAL v0 or v1 table, if custom palette types or labels are specified.
-    """
-    if len({len(p) for p in palettes}) != 1:
-        raise ColorLibError("color palettes have different lengths")
-
-    if (paletteLabels or paletteEntryLabels) and not nameTable:
-        raise TypeError(
-            "nameTable is required if palette or palette entries have labels"
-        )
-
-    cpal = C_P_A_L_.table_C_P_A_L_()
-    cpal.numPaletteEntries = len(palettes[0])
-
-    cpal.palettes = []
-    for i, palette in enumerate(palettes):
-        colors = []
-        for j, color in enumerate(palette):
-            if not isinstance(color, tuple) or len(color) != 4:
-                raise ColorLibError(
-                    f"In palette[{i}][{j}]: expected (R, G, B, A) tuple, got {color!r}"
-                )
-            if any(v > 1 or v < 0 for v in color):
-                raise ColorLibError(
-                    f"palette[{i}][{j}] has invalid out-of-range [0..1] color: {color!r}"
-                )
-            # input colors are RGBA, CPAL encodes them as BGRA
-            red, green, blue, alpha = color
-            colors.append(
-                C_P_A_L_.Color(*(round(v * 255) for v in (blue, green, red, alpha)))
-            )
-        cpal.palettes.append(colors)
-
-    if any(v is not None for v in (paletteTypes, paletteLabels, paletteEntryLabels)):
-        cpal.version = 1
-
-        if paletteTypes is not None:
-            if len(paletteTypes) != len(palettes):
-                raise ColorLibError(
-                    f"Expected {len(palettes)} paletteTypes, got {len(paletteTypes)}"
-                )
-            cpal.paletteTypes = [ColorPaletteType(t).value for t in paletteTypes]
-        else:
-            cpal.paletteTypes = [C_P_A_L_.table_C_P_A_L_.DEFAULT_PALETTE_TYPE] * len(
-                palettes
-            )
-
-        if paletteLabels is not None:
-            if len(paletteLabels) != len(palettes):
-                raise ColorLibError(
-                    f"Expected {len(palettes)} paletteLabels, got {len(paletteLabels)}"
-                )
-            cpal.paletteLabels = buildPaletteLabels(paletteLabels, nameTable)
-        else:
-            cpal.paletteLabels = [C_P_A_L_.table_C_P_A_L_.NO_NAME_ID] * len(palettes)
-
-        if paletteEntryLabels is not None:
-            if len(paletteEntryLabels) != cpal.numPaletteEntries:
-                raise ColorLibError(
-                    f"Expected {cpal.numPaletteEntries} paletteEntryLabels, "
-                    f"got {len(paletteEntryLabels)}"
-                )
-            cpal.paletteEntryLabels = buildPaletteLabels(paletteEntryLabels, nameTable)
-        else:
-            cpal.paletteEntryLabels = [
-                C_P_A_L_.table_C_P_A_L_.NO_NAME_ID
-            ] * cpal.numPaletteEntries
-    else:
-        cpal.version = 0
-
-    return cpal
-
-
-# COLR v1 tables
-# See draft proposal at: https://github.com/googlefonts/colr-gradients-spec
-
-
-def _is_colrv0_layer(layer: Any) -> bool:
-    # Consider as COLRv0 layer any sequence of length 2 (be it tuple or list) in which
-    # the first element is a str (the layerGlyph) and the second element is an int
-    # (CPAL paletteIndex).
-    # https://github.com/googlefonts/ufo2ft/issues/426
-    try:
-        layerGlyph, paletteIndex = layer
-    except (TypeError, ValueError):
-        return False
-    else:
-        return isinstance(layerGlyph, str) and isinstance(paletteIndex, int)
-
-
-def _split_color_glyphs_by_version(
-    colorGlyphs: _ColorGlyphsDict,
-) -> Tuple[_ColorGlyphsV0Dict, _ColorGlyphsDict]:
-    colorGlyphsV0 = {}
-    colorGlyphsV1 = {}
-    for baseGlyph, layers in colorGlyphs.items():
-        if all(_is_colrv0_layer(l) for l in layers):
-            colorGlyphsV0[baseGlyph] = layers
-        else:
-            colorGlyphsV1[baseGlyph] = layers
-
-    # sanity check
-    assert set(colorGlyphs) == (set(colorGlyphsV0) | set(colorGlyphsV1))
-
-    return colorGlyphsV0, colorGlyphsV1
-
-
-def _reuse_ranges(num_layers: int) -> Generator[Tuple[int, int], None, None]:
-    # TODO feels like something itertools might have already
-    for lbound in range(num_layers):
-        # Reuse of very large #s of layers is relatively unlikely
-        # +2: we want sequences of at least 2
-        # otData handles single-record duplication
-        for ubound in range(
-            lbound + 2, min(num_layers + 1, lbound + 2 + _MAX_REUSE_LEN)
-        ):
-            yield (lbound, ubound)
-
-
-class LayerV1ListBuilder:
-    slices: List[ot.Paint]
-    layers: List[ot.Paint]
-    reusePool: Mapping[Tuple[Any, ...], int]
-    tuples: Mapping[int, Tuple[Any, ...]]
-    keepAlive: List[ot.Paint]  # we need id to remain valid
-
-    def __init__(self):
-        self.slices = []
-        self.layers = []
-        self.reusePool = {}
-        self.tuples = {}
-        self.keepAlive = []
-
-        # We need to intercept construction of PaintColrLayers
-        callbacks = _buildPaintCallbacks()
-        callbacks[
-            (
-                BuildCallback.BEFORE_BUILD,
-                ot.Paint,
-                ot.PaintFormat.PaintColrLayers,
-            )
-        ] = self._beforeBuildPaintColrLayers
-        self.tableBuilder = TableBuilder(callbacks)
-
-    def _paint_tuple(self, paint: ot.Paint):
-        # start simple, who even cares about cyclic graphs or interesting field types
-        def _tuple_safe(value):
-            if isinstance(value, enum.Enum):
-                return value
-            elif hasattr(value, "__dict__"):
-                return tuple(
-                    (k, _tuple_safe(v)) for k, v in sorted(value.__dict__.items())
-                )
-            elif isinstance(value, collections.abc.MutableSequence):
-                return tuple(_tuple_safe(e) for e in value)
-            return value
-
-        # Cache the tuples for individual Paint instead of the whole sequence
-        # because the seq could be a transient slice
-        result = self.tuples.get(id(paint), None)
-        if result is None:
-            result = _tuple_safe(paint)
-            self.tuples[id(paint)] = result
-            self.keepAlive.append(paint)
-        return result
-
-    def _as_tuple(self, paints: Sequence[ot.Paint]) -> Tuple[Any, ...]:
-        return tuple(self._paint_tuple(p) for p in paints)
-
-    # COLR layers is unusual in that it modifies shared state
-    # so we need a callback into an object
-    def _beforeBuildPaintColrLayers(self, dest, source):
-        paint = ot.Paint()
-        paint.Format = int(ot.PaintFormat.PaintColrLayers)
-        self.slices.append(paint)
-
-        # Sketchy gymnastics: a sequence input will have dropped it's layers
-        # into NumLayers; get it back
-        if isinstance(source.get("NumLayers", None), collections.abc.Sequence):
-            layers = source["NumLayers"]
-        else:
-            layers = source["Layers"]
-
-        # Convert maps seqs or whatever into typed objects
-        layers = [self.buildPaint(l) for l in layers]
-
-        # No reason to have a colr layers with just one entry
-        if len(layers) == 1:
-            return layers[0], {}
-
-        # Look for reuse, with preference to longer sequences
-        # This may make the layer list smaller
-        found_reuse = True
-        while found_reuse:
-            found_reuse = False
-
-            ranges = sorted(
-                _reuse_ranges(len(layers)),
-                key=lambda t: (t[1] - t[0], t[1], t[0]),
-                reverse=True,
-            )
-            for lbound, ubound in ranges:
-                reuse_lbound = self.reusePool.get(
-                    self._as_tuple(layers[lbound:ubound]), -1
-                )
-                if reuse_lbound == -1:
-                    continue
-                new_slice = ot.Paint()
-                new_slice.Format = int(ot.PaintFormat.PaintColrLayers)
-                new_slice.NumLayers = ubound - lbound
-                new_slice.FirstLayerIndex = reuse_lbound
-                layers = layers[:lbound] + [new_slice] + layers[ubound:]
-                found_reuse = True
-                break
-
-        # The layer list is now final; if it's too big we need to tree it
-        is_tree = len(layers) > MAX_PAINT_COLR_LAYER_COUNT
-        layers = _build_n_ary_tree(layers, n=MAX_PAINT_COLR_LAYER_COUNT)
-
-        # We now have a tree of sequences with Paint leaves.
-        # Convert the sequences into PaintColrLayers.
-        def listToColrLayers(layer):
-            if isinstance(layer, collections.abc.Sequence):
-                return self.buildPaint(
-                    {
-                        "Format": ot.PaintFormat.PaintColrLayers,
-                        "Layers": [listToColrLayers(l) for l in layer],
-                    }
-                )
-            return layer
-
-        layers = [listToColrLayers(l) for l in layers]
-
-        paint.NumLayers = len(layers)
-        paint.FirstLayerIndex = len(self.layers)
-        self.layers.extend(layers)
-
-        # Register our parts for reuse provided we aren't a tree
-        # If we are a tree the leaves registered for reuse and that will suffice
-        if not is_tree:
-            for lbound, ubound in _reuse_ranges(len(layers)):
-                self.reusePool[self._as_tuple(layers[lbound:ubound])] = (
-                    lbound + paint.FirstLayerIndex
-                )
-
-        # we've fully built dest; empty source prevents generalized build from kicking in
-        return paint, {}
-
-    def buildPaint(self, paint: _PaintInput) -> ot.Paint:
-        return self.tableBuilder.build(ot.Paint, paint)
-
-    def build(self) -> ot.LayerV1List:
-        layers = ot.LayerV1List()
-        layers.LayerCount = len(self.layers)
-        layers.Paint = self.layers
-        return layers
-
-
-def buildBaseGlyphV1Record(
-    baseGlyph: str, layerBuilder: LayerV1ListBuilder, paint: _PaintInput
-) -> ot.BaseGlyphV1List:
-    self = ot.BaseGlyphV1Record()
-    self.BaseGlyph = baseGlyph
-    self.Paint = layerBuilder.buildPaint(paint)
-    return self
-
-
-def _format_glyph_errors(errors: Mapping[str, Exception]) -> str:
-    lines = []
-    for baseGlyph, error in sorted(errors.items()):
-        lines.append(f"    {baseGlyph} => {type(error).__name__}: {error}")
-    return "\n".join(lines)
-
-
-def buildColrV1(
-    colorGlyphs: _ColorGlyphsDict,
-    glyphMap: Optional[Mapping[str, int]] = None,
-) -> Tuple[ot.LayerV1List, ot.BaseGlyphV1List]:
-    if glyphMap is not None:
-        colorGlyphItems = sorted(
-            colorGlyphs.items(), key=lambda item: glyphMap[item[0]]
-        )
-    else:
-        colorGlyphItems = colorGlyphs.items()
-
-    errors = {}
-    baseGlyphs = []
-    layerBuilder = LayerV1ListBuilder()
-    for baseGlyph, paint in colorGlyphItems:
-        try:
-            baseGlyphs.append(buildBaseGlyphV1Record(baseGlyph, layerBuilder, paint))
-
-        except (ColorLibError, OverflowError, ValueError, TypeError) as e:
-            errors[baseGlyph] = e
-
-    if errors:
-        failed_glyphs = _format_glyph_errors(errors)
-        exc = ColorLibError(f"Failed to build BaseGlyphV1List:\n{failed_glyphs}")
-        exc.errors = errors
-        raise exc from next(iter(errors.values()))
-
-    layers = layerBuilder.build()
-    glyphs = ot.BaseGlyphV1List()
-    glyphs.BaseGlyphCount = len(baseGlyphs)
-    glyphs.BaseGlyphV1Record = baseGlyphs
-    return (layers, glyphs)
-
-
-def _build_n_ary_tree(leaves, n):
-    """Build N-ary tree from sequence of leaf nodes.
-
-    Return a list of lists where each non-leaf node is a list containing
-    max n nodes.
-    """
-    if not leaves:
-        return []
-
-    assert n > 1
-
-    depth = ceil(log(len(leaves), n))
-
-    if depth <= 1:
-        return list(leaves)
-
-    # Fully populate complete subtrees of root until we have enough leaves left
-    root = []
-    unassigned = None
-    full_step = n ** (depth - 1)
-    for i in range(0, len(leaves), full_step):
-        subtree = leaves[i : i + full_step]
-        if len(subtree) < full_step:
-            unassigned = subtree
-            break
-        while len(subtree) > n:
-            subtree = [subtree[k : k + n] for k in range(0, len(subtree), n)]
-        root.append(subtree)
-
-    if unassigned:
-        # Recurse to fill the last subtree, which is the only partially populated one
-        subtree = _build_n_ary_tree(unassigned, n)
-        if len(subtree) <= n - len(root):
-            # replace last subtree with its children if they can still fit
-            root.extend(subtree)
-        else:
-            root.append(subtree)
-        assert len(root) <= n
-
-    return root
diff --git a/Lib/fontTools/colorLib/errors.py b/Lib/fontTools/colorLib/errors.py
deleted file mode 100644
index a0bdda1..0000000
--- a/Lib/fontTools/colorLib/errors.py
+++ /dev/null
@@ -1,3 +0,0 @@
-
-class ColorLibError(Exception):
-    pass
diff --git a/Lib/fontTools/colorLib/geometry.py b/Lib/fontTools/colorLib/geometry.py
deleted file mode 100644
index e62aead..0000000
--- a/Lib/fontTools/colorLib/geometry.py
+++ /dev/null
@@ -1,145 +0,0 @@
-"""Helpers for manipulating 2D points and vectors in COLR table."""
-
-from math import copysign, cos, hypot, pi
-from fontTools.misc.roundTools import otRound
-
-
-def _vector_between(origin, target):
-    return (target[0] - origin[0], target[1] - origin[1])
-
-
-def _round_point(pt):
-    return (otRound(pt[0]), otRound(pt[1]))
-
-
-def _unit_vector(vec):
-    length = hypot(*vec)
-    if length == 0:
-        return None
-    return (vec[0] / length, vec[1] / length)
-
-
-# This is the same tolerance used by Skia's SkTwoPointConicalGradient.cpp to detect
-# when a radial gradient's focal point lies on the end circle.
-_NEARLY_ZERO = 1 / (1 << 12)  # 0.000244140625
-
-
-# The unit vector's X and Y components are respectively
-#   U = (cos(α), sin(α))
-# where α is the angle between the unit vector and the positive x axis.
-_UNIT_VECTOR_THRESHOLD = cos(3 / 8 * pi)  # == sin(1/8 * pi) == 0.38268343236508984
-
-
-def _rounding_offset(direction):
-    # Return 2-tuple of -/+ 1.0 or 0.0 approximately based on the direction vector.
-    # We divide the unit circle in 8 equal slices oriented towards the cardinal
-    # (N, E, S, W) and intermediate (NE, SE, SW, NW) directions. To each slice we
-    # map one of the possible cases: -1, 0, +1 for either X and Y coordinate.
-    # E.g. Return (+1.0, -1.0) if unit vector is oriented towards SE, or
-    # (-1.0, 0.0) if it's pointing West, etc.
-    uv = _unit_vector(direction)
-    if not uv:
-        return (0, 0)
-
-    result = []
-    for uv_component in uv:
-        if -_UNIT_VECTOR_THRESHOLD <= uv_component < _UNIT_VECTOR_THRESHOLD:
-            # unit vector component near 0: direction almost orthogonal to the
-            # direction of the current axis, thus keep coordinate unchanged
-            result.append(0)
-        else:
-            # nudge coord by +/- 1.0 in direction of unit vector
-            result.append(copysign(1.0, uv_component))
-    return tuple(result)
-
-
-class Circle:
-    def __init__(self, centre, radius):
-        self.centre = centre
-        self.radius = radius
-
-    def __repr__(self):
-        return f"Circle(centre={self.centre}, radius={self.radius})"
-
-    def round(self):
-        return Circle(_round_point(self.centre), otRound(self.radius))
-
-    def inside(self, outer_circle):
-        dist = self.radius + hypot(*_vector_between(self.centre, outer_circle.centre))
-        return (
-            abs(outer_circle.radius - dist) <= _NEARLY_ZERO
-            or outer_circle.radius > dist
-        )
-
-    def concentric(self, other):
-        return self.centre == other.centre
-
-    def move(self, dx, dy):
-        self.centre = (self.centre[0] + dx, self.centre[1] + dy)
-
-
-def round_start_circle_stable_containment(c0, r0, c1, r1):
-    """Round start circle so that it stays inside/outside end circle after rounding.
-
-    The rounding of circle coordinates to integers may cause an abrupt change
-    if the start circle c0 is so close to the end circle c1's perimiter that
-    it ends up falling outside (or inside) as a result of the rounding.
-    To keep the gradient unchanged, we nudge it in the right direction.
-
-    See:
-    https://github.com/googlefonts/colr-gradients-spec/issues/204
-    https://github.com/googlefonts/picosvg/issues/158
-    """
-    start, end = Circle(c0, r0), Circle(c1, r1)
-
-    inside_before_round = start.inside(end)
-
-    round_start = start.round()
-    round_end = end.round()
-    inside_after_round = round_start.inside(round_end)
-
-    if inside_before_round == inside_after_round:
-        return round_start
-    elif inside_after_round:
-        # start was outside before rounding: we need to push start away from end
-        direction = _vector_between(round_end.centre, round_start.centre)
-        radius_delta = +1.0
-    else:
-        # start was inside before rounding: we need to push start towards end
-        direction = _vector_between(round_start.centre, round_end.centre)
-        radius_delta = -1.0
-    dx, dy = _rounding_offset(direction)
-
-    # At most 2 iterations ought to be enough to converge. Before the loop, we
-    # know the start circle didn't keep containment after normal rounding; thus
-    # we continue adjusting by -/+ 1.0 until containment is restored.
-    # Normal rounding can at most move each coordinates -/+0.5; in the worst case
-    # both the start and end circle's centres and radii will be rounded in opposite
-    # directions, e.g. when they move along a 45 degree diagonal:
-    #   c0 = (1.5, 1.5) ===> (2.0, 2.0)
-    #   r0 = 0.5 ===> 1.0
-    #   c1 = (0.499, 0.499) ===> (0.0, 0.0)
-    #   r1 = 2.499 ===> 2.0
-    # In this example, the relative distance between the circles, calculated
-    # as r1 - (r0 + distance(c0, c1)) is initially 0.57437 (c0 is inside c1), and
-    # -1.82842 after rounding (c0 is now outside c1). Nudging c0 by -1.0 on both
-    # x and y axes moves it towards c1 by hypot(-1.0, -1.0) = 1.41421. Two of these
-    # moves cover twice that distance, which is enough to restore containment.
-    max_attempts = 2
-    for _ in range(max_attempts):
-        if round_start.concentric(round_end):
-            # can't move c0 towards c1 (they are the same), so we change the radius
-            round_start.radius += radius_delta
-            assert round_start.radius >= 0
-        else:
-            round_start.move(dx, dy)
-        if inside_before_round == round_start.inside(round_end):
-            break
-    else:  # likely a bug
-        raise AssertionError(
-            f"Rounding circle {start} "
-            f"{'inside' if inside_before_round else 'outside'} "
-            f"{end} failed after {max_attempts} attempts!"
-        )
-
-    return round_start
diff --git a/Lib/fontTools/colorLib/table_builder.py b/Lib/fontTools/colorLib/table_builder.py
deleted file mode 100644
index 6fba6b0..0000000
--- a/Lib/fontTools/colorLib/table_builder.py
+++ /dev/null
@@ -1,234 +0,0 @@
-"""
-colorLib.table_builder: Generic helper for filling in BaseTable derivatives from tuples and maps and such.
-
-"""
-
-import collections
-import enum
-from fontTools.ttLib.tables.otBase import (
-    BaseTable,
-    FormatSwitchingBaseTable,
-    UInt8FormatSwitchingBaseTable,
-)
-from fontTools.ttLib.tables.otConverters import (
-    ComputedInt,
-    SimpleValue,
-    Struct,
-    Short,
-    UInt8,
-    UShort,
-    VarInt16,
-    VarUInt16,
-    IntValue,
-    FloatValue,
-)
-from fontTools.misc.roundTools import otRound
-
-
-class BuildCallback(enum.Enum):
-    """Keyed on (BEFORE_BUILD, class[, Format if available]).
-    Receives (dest, source).
-    Should return (dest, source), which can be new objects.
-    """
-
-    BEFORE_BUILD = enum.auto()
-
-    """Keyed on (AFTER_BUILD, class[, Format if available]).
-    Receives (dest).
-    Should return dest, which can be a new object.
-    """
-    AFTER_BUILD = enum.auto()
-
-    """Keyed on (CREATE_DEFAULT, class).
-    Receives no arguments.
-    Should return a new instance of class.
-    """
-    CREATE_DEFAULT = enum.auto()
-
-
-def _assignable(convertersByName):
-    return {k: v for k, v in convertersByName.items() if not isinstance(v, ComputedInt)}
-
-
-def convertTupleClass(tupleClass, value):
-    if isinstance(value, tupleClass):
-        return value
-    if isinstance(value, tuple):
-        return tupleClass(*value)
-    return tupleClass(value)
-
-
-def _isNonStrSequence(value):
-    return isinstance(value, collections.abc.Sequence) and not isinstance(value, str)
-
-
-def _set_format(dest, source):
-    if _isNonStrSequence(source):
-        assert len(source) > 0, f"{type(dest)} needs at least format from {source}"
-        dest.Format = source[0]
-        source = source[1:]
-    elif isinstance(source, collections.abc.Mapping):
-        assert "Format" in source, f"{type(dest)} needs at least Format from {source}"
-        dest.Format = source["Format"]
-    else:
-        raise ValueError(f"Not sure how to populate {type(dest)} from {source}")
-
-    assert isinstance(
-        dest.Format, collections.abc.Hashable
-    ), f"{type(dest)} Format is not hashable: {dest.Format}"
-    assert (
-        dest.Format in dest.convertersByName
-    ), f"{dest.Format} invalid Format of {cls}"
-
-    return source
-
-
-class TableBuilder:
-    """
-    Helps to populate things derived from BaseTable from maps, tuples, etc.
-
-    A table of lifecycle callbacks may be provided to add logic beyond what is possible
-    based on otData info for the target class. See BuildCallbacks.
-    """
-
-    def __init__(self, callbackTable=None):
-        if callbackTable is None:
-            callbackTable = {}
-        self._callbackTable = callbackTable
-
-    def _convert(self, dest, field, converter, value):
-        tupleClass = getattr(converter, "tupleClass", None)
-        enumClass = getattr(converter, "enumClass", None)
-
-        if tupleClass:
-            value = convertTupleClass(tupleClass, value)
-
-        elif enumClass:
-            if isinstance(value, enumClass):
-                pass
-            elif isinstance(value, str):
-                try:
-                    value = getattr(enumClass, value.upper())
-                except AttributeError:
-                    raise ValueError(f"{value} is not a valid {enumClass}")
-            else:
-                value = enumClass(value)
-
-        elif isinstance(converter, IntValue):
-            value = otRound(value)
-        elif isinstance(converter, FloatValue):
-            value = float(value)
-
-        elif isinstance(converter, Struct):
-            if converter.repeat:
-                if _isNonStrSequence(value):
-                    value = [self.build(converter.tableClass, v) for v in value]
-                else:
-                    value = [self.build(converter.tableClass, value)]
-                setattr(dest, converter.repeat, len(value))
-            else:
-                value = self.build(converter.tableClass, value)
-        elif callable(converter):
-            value = converter(value)
-
-        setattr(dest, field, value)
-
-    def build(self, cls, source):
-        assert issubclass(cls, BaseTable)
-
-        if isinstance(source, cls):
-            return source
-
-        callbackKey = (cls,)
-        dest = self._callbackTable.get(
-            (BuildCallback.CREATE_DEFAULT,) + callbackKey, lambda: cls()
-        )()
-        assert isinstance(dest, cls)
-
-        convByName = _assignable(cls.convertersByName)
-        skippedFields = set()
-
-        # For format switchers we need to resolve converters based on format
-        if issubclass(cls, FormatSwitchingBaseTable):
-            source = _set_format(dest, source)
-
-            convByName = _assignable(convByName[dest.Format])
-            skippedFields.add("Format")
-            callbackKey = (cls, dest.Format)
-
-        # Convert sequence => mapping so before thunk only has to handle one format
-        if _isNonStrSequence(source):
-            # Sequence (typically list or tuple) assumed to match fields in declaration order
-            assert len(source) <= len(
-                convByName
-            ), f"Sequence of {len(source)} too long for {cls}; expected <= {len(convByName)} values"
-            source = dict(zip(convByName.keys(), source))
-
-        dest, source = self._callbackTable.get(
-            (BuildCallback.BEFORE_BUILD,) + callbackKey, lambda d, s: (d, s)
-        )(dest, source)
-
-        if isinstance(source, collections.abc.Mapping):
-            for field, value in source.items():
-                if field in skippedFields:
-                    continue
-                converter = convByName.get(field, None)
-                if not converter:
-                    raise ValueError(
-                        f"Unrecognized field {field} for {cls}; expected one of {sorted(convByName.keys())}"
-                    )
-                self._convert(dest, field, converter, value)
-        else:
-            # let's try as a 1-tuple
-            dest = self.build(cls, (source,))
-
-        dest = self._callbackTable.get(
-            (BuildCallback.AFTER_BUILD,) + callbackKey, lambda d: d
-        )(dest)
-
-        return dest
-
-
-class TableUnbuilder:
-    def __init__(self, callbackTable=None):
-        if callbackTable is None:
-            callbackTable = {}
-        self._callbackTable = callbackTable
-
-    def unbuild(self, table):
-        assert isinstance(table, BaseTable)
-
-        source = {}
-
-        callbackKey = (type(table),)
-        if isinstance(table, FormatSwitchingBaseTable):
-            source["Format"] = int(table.Format)
-            callbackKey += (table.Format,)
-
-        for converter in table.getConverters():
-            if isinstance(converter, ComputedInt):
-                continue
-            value = getattr(table, converter.name)
-
-            tupleClass = getattr(converter, "tupleClass", None)
-            enumClass = getattr(converter, "enumClass", None)
-            if tupleClass:
-                source[converter.name] = tuple(value)
-            elif enumClass:
-                source[converter.name] = value.name.lower()
-            elif isinstance(converter, Struct):
-                if converter.repeat:
-                    source[converter.name] = [self.unbuild(v) for v in value]
-                else:
-                    source[converter.name] = self.unbuild(value)
-            elif isinstance(converter, SimpleValue):
-                # "simple" values (e.g. int, float, str) need no further un-building
-                source[converter.name] = value
-            else:
-                raise NotImplementedError(
-                    "Don't know how unbuild {value!r} with {converter!r}"
-                )
-
-        source = self._callbackTable.get(callbackKey, lambda s: s)(source)
-
-        return source
diff --git a/Lib/fontTools/colorLib/unbuilder.py b/Lib/fontTools/colorLib/unbuilder.py
deleted file mode 100644
index 43582bd..0000000
--- a/Lib/fontTools/colorLib/unbuilder.py
+++ /dev/null
@@ -1,79 +0,0 @@
-from fontTools.ttLib.tables import otTables as ot
-from .table_builder import TableUnbuilder
-
-
-def unbuildColrV1(layerV1List, baseGlyphV1List):
-    unbuilder = LayerV1ListUnbuilder(layerV1List.Paint)
-    return {
-        rec.BaseGlyph: unbuilder.unbuildPaint(rec.Paint)
-        for rec in baseGlyphV1List.BaseGlyphV1Record
-    }
-
-
-def _flatten(lst):
-    for el in lst:
-        if isinstance(el, list):
-            yield from _flatten(el)
-        else:
-            yield el
-
-
-class LayerV1ListUnbuilder:
-    def __init__(self, layers):
-        self.layers = layers
-
-        callbacks = {
-            (
-                ot.Paint,
-                ot.PaintFormat.PaintColrLayers,
-            ): self._unbuildPaintColrLayers,
-        }
-        self.tableUnbuilder = TableUnbuilder(callbacks)
-
-    def unbuildPaint(self, paint):
-        assert isinstance(paint, ot.Paint)
-        return self.tableUnbuilder.unbuild(paint)
-
-    def _unbuildPaintColrLayers(self, source):
-        assert source["Format"] == ot.PaintFormat.PaintColrLayers
-
-        layers = list(
-            _flatten(
-                [
-                    self.unbuildPaint(childPaint)
-                    for childPaint in self.layers[
-                        source["FirstLayerIndex"] : source["FirstLayerIndex"]
-                        + source["NumLayers"]
-                    ]
-                ]
-            )
-        )
-
-        if len(layers) == 1:
-            return layers[0]
-
-        return {"Format": source["Format"], "Layers": layers}
-
-
-if __name__ == "__main__":
-    from pprint import pprint
-    import sys
-    from fontTools.ttLib import TTFont
-
-    try:
-        fontfile = sys.argv[1]
-    except IndexError:
-        sys.exit("usage: fonttools colorLib.unbuilder FONTFILE")
-
-    font = TTFont(fontfile)
-    colr = font["COLR"]
-    if colr.version < 1:
-        sys.exit(f"error: No COLR table version=1 found in {fontfile}")
-
-    colorGlyphs = unbuildColrV1(
-        colr.table.LayerV1List,
-        colr.table.BaseGlyphV1List,
-        ignoreVarIdx=not colr.table.VarStore,
-    )
-
-    pprint(colorGlyphs)
diff --git a/Lib/fontTools/cu2qu/__init__.py b/Lib/fontTools/cu2qu/__init__.py
deleted file mode 100644
index 4ae6356..0000000
--- a/Lib/fontTools/cu2qu/__init__.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2016 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from .cu2qu import *
diff --git a/Lib/fontTools/cu2qu/__main__.py b/Lib/fontTools/cu2qu/__main__.py
deleted file mode 100644
index 084bf8f..0000000
--- a/Lib/fontTools/cu2qu/__main__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-import sys
-from .cli import main
-
-
-if __name__ == "__main__":
-    sys.exit(main())
diff --git a/Lib/fontTools/cu2qu/cli.py b/Lib/fontTools/cu2qu/cli.py
deleted file mode 100644
index d4e83b8..0000000
--- a/Lib/fontTools/cu2qu/cli.py
+++ /dev/null
@@ -1,177 +0,0 @@
-import os
-import argparse
-import logging
-import shutil
-import multiprocessing as mp
-from contextlib import closing
-from functools import partial
-
-import fontTools
-from .ufo import font_to_quadratic, fonts_to_quadratic
-
-ufo_module = None
-try:
-    import ufoLib2 as ufo_module
-except ImportError:
-    try:
-        import defcon as ufo_module
-    except ImportError as e:
-        pass
-
-
-logger = logging.getLogger("fontTools.cu2qu")
-
-
-def _cpu_count():
-    try:
-        return mp.cpu_count()
-    except NotImplementedError:  # pragma: no cover
-        return 1
-
-
-def _font_to_quadratic(input_path, output_path=None, **kwargs):
-    ufo = ufo_module.Font(input_path)
-    logger.info('Converting curves for %s', input_path)
-    if font_to_quadratic(ufo, **kwargs):
-        logger.info("Saving %s", output_path)
-        if output_path:
-            ufo.save(output_path)
-        else:
-            ufo.save()  # save in-place
-    elif output_path:
-        _copytree(input_path, output_path)
-
-
-def _samepath(path1, path2):
-    # TODO on python3+, there's os.path.samefile
-    path1 = os.path.normcase(os.path.abspath(os.path.realpath(path1)))
-    path2 = os.path.normcase(os.path.abspath(os.path.realpath(path2)))
-    return path1 == path2
-
-
-def _copytree(input_path, output_path):
-    if _samepath(input_path, output_path):
-        logger.debug("input and output paths are the same file; skipped copy")
-        return
-    if os.path.exists(output_path):
-        shutil.rmtree(output_path)
-    shutil.copytree(input_path, output_path)
-
-
-def main(args=None):
-    """Convert a UFO font from cubic to quadratic curves"""
-    parser = argparse.ArgumentParser(prog="cu2qu")
-    parser.add_argument(
-        "--version", action="version", version=fontTools.__version__)
-    parser.add_argument(
-        "infiles",
-        nargs="+",
-        metavar="INPUT",
-        help="one or more input UFO source file(s).")
-    parser.add_argument("-v", "--verbose", action="count", default=0)
-    parser.add_argument(
-        "-e",
-        "--conversion-error",
-        type=float,
-        metavar="ERROR",
-        default=None,
-        help="maxiumum approximation error measured in EM (default: 0.001)")
-    parser.add_argument(
-        "--keep-direction",
-        dest="reverse_direction",
-        action="store_false",
-        help="do not reverse the contour direction")
-
-    mode_parser = parser.add_mutually_exclusive_group()
-    mode_parser.add_argument(
-        "-i",
-        "--interpolatable",
-        action="store_true",
-        help="whether curve conversion should keep interpolation compatibility"
-    )
-    mode_parser.add_argument(
-        "-j",
-        "--jobs",
-        type=int,
-        nargs="?",
-        default=1,
-        const=_cpu_count(),
-        metavar="N",
-        help="Convert using N multiple processes (default: %(default)s)")
-
-    output_parser = parser.add_mutually_exclusive_group()
-    output_parser.add_argument(
-        "-o",
-        "--output-file",
-        default=None,
-        metavar="OUTPUT",
-        help=("output filename for the converted UFO. By default fonts are "
-              "modified in place. This only works with a single input."))
-    output_parser.add_argument(
-        "-d",
-        "--output-dir",
-        default=None,
-        metavar="DIRECTORY",
-        help="output directory where to save converted UFOs")
-
-    options = parser.parse_args(args)
-
-    if ufo_module is None:
-        parser.error("Either ufoLib2 or defcon are required to run this script.")
-
-    if not options.verbose:
-        level = "WARNING"
-    elif options.verbose == 1:
-        level = "INFO"
-    else:
-        level = "DEBUG"
-    logging.basicConfig(level=level)
-
-    if len(options.infiles) > 1 and options.output_file:
-        parser.error("-o/--output-file can't be used with multile inputs")
-
-    if options.output_dir:
-        output_dir = options.output_dir
-        if not os.path.exists(output_dir):
-            os.mkdir(output_dir)
-        elif not os.path.isdir(output_dir):
-            parser.error("'%s' is not a directory" % output_dir)
-        output_paths = [
-            os.path.join(output_dir, os.path.basename(p))
-            for p in options.infiles
-        ]
-    elif options.output_file:
-        output_paths = [options.output_file]
-    else:
-        # save in-place
-        output_paths = [None] * len(options.infiles)
-
-    kwargs = dict(dump_stats=options.verbose > 0,
-                  max_err_em=options.conversion_error,
-                  reverse_direction=options.reverse_direction)
-
-    if options.interpolatable:
-        logger.info('Converting curves compatibly')
-        ufos = [ufo_module.Font(infile) for infile in options.infiles]
-        if fonts_to_quadratic(ufos, **kwargs):
-            for ufo, output_path in zip(ufos, output_paths):
-                logger.info("Saving %s", output_path)
-                if output_path:
-                    ufo.save(output_path)
-                else:
-                    ufo.save()
-        else:
-            for input_path, output_path in zip(options.infiles, output_paths):
-                if output_path:
-                    _copytree(input_path, output_path)
-    else:
-        jobs = min(len(options.infiles),
-                   options.jobs) if options.jobs > 1 else 1
-        if jobs > 1:
-            func = partial(_font_to_quadratic, **kwargs)
-            logger.info('Running %d parallel processes', jobs)
-            with closing(mp.Pool(jobs)) as pool:
-                pool.starmap(func, zip(options.infiles, output_paths))
-        else:
-            for input_path, output_path in zip(options.infiles, output_paths):
-                _font_to_quadratic(input_path, output_path, **kwargs)
diff --git a/Lib/fontTools/cu2qu/cu2qu.py b/Lib/fontTools/cu2qu/cu2qu.py
deleted file mode 100644
index c9ce93a..0000000
--- a/Lib/fontTools/cu2qu/cu2qu.py
+++ /dev/null
@@ -1,496 +0,0 @@
-#cython: language_level=3
-#distutils: define_macros=CYTHON_TRACE_NOGIL=1
-
-# Copyright 2015 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-try:
-    import cython
-except ImportError:
-    # if cython not installed, use mock module with no-op decorators and types
-    from fontTools.misc import cython
-
-import math
-
-from .errors import Error as Cu2QuError, ApproxNotFoundError
-
-
-__all__ = ['curve_to_quadratic', 'curves_to_quadratic']
-
-MAX_N = 100
-
-NAN = float("NaN")
-
-
-if cython.compiled:
-    # Yep, I'm compiled.
-    COMPILED = True
-else:
-    # Just a lowly interpreted script.
-    COMPILED = False
-
-
-@cython.cfunc
-@cython.inline
-@cython.returns(cython.double)
-@cython.locals(v1=cython.complex, v2=cython.complex)
-def dot(v1, v2):
-    """Return the dot product of two vectors.
-
-    Args:
-        v1 (complex): First vector.
-        v2 (complex): Second vector.
-
-    Returns:
-        double: Dot product.
-    """
-    return (v1 * v2.conjugate()).real
-
-
-@cython.cfunc
-@cython.inline
-@cython.locals(a=cython.complex, b=cython.complex, c=cython.complex, d=cython.complex)
-@cython.locals(_1=cython.complex, _2=cython.complex, _3=cython.complex, _4=cython.complex)
-def calc_cubic_points(a, b, c, d):
-    _1 = d
-    _2 = (c / 3.0) + d
-    _3 = (b + c) / 3.0 + _2
-    _4 = a + d + c + b
-    return _1, _2, _3, _4
-
-
-@cython.cfunc
-@cython.inline
-@cython.locals(p0=cython.complex, p1=cython.complex, p2=cython.complex, p3=cython.complex)
-@cython.locals(a=cython.complex, b=cython.complex, c=cython.complex, d=cython.complex)
-def calc_cubic_parameters(p0, p1, p2, p3):
-    c = (p1 - p0) * 3.0
-    b = (p2 - p1) * 3.0 - c
-    d = p0
-    a = p3 - d - c - b
-    return a, b, c, d
-
-
-@cython.cfunc
-@cython.locals(p0=cython.complex, p1=cython.complex, p2=cython.complex, p3=cython.complex)
-def split_cubic_into_n_iter(p0, p1, p2, p3, n):
-    """Split a cubic Bezier into n equal parts.
-
-    Splits the curve into `n` equal parts by curve time.
-    (t=0..1/n, t=1/n..2/n, ...)
-
-    Args:
-        p0 (complex): Start point of curve.
-        p1 (complex): First handle of curve.
-        p2 (complex): Second handle of curve.
-        p3 (complex): End point of curve.
-
-    Returns:
-        An iterator yielding the control points (four complex values) of the
-        subcurves.
-    """
-    # Hand-coded special-cases
-    if n == 2:
-        return iter(split_cubic_into_two(p0, p1, p2, p3))
-    if n == 3:
-        return iter(split_cubic_into_three(p0, p1, p2, p3))
-    if n == 4:
-        a, b = split_cubic_into_two(p0, p1, p2, p3)
-        return iter(split_cubic_into_two(*a) + split_cubic_into_two(*b))
-    if n == 6:
-        a, b = split_cubic_into_two(p0, p1, p2, p3)
-        return iter(split_cubic_into_three(*a) + split_cubic_into_three(*b))
-
-    return _split_cubic_into_n_gen(p0,p1,p2,p3,n)
-
-
-@cython.locals(p0=cython.complex, p1=cython.complex, p2=cython.complex, p3=cython.complex, n=cython.int)
-@cython.locals(a=cython.complex, b=cython.complex, c=cython.complex, d=cython.complex)
-@cython.locals(dt=cython.double, delta_2=cython.double, delta_3=cython.double, i=cython.int)
-@cython.locals(a1=cython.complex, b1=cython.complex, c1=cython.complex, d1=cython.complex)
-def _split_cubic_into_n_gen(p0, p1, p2, p3, n):
-    a, b, c, d = calc_cubic_parameters(p0, p1, p2, p3)
-    dt = 1 / n
-    delta_2 = dt * dt
-    delta_3 = dt * delta_2
-    for i in range(n):
-        t1 = i * dt
-        t1_2 = t1 * t1
-        # calc new a, b, c and d
-        a1 = a * delta_3
-        b1 = (3*a*t1 + b) * delta_2
-        c1 = (2*b*t1 + c + 3*a*t1_2) * dt
-        d1 = a*t1*t1_2 + b*t1_2 + c*t1 + d
-        yield calc_cubic_points(a1, b1, c1, d1)
-
-
-@cython.locals(p0=cython.complex, p1=cython.complex, p2=cython.complex, p3=cython.complex)
-@cython.locals(mid=cython.complex, deriv3=cython.complex)
-def split_cubic_into_two(p0, p1, p2, p3):
-    """Split a cubic Bezier into two equal parts.
-
-    Splits the curve into two equal parts at t = 0.5
-
-    Args:
-        p0 (complex): Start point of curve.
-        p1 (complex): First handle of curve.
-        p2 (complex): Second handle of curve.
-        p3 (complex): End point of curve.
-
-    Returns:
-        tuple: Two cubic Beziers (each expressed as a tuple of four complex
-        values).
-    """
-    mid = (p0 + 3 * (p1 + p2) + p3) * .125
-    deriv3 = (p3 + p2 - p1 - p0) * .125
-    return ((p0, (p0 + p1) * .5, mid - deriv3, mid),
-            (mid, mid + deriv3, (p2 + p3) * .5, p3))
-
-
-@cython.locals(p0=cython.complex, p1=cython.complex, p2=cython.complex, p3=cython.complex, _27=cython.double)
-@cython.locals(mid1=cython.complex, deriv1=cython.complex, mid2=cython.complex, deriv2=cython.complex)
-def split_cubic_into_three(p0, p1, p2, p3, _27=1/27):
-    """Split a cubic Bezier into three equal parts.
-
-    Splits the curve into three equal parts at t = 1/3 and t = 2/3
-
-    Args:
-        p0 (complex): Start point of curve.
-        p1 (complex): First handle of curve.
-        p2 (complex): Second handle of curve.
-        p3 (complex): End point of curve.
-
-    Returns:
-        tuple: Three cubic Beziers (each expressed as a tuple of four complex
-        values).
-    """
-    # we define 1/27 as a keyword argument so that it will be evaluated only
-    # once but still in the scope of this function
-    mid1 = (8*p0 + 12*p1 + 6*p2 + p3) * _27
-    deriv1 = (p3 + 3*p2 - 4*p0) * _27
-    mid2 = (p0 + 6*p1 + 12*p2 + 8*p3) * _27
-    deriv2 = (4*p3 - 3*p1 - p0) * _27
-    return ((p0, (2*p0 + p1) / 3.0, mid1 - deriv1, mid1),
-            (mid1, mid1 + deriv1, mid2 - deriv2, mid2),
-            (mid2, mid2 + deriv2, (p2 + 2*p3) / 3.0, p3))
-
-
-@cython.returns(cython.complex)
-@cython.locals(t=cython.double, p0=cython.complex, p1=cython.complex, p2=cython.complex, p3=cython.complex)
-@cython.locals(_p1=cython.complex, _p2=cython.complex)
-def cubic_approx_control(t, p0, p1, p2, p3):
-    """Approximate a cubic Bezier using a quadratic one.
-
-    Args:
-        t (double): Position of control point.
-        p0 (complex): Start point of curve.
-        p1 (complex): First handle of curve.
-        p2 (complex): Second handle of curve.
-        p3 (complex): End point of curve.
-
-    Returns:
-        complex: Location of candidate control point on quadratic curve.
-    """
-    _p1 = p0 + (p1 - p0) * 1.5
-    _p2 = p3 + (p2 - p3) * 1.5
-    return _p1 + (_p2 - _p1) * t
-
-
-@cython.returns(cython.complex)
-@cython.locals(a=cython.complex, b=cython.complex, c=cython.complex, d=cython.complex)
-@cython.locals(ab=cython.complex, cd=cython.complex, p=cython.complex, h=cython.double)
-def calc_intersect(a, b, c, d):
-    """Calculate the intersection of two lines.
-
-    Args:
-        a (complex): Start point of first line.
-        b (complex): End point of first line.
-        c (complex): Start point of second line.
-        d (complex): End point of second line.
-
-    Returns:
-        complex: Location of intersection if one present, ``complex(NaN,NaN)``
-        if no intersection was found.
-    """
-    ab = b - a
-    cd = d - c
-    p = ab * 1j
-    try:
-        h = dot(p, a - c) / dot(p, cd)
-    except ZeroDivisionError:
-        return complex(NAN, NAN)
-    return c + cd * h
-
-
-@cython.cfunc
-@cython.returns(cython.int)
-@cython.locals(tolerance=cython.double, p0=cython.complex, p1=cython.complex, p2=cython.complex, p3=cython.complex)
-@cython.locals(mid=cython.complex, deriv3=cython.complex)
-def cubic_farthest_fit_inside(p0, p1, p2, p3, tolerance):
-    """Check if a cubic Bezier lies within a given distance of the origin.
-
-    "Origin" means *the* origin (0,0), not the start of the curve. Note that no
-    checks are made on the start and end positions of the curve; this function
-    only checks the inside of the curve.
-
-    Args:
-        p0 (complex): Start point of curve.
-        p1 (complex): First handle of curve.
-        p2 (complex): Second handle of curve.
-        p3 (complex): End point of curve.
-        tolerance (double): Distance from origin.
-
-    Returns:
-        bool: True if the cubic Bezier ``p`` entirely lies within a distance
-        ``tolerance`` of the origin, False otherwise.
-    """
-    # First check p2 then p1, as p2 has higher error early on.
-    if abs(p2) <= tolerance and abs(p1) <= tolerance:
-        return True
-
-    # Split.
-    mid = (p0 + 3 * (p1 + p2) + p3) * .125
-    if abs(mid) > tolerance:
-        return False
-    deriv3 = (p3 + p2 - p1 - p0) * .125
-    return (cubic_farthest_fit_inside(p0, (p0+p1)*.5, mid-deriv3, mid, tolerance) and
-            cubic_farthest_fit_inside(mid, mid+deriv3, (p2+p3)*.5, p3, tolerance))
-
-
-@cython.cfunc
-@cython.locals(tolerance=cython.double, _2_3=cython.double)
-@cython.locals(q1=cython.complex, c0=cython.complex, c1=cython.complex, c2=cython.complex, c3=cython.complex)
-def cubic_approx_quadratic(cubic, tolerance, _2_3=2/3):
-    """Approximate a cubic Bezier with a single quadratic within a given tolerance.
-
-    Args:
-        cubic (sequence): Four complex numbers representing control points of
-            the cubic Bezier curve.
-        tolerance (double): Permitted deviation from the original curve.
-
-    Returns:
-        Three complex numbers representing control points of the quadratic
-        curve if it fits within the given tolerance, or ``None`` if no suitable
-        curve could be calculated.
-    """
-    # we define 2/3 as a keyword argument so that it will be evaluated only
-    # once but still in the scope of this function
-
-    q1 = calc_intersect(*cubic)
-    if math.isnan(q1.imag):
-        return None
-    c0 = cubic[0]
-    c3 = cubic[3]
-    c1 = c0 + (q1 - c0) * _2_3
-    c2 = c3 + (q1 - c3) * _2_3
-    if not cubic_farthest_fit_inside(0,
-                                     c1 - cubic[1],
-                                     c2 - cubic[2],
-                                     0, tolerance):
-        return None
-    return c0, q1, c3
-
-
-@cython.cfunc
-@cython.locals(n=cython.int, tolerance=cython.double, _2_3=cython.double)
-@cython.locals(i=cython.int)
-@cython.locals(c0=cython.complex, c1=cython.complex, c2=cython.complex, c3=cython.complex)
-@cython.locals(q0=cython.complex, q1=cython.complex, next_q1=cython.complex, q2=cython.complex, d1=cython.complex)
-def cubic_approx_spline(cubic, n, tolerance, _2_3=2/3):
-    """Approximate a cubic Bezier curve with a spline of n quadratics.
-
-    Args:
-        cubic (sequence): Four complex numbers representing control points of
-            the cubic Bezier curve.
-        n (int): Number of quadratic Bezier curves in the spline.
-        tolerance (double): Permitted deviation from the original curve.
-
-    Returns:
-        A list of ``n+2`` complex numbers, representing control points of the
-        quadratic spline if it fits within the given tolerance, or ``None`` if
-        no suitable spline could be calculated.
-    """
-    # we define 2/3 as a keyword argument so that it will be evaluated only
-    # once but still in the scope of this function
-
-    if n == 1:
-        return cubic_approx_quadratic(cubic, tolerance)
-
-    cubics = split_cubic_into_n_iter(cubic[0], cubic[1], cubic[2], cubic[3], n)
-
-    # calculate the spline of quadratics and check errors at the same time.
-    next_cubic = next(cubics)
-    next_q1 = cubic_approx_control(0, *next_cubic)
-    q2 = cubic[0]
-    d1 = 0j
-    spline = [cubic[0], next_q1]
-    for i in range(1, n+1):
-
-        # Current cubic to convert
-        c0, c1, c2, c3 = next_cubic
-
-        # Current quadratic approximation of current cubic
-        q0 = q2
-        q1 = next_q1
-        if i < n:
-            next_cubic = next(cubics)
-            next_q1 = cubic_approx_control(i / (n-1), *next_cubic)
-            spline.append(next_q1)
-            q2 = (q1 + next_q1) * .5
-        else:
-            q2 = c3
-
-        # End-point deltas
-        d0 = d1
-        d1 = q2 - c3
-
-        if (abs(d1) > tolerance or
-            not cubic_farthest_fit_inside(d0,
-                                          q0 + (q1 - q0) * _2_3 - c1,
-                                          q2 + (q1 - q2) * _2_3 - c2,
-                                          d1,
-                                          tolerance)):
-            return None
-    spline.append(cubic[3])
-
-    return spline
-
-
-@cython.locals(max_err=cython.double)
-@cython.locals(n=cython.int)
-def curve_to_quadratic(curve, max_err):
-    """Approximate a cubic Bezier curve with a spline of n quadratics.
-
-    Args:
-        cubic (sequence): Four 2D tuples representing control points of
-            the cubic Bezier curve.
-        max_err (double): Permitted deviation from the original curve.
-
-    Returns:
-        A list of 2D tuples, representing control points of the quadratic
-        spline if it fits within the given tolerance, or ``None`` if no
-        suitable spline could be calculated.
-    """
-
-    curve = [complex(*p) for p in curve]
-
-    for n in range(1, MAX_N + 1):
-        spline = cubic_approx_spline(curve, n, max_err)
-        if spline is not None:
-            # done. go home
-            return [(s.real, s.imag) for s in spline]
-
-    raise ApproxNotFoundError(curve)
-
-
-
-@cython.locals(l=cython.int, last_i=cython.int, i=cython.int)
-def curves_to_quadratic(curves, max_errors):
-    """Return quadratic Bezier splines approximating the input cubic Beziers.
-
-    Args:
-        curves: A sequence of *n* curves, each curve being a sequence of four
-            2D tuples.
-        max_errors: A sequence of *n* floats representing the maximum permissible
-            deviation from each of the cubic Bezier curves.
-
-    Example::
-
-        >>> curves_to_quadratic( [
-        ...   [ (50,50), (100,100), (150,100), (200,50) ],
-        ...   [ (75,50), (120,100), (150,75),  (200,60) ]
-        ... ], [1,1] )
-        [[(50.0, 50.0), (75.0, 75.0), (125.0, 91.66666666666666), (175.0, 75.0), (200.0, 50.0)], [(75.0, 50.0), (97.5, 75.0), (135.41666666666666, 82.08333333333333), (175.0, 67.5), (200.0, 60.0)]]
-
-    The returned splines have "implied oncurve points" suitable for use in
-    TrueType ``glif`` outlines - i.e. in the first spline returned above,
-    the first quadratic segment runs from (50,50) to
-    ( (75 + 125)/2 , (120 + 91.666..)/2 ) = (100, 83.333...).
-
-    Returns:
-        A list of splines, each spline being a list of 2D tuples.
-
-    Raises:
-        fontTools.cu2qu.Errors.ApproxNotFoundError: if no suitable approximation
-        can be found for all curves with the given parameters.
-    """
-
-    curves = [[complex(*p) for p in curve] for curve in curves]
-    assert len(max_errors) == len(curves)
-
-    l = len(curves)
-    splines = [None] * l
-    last_i = i = 0
-    n = 1
-    while True:
-        spline = cubic_approx_spline(curves[i], n, max_errors[i])
-        if spline is None:
-            if n == MAX_N:
-                break
-            n += 1
-            last_i = i
-            continue
-        splines[i] = spline
-        i = (i + 1) % l
-        if i == last_i:
-            # done. go home
-            return [[(s.real, s.imag) for s in spline] for spline in splines]
-
-    raise ApproxNotFoundError(curves)
-
-
-if __name__ == '__main__':
-    import random
-    import timeit
-
-    MAX_ERR = 5
-
-    def generate_curve():
-        return [
-            tuple(float(random.randint(0, 2048)) for coord in range(2))
-            for point in range(4)]
-
-    def setup_curve_to_quadratic():
-        return generate_curve(), MAX_ERR
-
-    def setup_curves_to_quadratic():
-        num_curves = 3
-        return (
-            [generate_curve() for curve in range(num_curves)],
-            [MAX_ERR] * num_curves)
-
-    def run_benchmark(
-            benchmark_module, module, function, setup_suffix='', repeat=5, number=1000):
-        setup_func = 'setup_' + function
-        if setup_suffix:
-            print('%s with %s:' % (function, setup_suffix), end='')
-            setup_func += '_' + setup_suffix
-        else:
-            print('%s:' % function, end='')
-
-        def wrapper(function, setup_func):
-            function = globals()[function]
-            setup_func = globals()[setup_func]
-            def wrapped():
-                return function(*setup_func())
-            return wrapped
-        results = timeit.repeat(wrapper(function, setup_func), repeat=repeat, number=number)
-        print('\t%5.1fus' % (min(results) * 1000000. / number))
-
-    def main():
-        run_benchmark('cu2qu.benchmark', 'cu2qu', 'curve_to_quadratic')
-        run_benchmark('cu2qu.benchmark', 'cu2qu', 'curves_to_quadratic')
-
-    random.seed(1)
-    main()
diff --git a/Lib/fontTools/cu2qu/errors.py b/Lib/fontTools/cu2qu/errors.py
deleted file mode 100644
index 74c4c22..0000000
--- a/Lib/fontTools/cu2qu/errors.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# Copyright 2016 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-class Error(Exception):
-    """Base Cu2Qu exception class for all other errors."""
-
-
-class ApproxNotFoundError(Error):
-    def __init__(self, curve):
-        message = "no approximation found: %s" % curve
-        super().__init__(message)
-        self.curve = curve
-
-
-class UnequalZipLengthsError(Error):
-    pass
-
-
-class IncompatibleGlyphsError(Error):
-    def __init__(self, glyphs):
-        assert len(glyphs) > 1
-        self.glyphs = glyphs
-        names = set(repr(g.name) for g in glyphs)
-        if len(names) > 1:
-            self.combined_name = "{%s}" % ", ".join(sorted(names))
-        else:
-            self.combined_name = names.pop()
-
-    def __repr__(self):
-        return "<%s %s>" % (type(self).__name__, self.combined_name)
-
-
-class IncompatibleSegmentNumberError(IncompatibleGlyphsError):
-    def __str__(self):
-        return "Glyphs named %s have different number of segments" % (
-            self.combined_name
-        )
-
-
-class IncompatibleSegmentTypesError(IncompatibleGlyphsError):
-    def __init__(self, glyphs, segments):
-        IncompatibleGlyphsError.__init__(self, glyphs)
-        self.segments = segments
-
-    def __str__(self):
-        lines = []
-        ndigits = len(str(max(self.segments)))
-        for i, tags in sorted(self.segments.items()):
-            lines.append(
-                "%s: (%s)" % (str(i).rjust(ndigits), ", ".join(repr(t) for t in tags))
-            )
-        return "Glyphs named %s have incompatible segment types:\n  %s" % (
-            self.combined_name,
-            "\n  ".join(lines),
-        )
-
-
-class IncompatibleFontsError(Error):
-    def __init__(self, glyph_errors):
-        self.glyph_errors = glyph_errors
-
-    def __str__(self):
-        return "fonts contains incompatible glyphs: %s" % (
-            ", ".join(repr(g) for g in sorted(self.glyph_errors.keys()))
-        )
diff --git a/Lib/fontTools/cu2qu/ufo.py b/Lib/fontTools/cu2qu/ufo.py
deleted file mode 100644
index 447de7b..0000000
--- a/Lib/fontTools/cu2qu/ufo.py
+++ /dev/null
@@ -1,324 +0,0 @@
-# Copyright 2015 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-"""Converts cubic bezier curves to quadratic splines.
-
-Conversion is performed such that the quadratic splines keep the same end-curve
-tangents as the original cubics. The approach is iterative, increasing the
-number of segments for a spline until the error gets below a bound.
-
-Respective curves from multiple fonts will be converted at once to ensure that
-the resulting splines are interpolation-compatible.
-"""
-
-import logging
-from fontTools.pens.basePen import AbstractPen
-from fontTools.pens.pointPen import PointToSegmentPen
-from fontTools.pens.reverseContourPen import ReverseContourPen
-
-from . import curves_to_quadratic
-from .errors import (
-    UnequalZipLengthsError, IncompatibleSegmentNumberError,
-    IncompatibleSegmentTypesError, IncompatibleGlyphsError,
-    IncompatibleFontsError)
-
-
-__all__ = ['fonts_to_quadratic', 'font_to_quadratic']
-
-# The default approximation error below is a relative value (1/1000 of the EM square).
-# Later on, we convert it to absolute font units by multiplying it by a font's UPEM
-# (see fonts_to_quadratic).
-DEFAULT_MAX_ERR = 0.001
-CURVE_TYPE_LIB_KEY = "com.github.googlei18n.cu2qu.curve_type"
-
-logger = logging.getLogger(__name__)
-
-
-_zip = zip
-def zip(*args):
-    """Ensure each argument to zip has the same length. Also make sure a list is
-    returned for python 2/3 compatibility.
-    """
-
-    if len(set(len(a) for a in args)) != 1:
-        raise UnequalZipLengthsError(*args)
-    return list(_zip(*args))
-
-
-class GetSegmentsPen(AbstractPen):
-    """Pen to collect segments into lists of points for conversion.
-
-    Curves always include their initial on-curve point, so some points are
-    duplicated between segments.
-    """
-
-    def __init__(self):
-        self._last_pt = None
-        self.segments = []
-
-    def _add_segment(self, tag, *args):
-        if tag in ['move', 'line', 'qcurve', 'curve']:
-            self._last_pt = args[-1]
-        self.segments.append((tag, args))
-
-    def moveTo(self, pt):
-        self._add_segment('move', pt)
-
-    def lineTo(self, pt):
-        self._add_segment('line', pt)
-
-    def qCurveTo(self, *points):
-        self._add_segment('qcurve', self._last_pt, *points)
-
-    def curveTo(self, *points):
-        self._add_segment('curve', self._last_pt, *points)
-
-    def closePath(self):
-        self._add_segment('close')
-
-    def endPath(self):
-        self._add_segment('end')
-
-    def addComponent(self, glyphName, transformation):
-        pass
-
-
-def _get_segments(glyph):
-    """Get a glyph's segments as extracted by GetSegmentsPen."""
-
-    pen = GetSegmentsPen()
-    # glyph.draw(pen)
-    # We can't simply draw the glyph with the pen, but we must initialize the
-    # PointToSegmentPen explicitly with outputImpliedClosingLine=True.
-    # By default PointToSegmentPen does not outputImpliedClosingLine -- unless
-    # last and first point on closed contour are duplicated. Because we are
-    # converting multiple glyphs at the same time, we want to make sure
-    # this function returns the same number of segments, whether or not
-    # the last and first point overlap.
-    # https://github.com/googlefonts/fontmake/issues/572
-    # https://github.com/fonttools/fonttools/pull/1720
-    pointPen = PointToSegmentPen(pen, outputImpliedClosingLine=True)
-    glyph.drawPoints(pointPen)
-    return pen.segments
-
-
-def _set_segments(glyph, segments, reverse_direction):
-    """Draw segments as extracted by GetSegmentsPen back to a glyph."""
-
-    glyph.clearContours()
-    pen = glyph.getPen()
-    if reverse_direction:
-        pen = ReverseContourPen(pen)
-    for tag, args in segments:
-        if tag == 'move':
-            pen.moveTo(*args)
-        elif tag == 'line':
-            pen.lineTo(*args)
-        elif tag == 'curve':
-            pen.curveTo(*args[1:])
-        elif tag == 'qcurve':
-            pen.qCurveTo(*args[1:])
-        elif tag == 'close':
-            pen.closePath()
-        elif tag == 'end':
-            pen.endPath()
-        else:
-            raise AssertionError('Unhandled segment type "%s"' % tag)
-
-
-def _segments_to_quadratic(segments, max_err, stats):
-    """Return quadratic approximations of cubic segments."""
-
-    assert all(s[0] == 'curve' for s in segments), 'Non-cubic given to convert'
-
-    new_points = curves_to_quadratic([s[1] for s in segments], max_err)
-    n = len(new_points[0])
-    assert all(len(s) == n for s in new_points[1:]), 'Converted incompatibly'
-
-    spline_length = str(n - 2)
-    stats[spline_length] = stats.get(spline_length, 0) + 1
-
-    return [('qcurve', p) for p in new_points]
-
-
-def _glyphs_to_quadratic(glyphs, max_err, reverse_direction, stats):
-    """Do the actual conversion of a set of compatible glyphs, after arguments
-    have been set up.
-
-    Return True if the glyphs were modified, else return False.
-    """
-
-    try:
-        segments_by_location = zip(*[_get_segments(g) for g in glyphs])
-    except UnequalZipLengthsError:
-        raise IncompatibleSegmentNumberError(glyphs)
-    if not any(segments_by_location):
-        return False
-
-    # always modify input glyphs if reverse_direction is True
-    glyphs_modified = reverse_direction
-
-    new_segments_by_location = []
-    incompatible = {}
-    for i, segments in enumerate(segments_by_location):
-        tag = segments[0][0]
-        if not all(s[0] == tag for s in segments[1:]):
-            incompatible[i] = [s[0] for s in segments]
-        elif tag == 'curve':
-            segments = _segments_to_quadratic(segments, max_err, stats)
-            glyphs_modified = True
-        new_segments_by_location.append(segments)
-
-    if glyphs_modified:
-        new_segments_by_glyph = zip(*new_segments_by_location)
-        for glyph, new_segments in zip(glyphs, new_segments_by_glyph):
-            _set_segments(glyph, new_segments, reverse_direction)
-
-    if incompatible:
-        raise IncompatibleSegmentTypesError(glyphs, segments=incompatible)
-    return glyphs_modified
-
-
-def glyphs_to_quadratic(
-        glyphs, max_err=None, reverse_direction=False, stats=None):
-    """Convert the curves of a set of compatible of glyphs to quadratic.
-
-    All curves will be converted to quadratic at once, ensuring interpolation
-    compatibility. If this is not required, calling glyphs_to_quadratic with one
-    glyph at a time may yield slightly more optimized results.
-
-    Return True if glyphs were modified, else return False.
-
-    Raises IncompatibleGlyphsError if glyphs have non-interpolatable outlines.
-    """
-    if stats is None:
-        stats = {}
-
-    if not max_err:
-        # assume 1000 is the default UPEM
-        max_err = DEFAULT_MAX_ERR * 1000
-
-    if isinstance(max_err, (list, tuple)):
-        max_errors = max_err
-    else:
-        max_errors = [max_err] * len(glyphs)
-    assert len(max_errors) == len(glyphs)
-
-    return _glyphs_to_quadratic(glyphs, max_errors, reverse_direction, stats)
-
-
-def fonts_to_quadratic(
-        fonts, max_err_em=None, max_err=None, reverse_direction=False,
-        stats=None, dump_stats=False, remember_curve_type=True):
-    """Convert the curves of a collection of fonts to quadratic.
-
-    All curves will be converted to quadratic at once, ensuring interpolation
-    compatibility. If this is not required, calling fonts_to_quadratic with one
-    font at a time may yield slightly more optimized results.
-
-    Return True if fonts were modified, else return False.
-
-    By default, cu2qu stores the curve type in the fonts' lib, under a private
-    key "com.github.googlei18n.cu2qu.curve_type", and will not try to convert
-    them again if the curve type is already set to "quadratic".
-    Setting 'remember_curve_type' to False disables this optimization.
-
-    Raises IncompatibleFontsError if same-named glyphs from different fonts
-    have non-interpolatable outlines.
-    """
-
-    if remember_curve_type:
-        curve_types = {f.lib.get(CURVE_TYPE_LIB_KEY, "cubic") for f in fonts}
-        if len(curve_types) == 1:
-            curve_type = next(iter(curve_types))
-            if curve_type == "quadratic":
-                logger.info("Curves already converted to quadratic")
-                return False
-            elif curve_type == "cubic":
-                pass  # keep converting
-            else:
-                raise NotImplementedError(curve_type)
-        elif len(curve_types) > 1:
-            # going to crash later if they do differ
-            logger.warning("fonts may contain different curve types")
-
-    if stats is None:
-        stats = {}
-
-    if max_err_em and max_err:
-        raise TypeError('Only one of max_err and max_err_em can be specified.')
-    if not (max_err_em or max_err):
-        max_err_em = DEFAULT_MAX_ERR
-
-    if isinstance(max_err, (list, tuple)):
-        assert len(max_err) == len(fonts)
-        max_errors = max_err
-    elif max_err:
-        max_errors = [max_err] * len(fonts)
-
-    if isinstance(max_err_em, (list, tuple)):
-        assert len(fonts) == len(max_err_em)
-        max_errors = [f.info.unitsPerEm * e
-                      for f, e in zip(fonts, max_err_em)]
-    elif max_err_em:
-        max_errors = [f.info.unitsPerEm * max_err_em for f in fonts]
-
-    modified = False
-    glyph_errors = {}
-    for name in set().union(*(f.keys() for f in fonts)):
-        glyphs = []
-        cur_max_errors = []
-        for font, error in zip(fonts, max_errors):
-            if name in font:
-                glyphs.append(font[name])
-                cur_max_errors.append(error)
-        try:
-            modified |= _glyphs_to_quadratic(
-                glyphs, cur_max_errors, reverse_direction, stats)
-        except IncompatibleGlyphsError as exc:
-            logger.error(exc)
-            glyph_errors[name] = exc
-
-    if glyph_errors:
-        raise IncompatibleFontsError(glyph_errors)
-
-    if modified and dump_stats:
-        spline_lengths = sorted(stats.keys())
-        logger.info('New spline lengths: %s' % (', '.join(
-                    '%s: %d' % (l, stats[l]) for l in spline_lengths)))
-
-    if remember_curve_type:
-        for font in fonts:
-            curve_type = font.lib.get(CURVE_TYPE_LIB_KEY, "cubic")
-            if curve_type != "quadratic":
-                font.lib[CURVE_TYPE_LIB_KEY] = "quadratic"
-                modified = True
-    return modified
-
-
-def glyph_to_quadratic(glyph, **kwargs):
-    """Convenience wrapper around glyphs_to_quadratic, for just one glyph.
-    Return True if the glyph was modified, else return False.
-    """
-
-    return glyphs_to_quadratic([glyph], **kwargs)
-
-
-def font_to_quadratic(font, **kwargs):
-    """Convenience wrapper around fonts_to_quadratic, for just one font.
-    Return True if the font was modified, else return False.
-    """
-
-    return fonts_to_quadratic([font], **kwargs)
diff --git a/Lib/fontTools/designspaceLib/__init__.py b/Lib/fontTools/designspaceLib/__init__.py
index 9ea22fe..e40f5ed 100644
--- a/Lib/fontTools/designspaceLib/__init__.py
+++ b/Lib/fontTools/designspaceLib/__init__.py
@@ -1,9 +1,9 @@
 # -*- coding: utf-8 -*-
 
-from fontTools.misc.py23 import tobytes, tostr
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.loggingTools import LogMixin
 import collections
-from io import BytesIO, StringIO
 import os
 import posixpath
 from fontTools.misc import etree as ET
@@ -101,32 +101,14 @@
               'mutedGlyphNames',
               'familyName', 'styleName']
 
-    def __init__(
-        self,
-        *,
-        filename=None,
-        path=None,
-        font=None,
-        name=None,
-        location=None,
-        layerName=None,
-        familyName=None,
-        styleName=None,
-        copyLib=False,
-        copyInfo=False,
-        copyGroups=False,
-        copyFeatures=False,
-        muteKerning=False,
-        muteInfo=False,
-        mutedGlyphNames=None,
-    ):
-        self.filename = filename
+    def __init__(self):
+        self.filename = None
         """The original path as found in the document."""
 
-        self.path = path
+        self.path = None
         """The absolute path, calculated from filename."""
 
-        self.font = font
+        self.font = None
         """Any Python object. Optional. Points to a representation of this
         source font that is loaded in memory, as a Python object (e.g. a
         ``defcon.Font`` or a ``fontTools.ttFont.TTFont``).
@@ -138,19 +120,18 @@
         this field to the disk and make ```filename`` point to that.
         """
 
-        self.name = name
-        self.location = location
-        self.layerName = layerName
-        self.familyName = familyName
-        self.styleName = styleName
-
-        self.copyLib = copyLib
-        self.copyInfo = copyInfo
-        self.copyGroups = copyGroups
-        self.copyFeatures = copyFeatures
-        self.muteKerning = muteKerning
-        self.muteInfo = muteInfo
-        self.mutedGlyphNames = mutedGlyphNames or []
+        self.name = None
+        self.location = None
+        self.layerName = None
+        self.copyLib = False
+        self.copyInfo = False
+        self.copyGroups = False
+        self.copyFeatures = False
+        self.muteKerning = False
+        self.muteInfo = False
+        self.mutedGlyphNames = []
+        self.familyName = None
+        self.styleName = None
 
     path = posixpath_property("_path")
     filename = posixpath_property("_filename")
@@ -172,12 +153,10 @@
     """
     _attrs = ['name', 'conditionSets', 'subs']   # what do we need here
 
-    def __init__(self, *, name=None, conditionSets=None, subs=None):
-        self.name = name
-        # list of lists of dict(name='aaaa', minimum=0, maximum=1000)
-        self.conditionSets = conditionSets or []
-        # list of substitutions stored as tuples of glyphnames ("a", "a.alt")
-        self.subs = subs or []
+    def __init__(self):
+        self.name = None
+        self.conditionSets = []  # list of list of dict(name='aaaa', minimum=0, maximum=1000)
+        self.subs = []  # list of substitutions stored as tuples of glyphnames ("a", "a.alt")
 
 
 def evaluateRule(rule, location):
@@ -204,7 +183,7 @@
 
 
 def processRules(rules, location, glyphNames):
-    """ Apply these rules at this location to these glyphnames
+    """ Apply these rules at this location to these glyphnames.minimum
         - rule order matters
     """
     newNames = []
@@ -241,75 +220,50 @@
               'info',
               'lib']
 
-    def __init__(
-        self,
-        *,
-        filename=None,
-        path=None,
-        font=None,
-        name=None,
-        location=None,
-        familyName=None,
-        styleName=None,
-        postScriptFontName=None,
-        styleMapFamilyName=None,
-        styleMapStyleName=None,
-        localisedFamilyName=None,
-        localisedStyleName=None,
-        localisedStyleMapFamilyName=None,
-        localisedStyleMapStyleName=None,
-        glyphs=None,
-        kerning=True,
-        info=True,
-        lib=None,
-    ):
-        # the original path as found in the document
-        self.filename = filename
-        # the absolute path, calculated from filename
-        self.path = path
-        # Same as in SourceDescriptor.
-        self.font = font
-        self.name = name
-        self.location = location
-        self.familyName = familyName
-        self.styleName = styleName
-        self.postScriptFontName = postScriptFontName
-        self.styleMapFamilyName = styleMapFamilyName
-        self.styleMapStyleName = styleMapStyleName
-        self.localisedFamilyName = localisedFamilyName or {}
-        self.localisedStyleName = localisedStyleName or {}
-        self.localisedStyleMapFamilyName = localisedStyleMapFamilyName or {}
-        self.localisedStyleMapStyleName = localisedStyleMapStyleName or {}
-        self.glyphs = glyphs or {}
-        self.kerning = kerning
-        self.info = info
+    def __init__(self):
+        self.filename = None    # the original path as found in the document
+        self.path = None        # the absolute path, calculated from filename
+        self.name = None
+        self.location = None
+        self.familyName = None
+        self.styleName = None
+        self.postScriptFontName = None
+        self.styleMapFamilyName = None
+        self.styleMapStyleName = None
+        self.localisedStyleName = {}
+        self.localisedFamilyName = {}
+        self.localisedStyleMapStyleName = {}
+        self.localisedStyleMapFamilyName = {}
+        self.glyphs = {}
+        self.kerning = True
+        self.info = True
 
-        self.lib = lib or {}
+        self.lib = {}
         """Custom data associated with this instance."""
 
     path = posixpath_property("_path")
     filename = posixpath_property("_filename")
 
     def setStyleName(self, styleName, languageCode="en"):
-        self.localisedStyleName[languageCode] = tostr(styleName)
+        self.localisedStyleName[languageCode] = tounicode(styleName)
 
     def getStyleName(self, languageCode="en"):
         return self.localisedStyleName.get(languageCode)
 
     def setFamilyName(self, familyName, languageCode="en"):
-        self.localisedFamilyName[languageCode] = tostr(familyName)
+        self.localisedFamilyName[languageCode] = tounicode(familyName)
 
     def getFamilyName(self, languageCode="en"):
         return self.localisedFamilyName.get(languageCode)
 
     def setStyleMapStyleName(self, styleMapStyleName, languageCode="en"):
-        self.localisedStyleMapStyleName[languageCode] = tostr(styleMapStyleName)
+        self.localisedStyleMapStyleName[languageCode] = tounicode(styleMapStyleName)
 
     def getStyleMapStyleName(self, languageCode="en"):
         return self.localisedStyleMapStyleName.get(languageCode)
 
     def setStyleMapFamilyName(self, styleMapFamilyName, languageCode="en"):
-        self.localisedStyleMapFamilyName[languageCode] = tostr(styleMapFamilyName)
+        self.localisedStyleMapFamilyName[languageCode] = tounicode(styleMapFamilyName)
 
     def getStyleMapFamilyName(self, languageCode="en"):
         return self.localisedStyleMapFamilyName.get(languageCode)
@@ -340,29 +294,15 @@
     flavor = "axis"
     _attrs = ['tag', 'name', 'maximum', 'minimum', 'default', 'map']
 
-    def __init__(
-        self,
-        *,
-        tag=None,
-        name=None,
-        labelNames=None,
-        minimum=None,
-        default=None,
-        maximum=None,
-        hidden=False,
-        map=None,
-    ):
-        # opentype tag for this axis
-        self.tag = tag
-        # name of the axis used in locations
-        self.name = name
-        # names for UI purposes, if this is not a standard axis,
-        self.labelNames = labelNames or {}
-        self.minimum = minimum
-        self.maximum = maximum
-        self.default = default
-        self.hidden = hidden
-        self.map = map or []
+    def __init__(self):
+        self.tag = None       # opentype tag for this axis
+        self.name = None      # name of the axis used in locations
+        self.labelNames = {}  # names for UI purposes, if this is not a standard axis,
+        self.minimum = None
+        self.maximum = None
+        self.default = None
+        self.hidden = False
+        self.map = []
 
     def serialize(self):
         # output to a dict, used in testing
@@ -418,7 +358,7 @@
     def __init__(self, documentPath, documentObject):
         self.path = documentPath
         self.documentObject = documentObject
-        self.documentVersion = "4.1"
+        self.documentVersion = "4.0"
         self.root = ET.Element("designspace")
         self.root.attrib['format'] = self.documentVersion
         self._axes = []     # for use by the writer only
@@ -431,11 +371,7 @@
             self._addAxis(axisObject)
 
         if self.documentObject.rules:
-            if getattr(self.documentObject, "rulesProcessingLast", False):
-                attributes = {"processing": "last"}
-            else:
-                attributes = {}
-            self.root.append(ET.Element("rules", attributes))
+            self.root.append(ET.Element("rules"))
         for ruleObject in self.documentObject.rules:
             self._addRule(ruleObject)
 
@@ -739,14 +675,6 @@
     def readRules(self):
         # we also need to read any conditions that are outside of a condition set.
         rules = []
-        rulesElement = self.root.find(".rules")
-        if rulesElement is not None:
-            processingValue = rulesElement.attrib.get("processing", "first")
-            if processingValue not in {"first", "last"}:
-                raise DesignSpaceDocumentError(
-                    "<rules> processing attribute value is not valid: %r, "
-                    "expected 'first' or 'last'" % processingValue)
-            self.documentObject.rulesProcessingLast = processingValue == "last"
         for ruleElement in self.root.findall(".rules/rule"):
             ruleObject = self.ruleDescriptorClass()
             ruleName = ruleObject.name = ruleElement.attrib.get("name")
@@ -824,7 +752,7 @@
                 # '{http://www.w3.org/XML/1998/namespace}lang'
                 for key, lang in labelNameElement.items():
                     if key == XML_LANG:
-                        axisObject.labelNames[lang] = tostr(labelNameElement.text)
+                        axisObject.labelNames[lang] = tounicode(labelNameElement.text)
             self.documentObject.axes.append(axisObject)
             self.axisDefaults[axisObject.name] = axisObject.default
 
@@ -1068,7 +996,6 @@
         self.instances = []
         self.axes = []
         self.rules = []
-        self.rulesProcessingLast = False
         self.default = None         # name of the default master
 
         self.lib = {}
@@ -1100,10 +1027,10 @@
         return self
 
     def tostring(self, encoding=None):
-        if encoding is str or (
+        if encoding is unicode or (
             encoding is not None and encoding.lower() == "unicode"
         ):
-            f = StringIO()
+            f = UnicodeIO()
             xml_declaration = False
         elif encoding is None or encoding == "utf-8":
             f = BytesIO()
@@ -1189,35 +1116,15 @@
     def addSource(self, sourceDescriptor):
         self.sources.append(sourceDescriptor)
 
-    def addSourceDescriptor(self, **kwargs):
-        source = self.writerClass.sourceDescriptorClass(**kwargs)
-        self.addSource(source)
-        return source
-
     def addInstance(self, instanceDescriptor):
         self.instances.append(instanceDescriptor)
 
-    def addInstanceDescriptor(self, **kwargs):
-        instance = self.writerClass.instanceDescriptorClass(**kwargs)
-        self.addInstance(instance)
-        return instance
-
     def addAxis(self, axisDescriptor):
         self.axes.append(axisDescriptor)
 
-    def addAxisDescriptor(self, **kwargs):
-        axis = self.writerClass.axisDescriptorClass(**kwargs)
-        self.addAxis(axis)
-        return axis
-
     def addRule(self, ruleDescriptor):
         self.rules.append(ruleDescriptor)
 
-    def addRuleDescriptor(self, **kwargs):
-        rule = self.writerClass.ruleDescriptorClass(**kwargs)
-        self.addRule(rule)
-        return rule
-
     def newDefaultLocation(self):
         """Return default location in design space."""
         # Without OrderedDict, output XML would be non-deterministic.
diff --git a/Lib/fontTools/encodings/MacRoman.py b/Lib/fontTools/encodings/MacRoman.py
index 25232d3..43c58eb 100644
--- a/Lib/fontTools/encodings/MacRoman.py
+++ b/Lib/fontTools/encodings/MacRoman.py
@@ -1,3 +1,6 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+
 MacRoman = [
 		'NUL', 'Eth', 'eth', 'Lslash', 'lslash', 'Scaron', 'scaron', 'Yacute',
 		'yacute', 'HT', 'LF', 'Thorn', 'thorn', 'CR', 'Zcaron', 'zcaron', 'DLE', 'DC1',
diff --git a/Lib/fontTools/encodings/StandardEncoding.py b/Lib/fontTools/encodings/StandardEncoding.py
index 810b2a0..dc01ef8 100644
--- a/Lib/fontTools/encodings/StandardEncoding.py
+++ b/Lib/fontTools/encodings/StandardEncoding.py
@@ -1,3 +1,6 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+
 StandardEncoding = [
 		'.notdef', '.notdef', '.notdef', '.notdef', '.notdef',
 		'.notdef', '.notdef', '.notdef', '.notdef', '.notdef',
diff --git a/Lib/fontTools/encodings/__init__.py b/Lib/fontTools/encodings/__init__.py
index 156cb23..3f9abc9 100644
--- a/Lib/fontTools/encodings/__init__.py
+++ b/Lib/fontTools/encodings/__init__.py
@@ -1 +1,4 @@
 """Empty __init__.py file to signal Python this directory is a package."""
+
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
diff --git a/Lib/fontTools/encodings/codecs.py b/Lib/fontTools/encodings/codecs.py
index 3b1a825..5e401f0 100644
--- a/Lib/fontTools/encodings/codecs.py
+++ b/Lib/fontTools/encodings/codecs.py
@@ -1,6 +1,8 @@
 """Extend the Python codecs module with a few encodings that are used in OpenType (name table)
 but missing from Python.  See https://github.com/fonttools/fonttools/issues/236 for details."""
 
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 import codecs
 import encodings
 
@@ -15,29 +17,43 @@
 		self.info = codecs.CodecInfo(name=self.name, encode=self.encode, decode=self.decode)
 		codecs.register_error(name, self.error)
 
-	def _map(self, mapper, output_type, exc_type, input, errors):
-		base_error_handler = codecs.lookup_error(errors)
+	def encode(self, input, errors='strict'):
+		assert errors == 'strict'
+		#return codecs.encode(input, self.base_encoding, self.name), len(input)
+
+		# The above line could totally be all we needed, relying on the error
+		# handling to replace the unencodable Unicode characters with our extended
+		# byte sequences.
+		#
+		# However, there seems to be a design bug in Python (probably intentional):
+		# the error handler for encoding is supposed to return a **Unicode** character,
+		# that then needs to be encodable itself...  Ugh.
+		#
+		# So we implement what codecs.encode() should have been doing: which is expect
+		# error handler to return bytes() to be added to the output.
+		#
+		# This seems to have been fixed in Python 3.3.  We should try using that and
+		# use fallback only if that failed.
+		# https://docs.python.org/3.3/library/codecs.html#codecs.register_error
+
 		length = len(input)
-		out = output_type()
+		out = b''
 		while input:
-			# first try to use self.error as the error handler
 			try:
-				part = mapper(input, self.base_encoding, errors=self.name)
+				part = codecs.encode(input, self.base_encoding)
 				out += part
-				break  # All converted
-			except exc_type as e:
-				# else convert the correct part, handle error as requested and continue
-				out += mapper(input[:e.start], self.base_encoding, self.name)
-				replacement, pos = base_error_handler(e)
+				input = '' # All converted
+			except UnicodeEncodeError as e:
+				# Convert the correct part
+				out += codecs.encode(input[:e.start], self.base_encoding)
+				replacement, pos = self.error(e)
 				out += replacement
 				input = input[pos:]
 		return out, length
 
-	def encode(self, input, errors='strict'):
-		return self._map(codecs.encode, bytes, UnicodeEncodeError, input, errors)
-
 	def decode(self, input, errors='strict'):
-		return self._map(codecs.decode, str, UnicodeDecodeError, input, errors)
+		assert errors == 'strict'
+		return codecs.decode(input, self.base_encoding, self.name), len(input)
 
 	def error(self, e):
 		if isinstance(e, UnicodeDecodeError):
@@ -56,35 +72,35 @@
 
 _extended_encodings = {
 	"x_mac_japanese_ttx": ("shift_jis", {
-					b"\xFC": chr(0x007C),
-					b"\x7E": chr(0x007E),
-					b"\x80": chr(0x005C),
-					b"\xA0": chr(0x00A0),
-					b"\xFD": chr(0x00A9),
-					b"\xFE": chr(0x2122),
-					b"\xFF": chr(0x2026),
+					b"\xFC": unichr(0x007C),
+					b"\x7E": unichr(0x007E),
+					b"\x80": unichr(0x005C),
+					b"\xA0": unichr(0x00A0),
+					b"\xFD": unichr(0x00A9),
+					b"\xFE": unichr(0x2122),
+					b"\xFF": unichr(0x2026),
 				}),
 	"x_mac_trad_chinese_ttx": ("big5", {
-					b"\x80": chr(0x005C),
-					b"\xA0": chr(0x00A0),
-					b"\xFD": chr(0x00A9),
-					b"\xFE": chr(0x2122),
-					b"\xFF": chr(0x2026),
+					b"\x80": unichr(0x005C),
+					b"\xA0": unichr(0x00A0),
+					b"\xFD": unichr(0x00A9),
+					b"\xFE": unichr(0x2122),
+					b"\xFF": unichr(0x2026),
 				}),
 	"x_mac_korean_ttx": ("euc_kr", {
-					b"\x80": chr(0x00A0),
-					b"\x81": chr(0x20A9),
-					b"\x82": chr(0x2014),
-					b"\x83": chr(0x00A9),
-					b"\xFE": chr(0x2122),
-					b"\xFF": chr(0x2026),
+					b"\x80": unichr(0x00A0),
+					b"\x81": unichr(0x20A9),
+					b"\x82": unichr(0x2014),
+					b"\x83": unichr(0x00A9),
+					b"\xFE": unichr(0x2122),
+					b"\xFF": unichr(0x2026),
 				}),
 	"x_mac_simp_chinese_ttx": ("gb2312", {
-					b"\x80": chr(0x00FC),
-					b"\xA0": chr(0x00A0),
-					b"\xFD": chr(0x00A9),
-					b"\xFE": chr(0x2122),
-					b"\xFF": chr(0x2026),
+					b"\x80": unichr(0x00FC),
+					b"\xA0": unichr(0x00A0),
+					b"\xFD": unichr(0x00A9),
+					b"\xFE": unichr(0x2122),
+					b"\xFF": unichr(0x2026),
 				}),
 }
 
diff --git a/Lib/fontTools/feaLib/__main__.py b/Lib/fontTools/feaLib/__main__.py
index 99c6423..da4eff6 100644
--- a/Lib/fontTools/feaLib/__main__.py
+++ b/Lib/fontTools/feaLib/__main__.py
@@ -1,6 +1,7 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.ttLib import TTFont
 from fontTools.feaLib.builder import addOpenTypeFeatures, Builder
-from fontTools.feaLib.error import FeatureLibError
 from fontTools import configLogger
 from fontTools.misc.cliTools import makeOutputFileName
 import sys
@@ -12,47 +13,21 @@
 
 
 def main(args=None):
-    """Add features from a feature file (.fea) into a OTF font"""
     parser = argparse.ArgumentParser(
-        description="Use fontTools to compile OpenType feature files (*.fea)."
-    )
+        description="Use fontTools to compile OpenType feature files (*.fea).")
     parser.add_argument(
-        "input_fea", metavar="FEATURES", help="Path to the feature file"
-    )
+        "input_fea", metavar="FEATURES", help="Path to the feature file")
     parser.add_argument(
-        "input_font", metavar="INPUT_FONT", help="Path to the input font"
-    )
+        "input_font", metavar="INPUT_FONT", help="Path to the input font")
     parser.add_argument(
-        "-o",
-        "--output",
-        dest="output_font",
-        metavar="OUTPUT_FONT",
-        help="Path to the output font.",
-    )
+        "-o", "--output", dest="output_font", metavar="OUTPUT_FONT",
+        help="Path to the output font.")
     parser.add_argument(
-        "-t",
-        "--tables",
-        metavar="TABLE_TAG",
-        choices=Builder.supportedTables,
-        nargs="+",
-        help="Specify the table(s) to be built.",
-    )
+        "-t", "--tables", metavar="TABLE_TAG", choices=Builder.supportedTables,
+        nargs='+', help="Specify the table(s) to be built.")
     parser.add_argument(
-        "-d",
-        "--debug",
-        action="store_true",
-        help="Add source-level debugging information to font.",
-    )
-    parser.add_argument(
-        "-v",
-        "--verbose",
-        help="increase the logger verbosity. Multiple -v " "options are allowed.",
-        action="count",
-        default=0,
-    )
-    parser.add_argument(
-        "--traceback", help="show traceback for exceptions.", action="store_true"
-    )
+        "-v", "--verbose", help="increase the logger verbosity. Multiple -v "
+        "options are allowed.", action="count", default=0)
     options = parser.parse_args(args)
 
     levels = ["WARNING", "INFO", "DEBUG"]
@@ -62,16 +37,9 @@
     log.info("Compiling features to '%s'" % (output_font))
 
     font = TTFont(options.input_font)
-    try:
-        addOpenTypeFeatures(
-            font, options.input_fea, tables=options.tables, debug=options.debug
-        )
-    except FeatureLibError as e:
-        if options.traceback:
-            raise
-        log.error(e)
+    addOpenTypeFeatures(font, options.input_fea, tables=options.tables)
     font.save(output_font)
 
 
-if __name__ == "__main__":
+if __name__ == '__main__':
     sys.exit(main())
diff --git a/Lib/fontTools/feaLib/ast.py b/Lib/fontTools/feaLib/ast.py
index 763d0d2..1994fc0 100644
--- a/Lib/fontTools/feaLib/ast.py
+++ b/Lib/fontTools/feaLib/ast.py
@@ -1,6 +1,7 @@
-from fontTools.misc.py23 import byteord, tobytes
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.feaLib.error import FeatureLibError
-from fontTools.feaLib.location import FeatureLibLocation
 from fontTools.misc.encodingTools import getEncoding
 from collections import OrderedDict
 import itertools
@@ -8,71 +9,73 @@
 SHIFT = " " * 4
 
 __all__ = [
-    "Element",
-    "FeatureFile",
-    "Comment",
-    "GlyphName",
-    "GlyphClass",
-    "GlyphClassName",
-    "MarkClassName",
-    "AnonymousBlock",
-    "Block",
-    "FeatureBlock",
-    "NestedBlock",
-    "LookupBlock",
-    "GlyphClassDefinition",
-    "GlyphClassDefStatement",
-    "MarkClass",
-    "MarkClassDefinition",
-    "AlternateSubstStatement",
-    "Anchor",
-    "AnchorDefinition",
-    "AttachStatement",
-    "AxisValueLocationStatement",
-    "BaseAxis",
-    "CVParametersNameStatement",
-    "ChainContextPosStatement",
-    "ChainContextSubstStatement",
-    "CharacterStatement",
-    "CursivePosStatement",
-    "ElidedFallbackName",
-    "ElidedFallbackNameID",
-    "Expression",
-    "FeatureNameStatement",
-    "FeatureReferenceStatement",
-    "FontRevisionStatement",
-    "HheaField",
-    "IgnorePosStatement",
-    "IgnoreSubstStatement",
-    "IncludeStatement",
-    "LanguageStatement",
-    "LanguageSystemStatement",
-    "LigatureCaretByIndexStatement",
-    "LigatureCaretByPosStatement",
-    "LigatureSubstStatement",
-    "LookupFlagStatement",
-    "LookupReferenceStatement",
-    "MarkBasePosStatement",
-    "MarkLigPosStatement",
-    "MarkMarkPosStatement",
-    "MultipleSubstStatement",
-    "NameRecord",
-    "OS2Field",
-    "PairPosStatement",
-    "ReverseChainSingleSubstStatement",
-    "ScriptStatement",
-    "SinglePosStatement",
-    "SingleSubstStatement",
-    "SizeParameters",
-    "Statement",
-    "STATAxisValueStatement",
-    "STATDesignAxisStatement",
-    "STATNameStatement",
-    "SubtableStatement",
-    "TableBlock",
-    "ValueRecord",
-    "ValueRecordDefinition",
-    "VheaField",
+    'AlternateSubstStatement',
+    'Anchor',
+    'AnchorDefinition',
+    'AnonymousBlock',
+    'AttachStatement',
+    'BaseAxis',
+    'Block',
+    'BytesIO',
+    'CVParametersNameStatement',
+    'ChainContextPosStatement',
+    'ChainContextSubstStatement',
+    'CharacterStatement',
+    'Comment',
+    'CursivePosStatement',
+    'Element',
+    'Expression',
+    'FeatureBlock',
+    'FeatureFile',
+    'FeatureLibError',
+    'FeatureNameStatement',
+    'FeatureReferenceStatement',
+    'FontRevisionStatement',
+    'GlyphClass',
+    'GlyphClassDefStatement',
+    'GlyphClassDefinition',
+    'GlyphClassName',
+    'GlyphName',
+    'HheaField',
+    'IgnorePosStatement',
+    'IgnoreSubstStatement',
+    'IncludeStatement',
+    'LanguageStatement',
+    'LanguageSystemStatement',
+    'LigatureCaretByIndexStatement',
+    'LigatureCaretByPosStatement',
+    'LigatureSubstStatement',
+    'LookupBlock',
+    'LookupFlagStatement',
+    'LookupReferenceStatement',
+    'MarkBasePosStatement',
+    'MarkClass',
+    'MarkClassDefinition',
+    'MarkClassName',
+    'MarkLigPosStatement',
+    'MarkMarkPosStatement',
+    'MultipleSubstStatement',
+    'NameRecord',
+    'NestedBlock',
+    'OS2Field',
+    'OrderedDict',
+    'PairPosStatement',
+    'Py23Error',
+    'ReverseChainSingleSubstStatement',
+    'ScriptStatement',
+    'SimpleNamespace',
+    'SinglePosStatement',
+    'SingleSubstStatement',
+    'SizeParameters',
+    'Statement',
+    'StringIO',
+    'SubtableStatement',
+    'TableBlock',
+    'Tag',
+    'UnicodeIO',
+    'ValueRecord',
+    'ValueRecordDefinition',
+    'VheaField',
 ]
 
 
@@ -83,69 +86,32 @@
         return "<device %s>" % ", ".join("%d %d" % t for t in device)
 
 
-fea_keywords = set(
-    [
-        "anchor",
-        "anchordef",
-        "anon",
-        "anonymous",
-        "by",
-        "contour",
-        "cursive",
-        "device",
-        "enum",
-        "enumerate",
-        "excludedflt",
-        "exclude_dflt",
-        "feature",
-        "from",
-        "ignore",
-        "ignorebaseglyphs",
-        "ignoreligatures",
-        "ignoremarks",
-        "include",
-        "includedflt",
-        "include_dflt",
-        "language",
-        "languagesystem",
-        "lookup",
-        "lookupflag",
-        "mark",
-        "markattachmenttype",
-        "markclass",
-        "nameid",
-        "null",
-        "parameters",
-        "pos",
-        "position",
-        "required",
-        "righttoleft",
-        "reversesub",
-        "rsub",
-        "script",
-        "sub",
-        "substitute",
-        "subtable",
-        "table",
-        "usemarkfilteringset",
-        "useextension",
-        "valuerecorddef",
-        "base",
-        "gdef",
-        "head",
-        "hhea",
-        "name",
-        "vhea",
-        "vmtx",
-    ]
+fea_keywords = set([
+    "anchor", "anchordef", "anon", "anonymous",
+    "by",
+    "contour", "cursive",
+    "device",
+    "enum", "enumerate", "excludedflt", "exclude_dflt",
+    "feature", "from",
+    "ignore", "ignorebaseglyphs", "ignoreligatures", "ignoremarks",
+    "include", "includedflt", "include_dflt",
+    "language", "languagesystem", "lookup", "lookupflag",
+    "mark", "markattachmenttype", "markclass",
+    "nameid", "null",
+    "parameters", "pos", "position",
+    "required", "righttoleft", "reversesub", "rsub",
+    "script", "sub", "substitute", "subtable",
+    "table",
+    "usemarkfilteringset", "useextension", "valuerecorddef",
+    "base", "gdef", "head", "hhea", "name", "vhea", "vmtx"]
 )
 
 
 def asFea(g):
-    if hasattr(g, "asFea"):
+    if hasattr(g, 'asFea'):
         return g.asFea()
     elif isinstance(g, tuple) and len(g) == 2:
-        return asFea(g[0]) + " - " + asFea(g[1])  # a range
+        return asFea(g[0]) + "-" + asFea(g[1])   # a range
     elif g.lower() in fea_keywords:
         return "\\" + g
     else:
@@ -153,21 +119,14 @@
 
 
 class Element(object):
-    """A base class representing "something" in a feature file."""
 
     def __init__(self, location=None):
-        #: location of this element as a `FeatureLibLocation` object.
-        if location and not isinstance(location, FeatureLibLocation):
-            location = FeatureLibLocation(*location)
         self.location = location
 
     def build(self, builder):
         pass
 
     def asFea(self, indent=""):
-        """Returns this element as a string of feature code. For block-type
-        elements (such as :class:`FeatureBlock`), the `indent` string is
-        added to the start of each line in the output."""
         raise NotImplementedError
 
     def __str__(self):
@@ -183,42 +142,21 @@
 
 
 class Comment(Element):
-    """A comment in a feature file."""
-
     def __init__(self, text, location=None):
         super(Comment, self).__init__(location)
-        #: Text of the comment
         self.text = text
 
     def asFea(self, indent=""):
         return self.text
 
 
-class NullGlyph(Expression):
-    """The NULL glyph, used in glyph deletion substitutions."""
-
-    def __init__(self, location=None):
-        Expression.__init__(self, location)
-        #: The name itself as a string
-
-    def glyphSet(self):
-        """The glyphs in this class as a tuple of :class:`GlyphName` objects."""
-        return ()
-
-    def asFea(self, indent=""):
-        return "NULL"
-
-
 class GlyphName(Expression):
-    """A single glyph name, such as ``cedilla``."""
-
+    """A single glyph name, such as cedilla."""
     def __init__(self, glyph, location=None):
         Expression.__init__(self, location)
-        #: The name itself as a string
         self.glyph = glyph
 
     def glyphSet(self):
-        """The glyphs in this class as a tuple of :class:`GlyphName` objects."""
         return (self.glyph,)
 
     def asFea(self, indent=""):
@@ -226,78 +164,61 @@
 
 
 class GlyphClass(Expression):
-    """A glyph class, such as ``[acute cedilla grave]``."""
-
+    """A glyph class, such as [acute cedilla grave]."""
     def __init__(self, glyphs=None, location=None):
         Expression.__init__(self, location)
-        #: The list of glyphs in this class, as :class:`GlyphName` objects.
         self.glyphs = glyphs if glyphs is not None else []
         self.original = []
         self.curr = 0
 
     def glyphSet(self):
-        """The glyphs in this class as a tuple of :class:`GlyphName` objects."""
         return tuple(self.glyphs)
 
     def asFea(self, indent=""):
         if len(self.original):
             if self.curr < len(self.glyphs):
-                self.original.extend(self.glyphs[self.curr :])
+                self.original.extend(self.glyphs[self.curr:])
                 self.curr = len(self.glyphs)
             return "[" + " ".join(map(asFea, self.original)) + "]"
         else:
             return "[" + " ".join(map(asFea, self.glyphs)) + "]"
 
     def extend(self, glyphs):
-        """Add a list of :class:`GlyphName` objects to the class."""
         self.glyphs.extend(glyphs)
 
     def append(self, glyph):
-        """Add a single :class:`GlyphName` object to the class."""
         self.glyphs.append(glyph)
 
     def add_range(self, start, end, glyphs):
-        """Add a range (e.g. ``A-Z``) to the class. ``start`` and ``end``
-        are either :class:`GlyphName` objects or strings representing the
-        start and end glyphs in the class, and ``glyphs`` is the full list of
-        :class:`GlyphName` objects in the range."""
         if self.curr < len(self.glyphs):
-            self.original.extend(self.glyphs[self.curr :])
+            self.original.extend(self.glyphs[self.curr:])
         self.original.append((start, end))
         self.glyphs.extend(glyphs)
         self.curr = len(self.glyphs)
 
     def add_cid_range(self, start, end, glyphs):
-        """Add a range to the class by glyph ID. ``start`` and ``end`` are the
-        initial and final IDs, and ``glyphs`` is the full list of
-        :class:`GlyphName` objects in the range."""
         if self.curr < len(self.glyphs):
-            self.original.extend(self.glyphs[self.curr :])
-        self.original.append(("\\{}".format(start), "\\{}".format(end)))
+            self.original.extend(self.glyphs[self.curr:])
+        self.original.append(("cid{:05d}".format(start), "cid{:05d}".format(end)))
         self.glyphs.extend(glyphs)
         self.curr = len(self.glyphs)
 
     def add_class(self, gc):
-        """Add glyphs from the given :class:`GlyphClassName` object to the
-        class."""
         if self.curr < len(self.glyphs):
-            self.original.extend(self.glyphs[self.curr :])
+            self.original.extend(self.glyphs[self.curr:])
         self.original.append(gc)
         self.glyphs.extend(gc.glyphSet())
         self.curr = len(self.glyphs)
 
 
 class GlyphClassName(Expression):
-    """A glyph class name, such as ``@FRENCH_MARKS``. This must be instantiated
-    with a :class:`GlyphClassDefinition` object."""
-
+    """A glyph class name, such as @FRENCH_MARKS."""
     def __init__(self, glyphclass, location=None):
         Expression.__init__(self, location)
         assert isinstance(glyphclass, GlyphClassDefinition)
         self.glyphclass = glyphclass
 
     def glyphSet(self):
-        """The glyphs in this class as a tuple of :class:`GlyphName` objects."""
         return tuple(self.glyphclass.glyphSet())
 
     def asFea(self, indent=""):
@@ -305,16 +226,13 @@
 
 
 class MarkClassName(Expression):
-    """A mark class name, such as ``@FRENCH_MARKS`` defined with ``markClass``.
-    This must be instantiated with a :class:`MarkClass` object."""
-
+    """A mark class name, such as @FRENCH_MARKS defined with markClass."""
     def __init__(self, markClass, location=None):
         Expression.__init__(self, location)
         assert isinstance(markClass, MarkClass)
         self.markClass = markClass
 
     def glyphSet(self):
-        """The glyphs in this class as a tuple of :class:`GlyphName` objects."""
         return self.markClass.glyphSet()
 
     def asFea(self, indent=""):
@@ -322,12 +240,9 @@
 
 
 class AnonymousBlock(Statement):
-    """An anonymous data block."""
-
     def __init__(self, tag, content, location=None):
         Statement.__init__(self, location)
-        self.tag = tag  #: string containing the block's "tag"
-        self.content = content  #: block data as string
+        self.tag, self.content = tag, content
 
     def asFea(self, indent=""):
         res = "anon {} {{\n".format(self.tag)
@@ -337,32 +252,21 @@
 
 
 class Block(Statement):
-    """A block of statements: feature, lookup, etc."""
-
     def __init__(self, location=None):
         Statement.__init__(self, location)
-        self.statements = []  #: Statements contained in the block
+        self.statements = []
 
     def build(self, builder):
-        """When handed a 'builder' object of comparable interface to
-        :class:`fontTools.feaLib.builder`, walks the statements in this
-        block, calling the builder callbacks."""
         for s in self.statements:
             s.build(builder)
 
     def asFea(self, indent=""):
         indent += SHIFT
-        return (
-            indent
-            + ("\n" + indent).join([s.asFea(indent=indent) for s in self.statements])
-            + "\n"
-        )
+        return indent + ("\n" + indent).join(
+            [s.asFea(indent=indent) for s in self.statements]) + "\n"
 
 
 class FeatureFile(Block):
-    """The top-level element of the syntax tree, containing the whole feature
-    file in its ``statements`` attribute."""
-
     def __init__(self):
         Block.__init__(self, location=None)
         self.markClasses = {}  # name --> ast.MarkClass
@@ -372,15 +276,11 @@
 
 
 class FeatureBlock(Block):
-    """A named feature block."""
-
     def __init__(self, name, use_extension=False, location=None):
         Block.__init__(self, location)
         self.name, self.use_extension = name, use_extension
 
     def build(self, builder):
-        """Call the ``start_feature`` callback on the builder object, visit
-        all the statements in this feature, and then call ``end_feature``."""
         # TODO(sascha): Handle use_extension.
         builder.start_feature(self.location, self.name)
         # language exclude_dflt statements modify builder.features_
@@ -404,9 +304,6 @@
 
 
 class NestedBlock(Block):
-    """A block inside another block, for example when found inside a
-    ``cvParameters`` block."""
-
     def __init__(self, tag, block_name, location=None):
         Block.__init__(self, location)
         self.tag = tag
@@ -425,8 +322,6 @@
 
 
 class LookupBlock(Block):
-    """A named lookup, containing ``statements``."""
-
     def __init__(self, name, use_extension=False, location=None):
         Block.__init__(self, location)
         self.name, self.use_extension = name, use_extension
@@ -448,8 +343,6 @@
 
 
 class TableBlock(Block):
-    """A ``table ... { }`` block."""
-
     def __init__(self, name, location=None):
         Block.__init__(self, location)
         self.name = name
@@ -462,15 +355,13 @@
 
 
 class GlyphClassDefinition(Statement):
-    """Example: ``@UPPERCASE = [A-Z];``."""
-
+    """Example: @UPPERCASE = [A-Z];"""
     def __init__(self, name, glyphs, location=None):
         Statement.__init__(self, location)
-        self.name = name  #: class name as a string, without initial ``@``
-        self.glyphs = glyphs  #: a :class:`GlyphClass` object
+        self.name = name
+        self.glyphs = glyphs
 
     def glyphSet(self):
-        """The glyphs in this class as a tuple of :class:`GlyphName` objects."""
         return tuple(self.glyphs.glyphSet())
 
     def asFea(self, indent=""):
@@ -478,24 +369,21 @@
 
 
 class GlyphClassDefStatement(Statement):
-    """Example: ``GlyphClassDef @UPPERCASE, [B], [C], [D];``. The parameters
-    must be either :class:`GlyphClass` or :class:`GlyphClassName` objects, or
-    ``None``."""
-
-    def __init__(
-        self, baseGlyphs, markGlyphs, ligatureGlyphs, componentGlyphs, location=None
-    ):
+    """Example: GlyphClassDef @UPPERCASE, [B], [C], [D];"""
+    def __init__(self, baseGlyphs, markGlyphs, ligatureGlyphs,
+                 componentGlyphs, location=None):
         Statement.__init__(self, location)
         self.baseGlyphs, self.markGlyphs = (baseGlyphs, markGlyphs)
         self.ligatureGlyphs = ligatureGlyphs
         self.componentGlyphs = componentGlyphs
 
     def build(self, builder):
-        """Calls the builder's ``add_glyphClassDef`` callback."""
         base = self.baseGlyphs.glyphSet() if self.baseGlyphs else tuple()
-        liga = self.ligatureGlyphs.glyphSet() if self.ligatureGlyphs else tuple()
+        liga = self.ligatureGlyphs.glyphSet() \
+            if self.ligatureGlyphs else tuple()
         mark = self.markGlyphs.glyphSet() if self.markGlyphs else tuple()
-        comp = self.componentGlyphs.glyphSet() if self.componentGlyphs else tuple()
+        comp = (self.componentGlyphs.glyphSet()
+                if self.componentGlyphs else tuple())
         builder.add_glyphClassDef(self.location, base, liga, mark, comp)
 
     def asFea(self, indent=""):
@@ -503,32 +391,22 @@
             self.baseGlyphs.asFea() if self.baseGlyphs else "",
             self.ligatureGlyphs.asFea() if self.ligatureGlyphs else "",
             self.markGlyphs.asFea() if self.markGlyphs else "",
-            self.componentGlyphs.asFea() if self.componentGlyphs else "",
-        )
+            self.componentGlyphs.asFea() if self.componentGlyphs else "")
 
 
+# While glyph classes can be defined only once, the feature file format
+# allows expanding mark classes with multiple definitions, each using
+# different glyphs and anchors. The following are two MarkClassDefinitions
+# for the same MarkClass:
+#     markClass [acute grave] <anchor 350 800> @FRENCH_ACCENTS;
+#     markClass [cedilla] <anchor 350 -200> @FRENCH_ACCENTS;
 class MarkClass(object):
-    """One `or more` ``markClass`` statements for the same mark class.
-
-    While glyph classes can be defined only once, the feature file format
-    allows expanding mark classes with multiple definitions, each using
-    different glyphs and anchors. The following are two ``MarkClassDefinitions``
-    for the same ``MarkClass``::
-
-        markClass [acute grave] <anchor 350 800> @FRENCH_ACCENTS;
-        markClass [cedilla] <anchor 350 -200> @FRENCH_ACCENTS;
-
-    The ``MarkClass`` object is therefore just a container for a list of
-    :class:`MarkClassDefinition` statements.
-    """
-
     def __init__(self, name):
         self.name = name
         self.definitions = []
         self.glyphs = OrderedDict()  # glyph --> ast.MarkClassDefinitions
 
     def addDefinition(self, definition):
-        """Add a :class:`MarkClassDefinition` statement to this mark class."""
         assert isinstance(definition, MarkClassDefinition)
         self.definitions.append(definition)
         for glyph in definition.glyphSet():
@@ -537,14 +415,14 @@
                 if otherLoc is None:
                     end = ""
                 else:
-                    end = f" at {otherLoc}"
+                    end = " at %s:%d:%d" % (
+                        otherLoc[0], otherLoc[1], otherLoc[2])
                 raise FeatureLibError(
-                    "Glyph %s already defined%s" % (glyph, end), definition.location
-                )
+                    "Glyph %s already defined%s" % (glyph, end),
+                    definition.location)
             self.glyphs[glyph] = definition
 
     def glyphSet(self):
-        """The glyphs in this class as a tuple of :class:`GlyphName` objects."""
         return tuple(self.glyphs.keys())
 
     def asFea(self, indent=""):
@@ -553,28 +431,6 @@
 
 
 class MarkClassDefinition(Statement):
-    """A single ``markClass`` statement. The ``markClass`` should be a
-    :class:`MarkClass` object, the ``anchor`` an :class:`Anchor` object,
-    and the ``glyphs`` parameter should be a `glyph-containing object`_ .
-
-    Example:
-
-        .. code:: python
-
-            mc = MarkClass("FRENCH_ACCENTS")
-            mc.addDefinition( MarkClassDefinition(mc, Anchor(350, 800),
-                GlyphClass([ GlyphName("acute"), GlyphName("grave") ])
-            ) )
-            mc.addDefinition( MarkClassDefinition(mc, Anchor(350, -200),
-                GlyphClass([ GlyphName("cedilla") ])
-            ) )
-
-            mc.asFea()
-            # markClass [acute grave] <anchor 350 800> @FRENCH_ACCENTS;
-            # markClass [cedilla] <anchor 350 -200> @FRENCH_ACCENTS;
-
-    """
-
     def __init__(self, markClass, anchor, glyphs, location=None):
         Statement.__init__(self, location)
         assert isinstance(markClass, MarkClass)
@@ -582,42 +438,36 @@
         self.markClass, self.anchor, self.glyphs = markClass, anchor, glyphs
 
     def glyphSet(self):
-        """The glyphs in this class as a tuple of :class:`GlyphName` objects."""
         return self.glyphs.glyphSet()
 
     def asFea(self, indent=""):
         return "markClass {} {} @{};".format(
-            self.glyphs.asFea(), self.anchor.asFea(), self.markClass.name
-        )
+            self.glyphs.asFea(), self.anchor.asFea(),
+            self.markClass.name)
 
 
 class AlternateSubstStatement(Statement):
-    """A ``sub ... from ...`` statement.
-
-    ``prefix``, ``glyph``, ``suffix`` and ``replacement`` should be lists of
-    `glyph-containing objects`_. ``glyph`` should be a `one element list`."""
-
     def __init__(self, prefix, glyph, suffix, replacement, location=None):
         Statement.__init__(self, location)
         self.prefix, self.glyph, self.suffix = (prefix, glyph, suffix)
         self.replacement = replacement
 
     def build(self, builder):
-        """Calls the builder's ``add_alternate_subst`` callback."""
         glyph = self.glyph.glyphSet()
         assert len(glyph) == 1, glyph
         glyph = list(glyph)[0]
         prefix = [p.glyphSet() for p in self.prefix]
         suffix = [s.glyphSet() for s in self.suffix]
         replacement = self.replacement.glyphSet()
-        builder.add_alternate_subst(self.location, prefix, glyph, suffix, replacement)
+        builder.add_alternate_subst(self.location, prefix, glyph, suffix,
+                                    replacement)
 
     def asFea(self, indent=""):
         res = "sub "
         if len(self.prefix) or len(self.suffix):
             if len(self.prefix):
                 res += " ".join(map(asFea, self.prefix)) + " "
-            res += asFea(self.glyph) + "'"  # even though we really only use 1
+            res += asFea(self.glyph) + "'"    # even though we really only use 1
             if len(self.suffix):
                 res += " " + " ".join(map(asFea, self.suffix))
         else:
@@ -629,22 +479,8 @@
 
 
 class Anchor(Expression):
-    """An ``Anchor`` element, used inside a ``pos`` rule.
-
-    If a ``name`` is given, this will be used in preference to the coordinates.
-    Other values should be integer.
-    """
-
-    def __init__(
-        self,
-        x,
-        y,
-        name=None,
-        contourpoint=None,
-        xDeviceTable=None,
-        yDeviceTable=None,
-        location=None,
-    ):
+    def __init__(self, x, y, name=None, contourpoint=None,
+                 xDeviceTable=None, yDeviceTable=None, location=None):
         Expression.__init__(self, location)
         self.name = name
         self.x, self.y, self.contourpoint = x, y, contourpoint
@@ -666,8 +502,6 @@
 
 
 class AnchorDefinition(Statement):
-    """A named anchor definition. (2.e.viii). ``name`` should be a string."""
-
     def __init__(self, name, x, y, contourpoint=None, location=None):
         Statement.__init__(self, location)
         self.name, self.x, self.y, self.contourpoint = name, x, y, contourpoint
@@ -681,72 +515,41 @@
 
 
 class AttachStatement(Statement):
-    """A ``GDEF`` table ``Attach`` statement."""
-
     def __init__(self, glyphs, contourPoints, location=None):
         Statement.__init__(self, location)
-        self.glyphs = glyphs  #: A `glyph-containing object`_
-        self.contourPoints = contourPoints  #: A list of integer contour points
+        self.glyphs, self.contourPoints = (glyphs, contourPoints)
 
     def build(self, builder):
-        """Calls the builder's ``add_attach_points`` callback."""
         glyphs = self.glyphs.glyphSet()
         builder.add_attach_points(self.location, glyphs, self.contourPoints)
 
     def asFea(self, indent=""):
         return "Attach {} {};".format(
-            self.glyphs.asFea(), " ".join(str(c) for c in self.contourPoints)
-        )
+            self.glyphs.asFea(), " ".join(str(c) for c in self.contourPoints))
 
 
 class ChainContextPosStatement(Statement):
-    """A chained contextual positioning statement.
-
-    ``prefix``, ``glyphs``, and ``suffix`` should be lists of
-    `glyph-containing objects`_ .
-
-    ``lookups`` should be a list of elements representing what lookups
-    to apply at each glyph position. Each element should be a
-    :class:`LookupBlock` to apply a single chaining lookup at the given
-    position, a list of :class:`LookupBlock`\ s to apply multiple
-    lookups, or ``None`` to apply no lookup. The length of the outer
-    list should equal the length of ``glyphs``; the inner lists can be
-    of variable length."""
-
     def __init__(self, prefix, glyphs, suffix, lookups, location=None):
         Statement.__init__(self, location)
         self.prefix, self.glyphs, self.suffix = prefix, glyphs, suffix
-        self.lookups = list(lookups)
-        for i, lookup in enumerate(lookups):
-            if lookup:
-                try:
-                    (_ for _ in lookup)
-                except TypeError:
-                    self.lookups[i] = [lookup]
+        self.lookups = lookups
 
     def build(self, builder):
-        """Calls the builder's ``add_chain_context_pos`` callback."""
         prefix = [p.glyphSet() for p in self.prefix]
         glyphs = [g.glyphSet() for g in self.glyphs]
         suffix = [s.glyphSet() for s in self.suffix]
         builder.add_chain_context_pos(
-            self.location, prefix, glyphs, suffix, self.lookups
-        )
+            self.location, prefix, glyphs, suffix, self.lookups)
 
     def asFea(self, indent=""):
         res = "pos "
-        if (
-            len(self.prefix)
-            or len(self.suffix)
-            or any([x is not None for x in self.lookups])
-        ):
+        if len(self.prefix) or len(self.suffix) or any([x is not None for x in self.lookups]):
             if len(self.prefix):
                 res += " ".join(g.asFea() for g in self.prefix) + " "
             for i, g in enumerate(self.glyphs):
                 res += g.asFea() + "'"
-                if self.lookups[i]:
-                    for lu in self.lookups[i]:
-                        res += " lookup " + lu.name
+                if self.lookups[i] is not None:
+                    res += " lookup " + self.lookups[i].name
                 if i < len(self.glyphs) - 1:
                     res += " "
             if len(self.suffix):
@@ -758,53 +561,27 @@
 
 
 class ChainContextSubstStatement(Statement):
-    """A chained contextual substitution statement.
-
-    ``prefix``, ``glyphs``, and ``suffix`` should be lists of
-    `glyph-containing objects`_ .
-
-    ``lookups`` should be a list of elements representing what lookups
-    to apply at each glyph position. Each element should be a
-    :class:`LookupBlock` to apply a single chaining lookup at the given
-    position, a list of :class:`LookupBlock`\ s to apply multiple
-    lookups, or ``None`` to apply no lookup. The length of the outer
-    list should equal the length of ``glyphs``; the inner lists can be
-    of variable length."""
-
     def __init__(self, prefix, glyphs, suffix, lookups, location=None):
         Statement.__init__(self, location)
         self.prefix, self.glyphs, self.suffix = prefix, glyphs, suffix
-        self.lookups = list(lookups)
-        for i, lookup in enumerate(lookups):
-            if lookup:
-                try:
-                    (_ for _ in lookup)
-                except TypeError:
-                    self.lookups[i] = [lookup]
+        self.lookups = lookups
 
     def build(self, builder):
-        """Calls the builder's ``add_chain_context_subst`` callback."""
         prefix = [p.glyphSet() for p in self.prefix]
         glyphs = [g.glyphSet() for g in self.glyphs]
         suffix = [s.glyphSet() for s in self.suffix]
         builder.add_chain_context_subst(
-            self.location, prefix, glyphs, suffix, self.lookups
-        )
+            self.location, prefix, glyphs, suffix, self.lookups)
 
     def asFea(self, indent=""):
         res = "sub "
-        if (
-            len(self.prefix)
-            or len(self.suffix)
-            or any([x is not None for x in self.lookups])
-        ):
+        if len(self.prefix) or len(self.suffix) or any([x is not None for x in self.lookups]):
             if len(self.prefix):
                 res += " ".join(g.asFea() for g in self.prefix) + " "
             for i, g in enumerate(self.glyphs):
                 res += g.asFea() + "'"
-                if self.lookups[i]:
-                    for lu in self.lookups[i]:
-                        res += " lookup " + lu.name
+                if self.lookups[i] is not None:
+                    res += " lookup " + self.lookups[i].name
                 if i < len(self.glyphs) - 1:
                     res += " "
             if len(self.suffix):
@@ -816,19 +593,14 @@
 
 
 class CursivePosStatement(Statement):
-    """A cursive positioning statement. Entry and exit anchors can either
-    be :class:`Anchor` objects or ``None``."""
-
     def __init__(self, glyphclass, entryAnchor, exitAnchor, location=None):
         Statement.__init__(self, location)
         self.glyphclass = glyphclass
         self.entryAnchor, self.exitAnchor = entryAnchor, exitAnchor
 
     def build(self, builder):
-        """Calls the builder object's ``add_cursive_pos`` callback."""
         builder.add_cursive_pos(
-            self.location, self.glyphclass.glyphSet(), self.entryAnchor, self.exitAnchor
-        )
+            self.location, self.glyphclass.glyphSet(), self.entryAnchor, self.exitAnchor)
 
     def asFea(self, indent=""):
         entry = self.entryAnchor.asFea() if self.entryAnchor else "<anchor NULL>"
@@ -837,14 +609,12 @@
 
 
 class FeatureReferenceStatement(Statement):
-    """Example: ``feature salt;``"""
-
+    """Example: feature salt;"""
     def __init__(self, featureName, location=None):
         Statement.__init__(self, location)
         self.location, self.featureName = (location, featureName)
 
     def build(self, builder):
-        """Calls the builder object's ``add_feature_reference`` callback."""
         builder.add_feature_reference(self.location, self.featureName)
 
     def asFea(self, indent=""):
@@ -852,24 +622,17 @@
 
 
 class IgnorePosStatement(Statement):
-    """An ``ignore pos`` statement, containing `one or more` contexts to ignore.
-
-    ``chainContexts`` should be a list of ``(prefix, glyphs, suffix)`` tuples,
-    with each of ``prefix``, ``glyphs`` and ``suffix`` being
-    `glyph-containing objects`_ ."""
-
     def __init__(self, chainContexts, location=None):
         Statement.__init__(self, location)
         self.chainContexts = chainContexts
 
     def build(self, builder):
-        """Calls the builder object's ``add_chain_context_pos`` callback on each
-        rule context."""
         for prefix, glyphs, suffix in self.chainContexts:
             prefix = [p.glyphSet() for p in prefix]
             glyphs = [g.glyphSet() for g in glyphs]
             suffix = [s.glyphSet() for s in suffix]
-            builder.add_chain_context_pos(self.location, prefix, glyphs, suffix, [])
+            builder.add_chain_context_pos(
+                self.location, prefix, glyphs, suffix, [])
 
     def asFea(self, indent=""):
         contexts = []
@@ -888,24 +651,17 @@
 
 
 class IgnoreSubstStatement(Statement):
-    """An ``ignore sub`` statement, containing `one or more` contexts to ignore.
-
-    ``chainContexts`` should be a list of ``(prefix, glyphs, suffix)`` tuples,
-    with each of ``prefix``, ``glyphs`` and ``suffix`` being
-    `glyph-containing objects`_ ."""
-
     def __init__(self, chainContexts, location=None):
         Statement.__init__(self, location)
         self.chainContexts = chainContexts
 
     def build(self, builder):
-        """Calls the builder object's ``add_chain_context_subst`` callback on
-        each rule context."""
         for prefix, glyphs, suffix in self.chainContexts:
             prefix = [p.glyphSet() for p in prefix]
             glyphs = [g.glyphSet() for g in glyphs]
             suffix = [s.glyphSet() for s in suffix]
-            builder.add_chain_context_subst(self.location, prefix, glyphs, suffix, [])
+            builder.add_chain_context_subst(
+                self.location, prefix, glyphs, suffix, [])
 
     def asFea(self, indent=""):
         contexts = []
@@ -924,42 +680,34 @@
 
 
 class IncludeStatement(Statement):
-    """An ``include()`` statement."""
-
     def __init__(self, filename, location=None):
         super(IncludeStatement, self).__init__(location)
-        self.filename = filename  #: String containing name of file to include
+        self.filename = filename
 
     def build(self):
         # TODO: consider lazy-loading the including parser/lexer?
         raise FeatureLibError(
             "Building an include statement is not implemented yet. "
             "Instead, use Parser(..., followIncludes=True) for building.",
-            self.location,
-        )
+            self.location)
 
     def asFea(self, indent=""):
         return indent + "include(%s);" % self.filename
 
 
 class LanguageStatement(Statement):
-    """A ``language`` statement within a feature."""
-
-    def __init__(self, language, include_default=True, required=False, location=None):
+    def __init__(self, language, include_default=True, required=False,
+                 location=None):
         Statement.__init__(self, location)
-        assert len(language) == 4
-        self.language = language  #: A four-character language tag
-        self.include_default = include_default  #: If false, "exclude_dflt"
+        assert(len(language) == 4)
+        self.language = language
+        self.include_default = include_default
         self.required = required
 
     def build(self, builder):
-        """Call the builder object's ``set_language`` callback."""
-        builder.set_language(
-            location=self.location,
-            language=self.language,
-            include_default=self.include_default,
-            required=self.required,
-        )
+        builder.set_language(location=self.location, language=self.language,
+                             include_default=self.include_default,
+                             required=self.required)
 
     def asFea(self, indent=""):
         res = "language {}".format(self.language.strip())
@@ -972,14 +720,11 @@
 
 
 class LanguageSystemStatement(Statement):
-    """A top-level ``languagesystem`` statement."""
-
     def __init__(self, script, language, location=None):
         Statement.__init__(self, location)
         self.script, self.language = (script, language)
 
     def build(self, builder):
-        """Calls the builder object's ``add_language_system`` callback."""
         builder.add_language_system(self.location, self.script, self.language)
 
     def asFea(self, indent=""):
@@ -987,9 +732,6 @@
 
 
 class FontRevisionStatement(Statement):
-    """A ``head`` table ``FontRevision`` statement. ``revision`` should be a
-    number, and will be formatted to three significant decimal places."""
-
     def __init__(self, revision, location=None):
         Statement.__init__(self, location)
         self.revision = revision
@@ -1002,54 +744,36 @@
 
 
 class LigatureCaretByIndexStatement(Statement):
-    """A ``GDEF`` table ``LigatureCaretByIndex`` statement. ``glyphs`` should be
-    a `glyph-containing object`_, and ``carets`` should be a list of integers."""
-
     def __init__(self, glyphs, carets, location=None):
         Statement.__init__(self, location)
         self.glyphs, self.carets = (glyphs, carets)
 
     def build(self, builder):
-        """Calls the builder object's ``add_ligatureCaretByIndex_`` callback."""
         glyphs = self.glyphs.glyphSet()
         builder.add_ligatureCaretByIndex_(self.location, glyphs, set(self.carets))
 
     def asFea(self, indent=""):
         return "LigatureCaretByIndex {} {};".format(
-            self.glyphs.asFea(), " ".join(str(x) for x in self.carets)
-        )
+            self.glyphs.asFea(), " ".join(str(x) for x in self.carets))
 
 
 class LigatureCaretByPosStatement(Statement):
-    """A ``GDEF`` table ``LigatureCaretByPos`` statement. ``glyphs`` should be
-    a `glyph-containing object`_, and ``carets`` should be a list of integers."""
-
     def __init__(self, glyphs, carets, location=None):
         Statement.__init__(self, location)
         self.glyphs, self.carets = (glyphs, carets)
 
     def build(self, builder):
-        """Calls the builder object's ``add_ligatureCaretByPos_`` callback."""
         glyphs = self.glyphs.glyphSet()
         builder.add_ligatureCaretByPos_(self.location, glyphs, set(self.carets))
 
     def asFea(self, indent=""):
         return "LigatureCaretByPos {} {};".format(
-            self.glyphs.asFea(), " ".join(str(x) for x in self.carets)
-        )
+            self.glyphs.asFea(), " ".join(str(x) for x in self.carets))
 
 
 class LigatureSubstStatement(Statement):
-    """A chained contextual substitution statement.
-
-    ``prefix``, ``glyphs``, and ``suffix`` should be lists of
-    `glyph-containing objects`_; ``replacement`` should be a single
-    `glyph-containing object`_.
-
-    If ``forceChain`` is True, this is expressed as a chaining rule
-    (e.g. ``sub f' i' by f_i``) even when no context is given."""
-
-    def __init__(self, prefix, glyphs, suffix, replacement, forceChain, location=None):
+    def __init__(self, prefix, glyphs, suffix, replacement,
+                 forceChain, location=None):
         Statement.__init__(self, location)
         self.prefix, self.glyphs, self.suffix = (prefix, glyphs, suffix)
         self.replacement, self.forceChain = replacement, forceChain
@@ -1059,8 +783,8 @@
         glyphs = [g.glyphSet() for g in self.glyphs]
         suffix = [s.glyphSet() for s in self.suffix]
         builder.add_ligature_subst(
-            self.location, prefix, glyphs, suffix, self.replacement, self.forceChain
-        )
+            self.location, prefix, glyphs, suffix, self.replacement,
+            self.forceChain)
 
     def asFea(self, indent=""):
         res = "sub "
@@ -1079,28 +803,22 @@
 
 
 class LookupFlagStatement(Statement):
-    """A ``lookupflag`` statement. The ``value`` should be an integer value
-    representing the flags in use, but not including the ``markAttachment``
-    class and ``markFilteringSet`` values, which must be specified as
-    glyph-containing objects."""
-
-    def __init__(
-        self, value=0, markAttachment=None, markFilteringSet=None, location=None
-    ):
+    def __init__(self, value=0, markAttachment=None, markFilteringSet=None,
+                 location=None):
         Statement.__init__(self, location)
         self.value = value
         self.markAttachment = markAttachment
         self.markFilteringSet = markFilteringSet
 
     def build(self, builder):
-        """Calls the builder object's ``set_lookup_flag`` callback."""
         markAttach = None
         if self.markAttachment is not None:
             markAttach = self.markAttachment.glyphSet()
         markFilter = None
         if self.markFilteringSet is not None:
             markFilter = self.markFilteringSet.glyphSet()
-        builder.set_lookup_flag(self.location, self.value, markAttach, markFilter)
+        builder.set_lookup_flag(self.location, self.value,
+                                markAttach, markFilter)
 
     def asFea(self, indent=""):
         res = []
@@ -1120,16 +838,11 @@
 
 
 class LookupReferenceStatement(Statement):
-    """Represents a ``lookup ...;`` statement to include a lookup in a feature.
-
-    The ``lookup`` should be a :class:`LookupBlock` object."""
-
     def __init__(self, lookup, location=None):
         Statement.__init__(self, location)
         self.location, self.lookup = (location, lookup)
 
     def build(self, builder):
-        """Calls the builder object's ``add_lookup_call`` callback."""
         builder.add_lookup_call(self.lookup.name)
 
     def asFea(self, indent=""):
@@ -1137,59 +850,27 @@
 
 
 class MarkBasePosStatement(Statement):
-    """A mark-to-base positioning rule. The ``base`` should be a
-    `glyph-containing object`_. The ``marks`` should be a list of
-    (:class:`Anchor`, :class:`MarkClass`) tuples."""
-
     def __init__(self, base, marks, location=None):
         Statement.__init__(self, location)
         self.base, self.marks = base, marks
 
     def build(self, builder):
-        """Calls the builder object's ``add_mark_base_pos`` callback."""
         builder.add_mark_base_pos(self.location, self.base.glyphSet(), self.marks)
 
     def asFea(self, indent=""):
         res = "pos base {}".format(self.base.asFea())
         for a, m in self.marks:
-            res += "\n" + indent + SHIFT + "{} mark @{}".format(a.asFea(), m.name)
+            res += " {} mark @{}".format(a.asFea(), m.name)
         res += ";"
         return res
 
 
 class MarkLigPosStatement(Statement):
-    """A mark-to-ligature positioning rule. The ``ligatures`` must be a
-    `glyph-containing object`_. The ``marks`` should be a list of lists: each
-    element in the top-level list represents a component glyph, and is made
-    up of a list of (:class:`Anchor`, :class:`MarkClass`) tuples representing
-    mark attachment points for that position.
-
-    Example::
-
-        m1 = MarkClass("TOP_MARKS")
-        m2 = MarkClass("BOTTOM_MARKS")
-        # ... add definitions to mark classes...
-
-        glyph = GlyphName("lam_meem_jeem")
-        marks = [
-            [ (Anchor(625,1800), m1) ], # Attachments on 1st component (lam)
-            [ (Anchor(376,-378), m2) ], # Attachments on 2nd component (meem)
-            [ ]                         # No attachments on the jeem
-        ]
-        mlp = MarkLigPosStatement(glyph, marks)
-
-        mlp.asFea()
-        # pos ligature lam_meem_jeem <anchor 625 1800> mark @TOP_MARKS
-        # ligComponent <anchor 376 -378> mark @BOTTOM_MARKS;
-
-    """
-
     def __init__(self, ligatures, marks, location=None):
         Statement.__init__(self, location)
         self.ligatures, self.marks = ligatures, marks
 
     def build(self, builder):
-        """Calls the builder object's ``add_mark_lig_pos`` callback."""
         builder.add_mark_lig_pos(self.location, self.ligatures.glyphSet(), self.marks)
 
     def asFea(self, indent=""):
@@ -1198,15 +879,10 @@
         for l in self.marks:
             temp = ""
             if l is None or not len(l):
-                temp = "\n" + indent + SHIFT * 2 + "<anchor NULL>"
+                temp = " <anchor NULL>"
             else:
                 for a, m in l:
-                    temp += (
-                        "\n"
-                        + indent
-                        + SHIFT * 2
-                        + "{} mark @{}".format(a.asFea(), m.name)
-                    )
+                    temp += " {} mark @{}".format(a.asFea(), m.name)
             ligs.append(temp)
         res += ("\n" + indent + SHIFT + "ligComponent").join(ligs)
         res += ";"
@@ -1214,38 +890,22 @@
 
 
 class MarkMarkPosStatement(Statement):
-    """A mark-to-mark positioning rule. The ``baseMarks`` must be a
-    `glyph-containing object`_. The ``marks`` should be a list of
-    (:class:`Anchor`, :class:`MarkClass`) tuples."""
-
     def __init__(self, baseMarks, marks, location=None):
         Statement.__init__(self, location)
         self.baseMarks, self.marks = baseMarks, marks
 
     def build(self, builder):
-        """Calls the builder object's ``add_mark_mark_pos`` callback."""
         builder.add_mark_mark_pos(self.location, self.baseMarks.glyphSet(), self.marks)
 
     def asFea(self, indent=""):
         res = "pos mark {}".format(self.baseMarks.asFea())
         for a, m in self.marks:
-            res += "\n" + indent + SHIFT + "{} mark @{}".format(a.asFea(), m.name)
+            res += " {} mark @{}".format(a.asFea(), m.name)
         res += ";"
         return res
 
 
 class MultipleSubstStatement(Statement):
-    """A multiple substitution statement.
-
-    Args:
-        prefix: a list of `glyph-containing objects`_.
-        glyph: a single glyph-containing object.
-        suffix: a list of glyph-containing objects.
-        replacement: a list of glyph-containing objects.
-        forceChain: If true, the statement is expressed as a chaining rule
-            (e.g. ``sub f' i' by f_i``) even when no context is given.
-    """
-
     def __init__(
         self, prefix, glyph, suffix, replacement, forceChain=False, location=None
     ):
@@ -1255,12 +915,11 @@
         self.forceChain = forceChain
 
     def build(self, builder):
-        """Calls the builder object's ``add_multiple_subst`` callback."""
         prefix = [p.glyphSet() for p in self.prefix]
         suffix = [s.glyphSet() for s in self.suffix]
         builder.add_multiple_subst(
-            self.location, prefix, self.glyph, suffix, self.replacement, self.forceChain
-        )
+            self.location, prefix, self.glyph, suffix, self.replacement,
+            self.forceChain)
 
     def asFea(self, indent=""):
         res = "sub "
@@ -1272,100 +931,56 @@
                 res += " " + " ".join(map(asFea, self.suffix))
         else:
             res += asFea(self.glyph)
-        replacement = self.replacement or [NullGlyph()]
         res += " by "
-        res += " ".join(map(asFea, replacement))
+        res += " ".join(map(asFea, self.replacement))
         res += ";"
         return res
 
 
 class PairPosStatement(Statement):
-    """A pair positioning statement.
-
-    ``glyphs1`` and ``glyphs2`` should be `glyph-containing objects`_.
-    ``valuerecord1`` should be a :class:`ValueRecord` object;
-    ``valuerecord2`` should be either a :class:`ValueRecord` object or ``None``.
-    If ``enumerated`` is true, then this is expressed as an
-    `enumerated pair <https://adobe-type-tools.github.io/afdko/OpenTypeFeatureFileSpecification.html#6.b.ii>`_.
-    """
-
-    def __init__(
-        self,
-        glyphs1,
-        valuerecord1,
-        glyphs2,
-        valuerecord2,
-        enumerated=False,
-        location=None,
-    ):
+    def __init__(self, glyphs1, valuerecord1, glyphs2, valuerecord2,
+                 enumerated=False, location=None):
         Statement.__init__(self, location)
         self.enumerated = enumerated
         self.glyphs1, self.valuerecord1 = glyphs1, valuerecord1
         self.glyphs2, self.valuerecord2 = glyphs2, valuerecord2
 
     def build(self, builder):
-        """Calls a callback on the builder object:
-
-        * If the rule is enumerated, calls ``add_specific_pair_pos`` on each
-          combination of first and second glyphs.
-        * If the glyphs are both single :class:`GlyphName` objects, calls
-          ``add_specific_pair_pos``.
-        * Else, calls ``add_class_pair_pos``.
-        """
         if self.enumerated:
             g = [self.glyphs1.glyphSet(), self.glyphs2.glyphSet()]
             for glyph1, glyph2 in itertools.product(*g):
                 builder.add_specific_pair_pos(
-                    self.location, glyph1, self.valuerecord1, glyph2, self.valuerecord2
-                )
+                    self.location, glyph1, self.valuerecord1,
+                    glyph2, self.valuerecord2)
             return
 
-        is_specific = isinstance(self.glyphs1, GlyphName) and isinstance(
-            self.glyphs2, GlyphName
-        )
+        is_specific = (isinstance(self.glyphs1, GlyphName) and
+                       isinstance(self.glyphs2, GlyphName))
         if is_specific:
             builder.add_specific_pair_pos(
-                self.location,
-                self.glyphs1.glyph,
-                self.valuerecord1,
-                self.glyphs2.glyph,
-                self.valuerecord2,
-            )
+                self.location, self.glyphs1.glyph, self.valuerecord1,
+                self.glyphs2.glyph, self.valuerecord2)
         else:
             builder.add_class_pair_pos(
-                self.location,
-                self.glyphs1.glyphSet(),
-                self.valuerecord1,
-                self.glyphs2.glyphSet(),
-                self.valuerecord2,
-            )
+                self.location, self.glyphs1.glyphSet(), self.valuerecord1,
+                self.glyphs2.glyphSet(), self.valuerecord2)
 
     def asFea(self, indent=""):
         res = "enum " if self.enumerated else ""
         if self.valuerecord2:
             res += "pos {} {} {} {};".format(
-                self.glyphs1.asFea(),
-                self.valuerecord1.asFea(),
-                self.glyphs2.asFea(),
-                self.valuerecord2.asFea(),
-            )
+                self.glyphs1.asFea(), self.valuerecord1.asFea(),
+                self.glyphs2.asFea(), self.valuerecord2.asFea())
         else:
             res += "pos {} {} {};".format(
-                self.glyphs1.asFea(), self.glyphs2.asFea(), self.valuerecord1.asFea()
-            )
+                self.glyphs1.asFea(), self.glyphs2.asFea(),
+                self.valuerecord1.asFea())
         return res
 
 
 class ReverseChainSingleSubstStatement(Statement):
-    """A reverse chaining substitution statement. You don't see those every day.
-
-    Note the unusual argument order: ``suffix`` comes `before` ``glyphs``.
-    ``old_prefix``, ``old_suffix``, ``glyphs`` and ``replacements`` should be
-    lists of `glyph-containing objects`_. ``glyphs`` and ``replacements`` should
-    be one-item lists.
-    """
-
-    def __init__(self, old_prefix, old_suffix, glyphs, replacements, location=None):
+    def __init__(self, old_prefix, old_suffix, glyphs, replacements,
+                 location=None):
         Statement.__init__(self, location)
         self.old_prefix, self.old_suffix = old_prefix, old_suffix
         self.glyphs = glyphs
@@ -1379,8 +994,7 @@
         if len(replaces) == 1:
             replaces = replaces * len(originals)
         builder.add_reverse_chain_single_subst(
-            self.location, prefix, suffix, dict(zip(originals, replaces))
-        )
+            self.location, prefix, suffix, dict(zip(originals, replaces)))
 
     def asFea(self, indent=""):
         res = "rsub "
@@ -1397,15 +1011,8 @@
 
 
 class SingleSubstStatement(Statement):
-    """A single substitution statement.
-
-    Note the unusual argument order: ``prefix`` and suffix come `after`
-    the replacement ``glyphs``. ``prefix``, ``suffix``, ``glyphs`` and
-    ``replace`` should be lists of `glyph-containing objects`_. ``glyphs`` and
-    ``replace`` should be one-item lists.
-    """
-
-    def __init__(self, glyphs, replace, prefix, suffix, forceChain, location=None):
+    def __init__(self, glyphs, replace, prefix, suffix, forceChain,
+                 location=None):
         Statement.__init__(self, location)
         self.prefix, self.suffix = prefix, suffix
         self.forceChain = forceChain
@@ -1413,20 +1020,15 @@
         self.replacements = replace
 
     def build(self, builder):
-        """Calls the builder object's ``add_single_subst`` callback."""
         prefix = [p.glyphSet() for p in self.prefix]
         suffix = [s.glyphSet() for s in self.suffix]
         originals = self.glyphs[0].glyphSet()
         replaces = self.replacements[0].glyphSet()
         if len(replaces) == 1:
             replaces = replaces * len(originals)
-        builder.add_single_subst(
-            self.location,
-            prefix,
-            suffix,
-            OrderedDict(zip(originals, replaces)),
-            self.forceChain,
-        )
+        builder.add_single_subst(self.location, prefix, suffix,
+                                 OrderedDict(zip(originals, replaces)),
+                                 self.forceChain)
 
     def asFea(self, indent=""):
         res = "sub "
@@ -1443,14 +1045,11 @@
 
 
 class ScriptStatement(Statement):
-    """A ``script`` statement."""
-
     def __init__(self, script, location=None):
         Statement.__init__(self, location)
-        self.script = script  #: the script code
+        self.script = script
 
     def build(self, builder):
-        """Calls the builder's ``set_script`` callback."""
         builder.set_script(self.location, self.script)
 
     def asFea(self, indent=""):
@@ -1458,53 +1057,39 @@
 
 
 class SinglePosStatement(Statement):
-    """A single position statement. ``prefix`` and ``suffix`` should be
-    lists of `glyph-containing objects`_.
-
-    ``pos`` should be a one-element list containing a (`glyph-containing object`_,
-    :class:`ValueRecord`) tuple."""
-
     def __init__(self, pos, prefix, suffix, forceChain, location=None):
         Statement.__init__(self, location)
         self.pos, self.prefix, self.suffix = pos, prefix, suffix
         self.forceChain = forceChain
 
     def build(self, builder):
-        """Calls the builder object's ``add_single_pos`` callback."""
         prefix = [p.glyphSet() for p in self.prefix]
         suffix = [s.glyphSet() for s in self.suffix]
         pos = [(g.glyphSet(), value) for g, value in self.pos]
-        builder.add_single_pos(self.location, prefix, suffix, pos, self.forceChain)
+        builder.add_single_pos(self.location, prefix, suffix,
+                               pos, self.forceChain)
 
     def asFea(self, indent=""):
         res = "pos "
         if len(self.prefix) or len(self.suffix) or self.forceChain:
             if len(self.prefix):
                 res += " ".join(map(asFea, self.prefix)) + " "
-            res += " ".join(
-                [
-                    asFea(x[0]) + "'" + ((" " + x[1].asFea()) if x[1] else "")
-                    for x in self.pos
-                ]
-            )
+            res += " ".join([asFea(x[0]) + "'" + (
+                (" " + x[1].asFea()) if x[1] else "") for x in self.pos])
             if len(self.suffix):
                 res += " " + " ".join(map(asFea, self.suffix))
         else:
-            res += " ".join(
-                [asFea(x[0]) + " " + (x[1].asFea() if x[1] else "") for x in self.pos]
-            )
+            res += " ".join([asFea(x[0]) + " " +
+                             (x[1].asFea() if x[1] else "") for x in self.pos])
         res += ";"
         return res
 
 
 class SubtableStatement(Statement):
-    """Represents a subtable break."""
-
     def __init__(self, location=None):
         Statement.__init__(self, location)
 
     def build(self, builder):
-        """Calls the builder objects's ``add_subtable_break`` callback."""
         builder.add_subtable_break(self.location)
 
     def asFea(self, indent=""):
@@ -1512,21 +1097,11 @@
 
 
 class ValueRecord(Expression):
-    """Represents a value record."""
-
-    def __init__(
-        self,
-        xPlacement=None,
-        yPlacement=None,
-        xAdvance=None,
-        yAdvance=None,
-        xPlaDevice=None,
-        yPlaDevice=None,
-        xAdvDevice=None,
-        yAdvDevice=None,
-        vertical=False,
-        location=None,
-    ):
+    def __init__(self, xPlacement=None, yPlacement=None,
+                 xAdvance=None, yAdvance=None,
+                 xPlaDevice=None, yPlaDevice=None,
+                 xAdvDevice=None, yAdvDevice=None,
+                 vertical=False, location=None):
         Expression.__init__(self, location)
         self.xPlacement, self.yPlacement = (xPlacement, yPlacement)
         self.xAdvance, self.yAdvance = (xAdvance, yAdvance)
@@ -1535,29 +1110,21 @@
         self.vertical = vertical
 
     def __eq__(self, other):
-        return (
-            self.xPlacement == other.xPlacement
-            and self.yPlacement == other.yPlacement
-            and self.xAdvance == other.xAdvance
-            and self.yAdvance == other.yAdvance
-            and self.xPlaDevice == other.xPlaDevice
-            and self.xAdvDevice == other.xAdvDevice
-        )
+        return (self.xPlacement == other.xPlacement and
+                self.yPlacement == other.yPlacement and
+                self.xAdvance == other.xAdvance and
+                self.yAdvance == other.yAdvance and
+                self.xPlaDevice == other.xPlaDevice and
+                self.xAdvDevice == other.xAdvDevice)
 
     def __ne__(self, other):
         return not self.__eq__(other)
 
     def __hash__(self):
-        return (
-            hash(self.xPlacement)
-            ^ hash(self.yPlacement)
-            ^ hash(self.xAdvance)
-            ^ hash(self.yAdvance)
-            ^ hash(self.xPlaDevice)
-            ^ hash(self.yPlaDevice)
-            ^ hash(self.xAdvDevice)
-            ^ hash(self.yAdvDevice)
-        )
+        return (hash(self.xPlacement) ^ hash(self.yPlacement) ^
+                hash(self.xAdvance) ^ hash(self.yAdvance) ^
+                hash(self.xPlaDevice) ^ hash(self.yPlaDevice) ^
+                hash(self.xAdvDevice) ^ hash(self.yAdvDevice))
 
     def asFea(self, indent=""):
         if not self:
@@ -1583,25 +1150,15 @@
         yAdvance = yAdvance or 0
 
         # Try format B, if possible.
-        if (
-            xPlaDevice is None
-            and yPlaDevice is None
-            and xAdvDevice is None
-            and yAdvDevice is None
-        ):
+        if (xPlaDevice is None and yPlaDevice is None and
+                xAdvDevice is None and yAdvDevice is None):
             return "<%s %s %s %s>" % (x, y, xAdvance, yAdvance)
 
         # Last resort is format C.
         return "<%s %s %s %s %s %s %s %s>" % (
-            x,
-            y,
-            xAdvance,
-            yAdvance,
-            deviceToString(xPlaDevice),
-            deviceToString(yPlaDevice),
-            deviceToString(xAdvDevice),
-            deviceToString(yAdvDevice),
-        )
+            x, y, xAdvance, yAdvance,
+            deviceToString(xPlaDevice), deviceToString(yPlaDevice),
+            deviceToString(xAdvDevice), deviceToString(yAdvDevice))
 
     def __bool__(self):
         return any(
@@ -1622,12 +1179,10 @@
 
 
 class ValueRecordDefinition(Statement):
-    """Represents a named value record definition."""
-
     def __init__(self, name, value, location=None):
         Statement.__init__(self, location)
-        self.name = name  #: Value record name as string
-        self.value = value  #: :class:`ValueRecord` object
+        self.name = name
+        self.value = value
 
     def asFea(self, indent=""):
         return "valueRecordDef {} {};".format(self.value.asFea(), self.name)
@@ -1643,59 +1198,46 @@
 
 
 class NameRecord(Statement):
-    """Represents a name record. (`Section 9.e. <https://adobe-type-tools.github.io/afdko/OpenTypeFeatureFileSpecification.html#9.e>`_)"""
-
-    def __init__(self, nameID, platformID, platEncID, langID, string, location=None):
+    def __init__(self, nameID, platformID, platEncID, langID, string,
+                 location=None):
         Statement.__init__(self, location)
-        self.nameID = nameID  #: Name ID as integer (e.g. 9 for designer's name)
-        self.platformID = platformID  #: Platform ID as integer
-        self.platEncID = platEncID  #: Platform encoding ID as integer
-        self.langID = langID  #: Language ID as integer
-        self.string = string  #: Name record value
+        self.nameID = nameID
+        self.platformID = platformID
+        self.platEncID = platEncID
+        self.langID = langID
+        self.string = string
 
     def build(self, builder):
-        """Calls the builder object's ``add_name_record`` callback."""
         builder.add_name_record(
-            self.location,
-            self.nameID,
-            self.platformID,
-            self.platEncID,
-            self.langID,
-            self.string,
-        )
+            self.location, self.nameID, self.platformID,
+            self.platEncID, self.langID, self.string)
 
     def asFea(self, indent=""):
         def escape(c, escape_pattern):
             # Also escape U+0022 QUOTATION MARK and U+005C REVERSE SOLIDUS
             if c >= 0x20 and c <= 0x7E and c not in (0x22, 0x5C):
-                return chr(c)
+                return unichr(c)
             else:
                 return escape_pattern % c
-
         encoding = getEncoding(self.platformID, self.platEncID, self.langID)
         if encoding is None:
             raise FeatureLibError("Unsupported encoding", self.location)
         s = tobytes(self.string, encoding=encoding)
         if encoding == "utf_16_be":
-            escaped_string = "".join(
-                [
-                    escape(byteord(s[i]) * 256 + byteord(s[i + 1]), r"\%04x")
-                    for i in range(0, len(s), 2)
-                ]
-            )
+            escaped_string = "".join([
+                escape(byteord(s[i]) * 256 + byteord(s[i + 1]), r"\%04x")
+                for i in range(0, len(s), 2)])
         else:
             escaped_string = "".join([escape(byteord(b), r"\%02x") for b in s])
-        plat = simplify_name_attributes(self.platformID, self.platEncID, self.langID)
+        plat = simplify_name_attributes(
+            self.platformID, self.platEncID, self.langID)
         if plat != "":
             plat += " "
-        return 'nameid {} {}"{}";'.format(self.nameID, plat, escaped_string)
+        return "nameid {} {}\"{}\";".format(self.nameID, plat, escaped_string)
 
 
 class FeatureNameStatement(NameRecord):
-    """Represents a ``sizemenuname`` or ``name`` statement."""
-
     def build(self, builder):
-        """Calls the builder object's ``add_featureName`` callback."""
         NameRecord.build(self, builder)
         builder.add_featureName(self.nameID)
 
@@ -1707,23 +1249,12 @@
         plat = simplify_name_attributes(self.platformID, self.platEncID, self.langID)
         if plat != "":
             plat += " "
-        return '{} {}"{}";'.format(tag, plat, self.string)
-
-
-class STATNameStatement(NameRecord):
-    """Represents a STAT table ``name`` statement."""
-
-    def asFea(self, indent=""):
-        plat = simplify_name_attributes(self.platformID, self.platEncID, self.langID)
-        if plat != "":
-            plat += " "
-        return 'name {}"{}";'.format(plat, self.string)
+        return "{} {}\"{}\";".format(tag, plat, self.string)
 
 
 class SizeParameters(Statement):
-    """A ``parameters`` statement."""
-
-    def __init__(self, DesignSize, SubfamilyID, RangeStart, RangeEnd, location=None):
+    def __init__(self, DesignSize, SubfamilyID, RangeStart, RangeEnd,
+                 location=None):
         Statement.__init__(self, location)
         self.DesignSize = DesignSize
         self.SubfamilyID = SubfamilyID
@@ -1731,14 +1262,8 @@
         self.RangeEnd = RangeEnd
 
     def build(self, builder):
-        """Calls the builder object's ``set_size_parameters`` callback."""
-        builder.set_size_parameters(
-            self.location,
-            self.DesignSize,
-            self.SubfamilyID,
-            self.RangeStart,
-            self.RangeEnd,
-        )
+        builder.set_size_parameters(self.location, self.DesignSize,
+                                    self.SubfamilyID, self.RangeStart, self.RangeEnd)
 
     def asFea(self, indent=""):
         res = "parameters {:.1f} {}".format(self.DesignSize, self.SubfamilyID)
@@ -1748,18 +1273,13 @@
 
 
 class CVParametersNameStatement(NameRecord):
-    """Represent a name statement inside a ``cvParameters`` block."""
-
-    def __init__(
-        self, nameID, platformID, platEncID, langID, string, block_name, location=None
-    ):
-        NameRecord.__init__(
-            self, nameID, platformID, platEncID, langID, string, location=location
-        )
+    def __init__(self, nameID, platformID, platEncID, langID, string,
+                 block_name, location=None):
+        NameRecord.__init__(self, nameID, platformID, platEncID, langID,
+                            string, location=location)
         self.block_name = block_name
 
     def build(self, builder):
-        """Calls the builder object's ``add_cv_parameter`` callback."""
         item = ""
         if self.block_name == "ParamUILabelNameID":
             item = "_{}".format(builder.cv_num_named_params_.get(self.nameID, 0))
@@ -1768,10 +1288,11 @@
         NameRecord.build(self, builder)
 
     def asFea(self, indent=""):
-        plat = simplify_name_attributes(self.platformID, self.platEncID, self.langID)
+        plat = simplify_name_attributes(self.platformID, self.platEncID,
+                                        self.langID)
         if plat != "":
             plat += " "
-        return 'name {}"{}";'.format(plat, self.string)
+        return "name {}\"{}\";".format(plat, self.string)
 
 
 class CharacterStatement(Statement):
@@ -1781,14 +1302,12 @@
     notation. The value must be preceded by '0x' if it is a hexadecimal value.
     The largest Unicode value allowed is 0xFFFFFF.
     """
-
     def __init__(self, character, tag, location=None):
         Statement.__init__(self, location)
         self.character = character
         self.tag = tag
 
     def build(self, builder):
-        """Calls the builder object's ``add_cv_character`` callback."""
         builder.add_cv_character(self.character, self.tag)
 
     def asFea(self, indent=""):
@@ -1796,84 +1315,54 @@
 
 
 class BaseAxis(Statement):
-    """An axis definition, being either a ``VertAxis.BaseTagList/BaseScriptList``
-    pair or a ``HorizAxis.BaseTagList/BaseScriptList`` pair."""
-
     def __init__(self, bases, scripts, vertical, location=None):
         Statement.__init__(self, location)
-        self.bases = bases  #: A list of baseline tag names as strings
-        self.scripts = scripts  #: A list of script record tuplets (script tag, default baseline tag, base coordinate)
-        self.vertical = vertical  #: Boolean; VertAxis if True, HorizAxis if False
+        self.bases = bases
+        self.scripts = scripts
+        self.vertical = vertical
 
     def build(self, builder):
-        """Calls the builder object's ``set_base_axis`` callback."""
         builder.set_base_axis(self.bases, self.scripts, self.vertical)
 
     def asFea(self, indent=""):
         direction = "Vert" if self.vertical else "Horiz"
-        scripts = [
-            "{} {} {}".format(a[0], a[1], " ".join(map(str, a[2])))
-            for a in self.scripts
-        ]
+        scripts = ["{} {} {}".format(a[0], a[1], " ".join(map(str, a[2]))) for a in self.scripts]
         return "{}Axis.BaseTagList {};\n{}{}Axis.BaseScriptList {};".format(
-            direction, " ".join(self.bases), indent, direction, ", ".join(scripts)
-        )
+            direction, " ".join(self.bases), indent, direction, ", ".join(scripts))
 
 
 class OS2Field(Statement):
-    """An entry in the ``OS/2`` table. Most ``values`` should be numbers or
-    strings, apart from when the key is ``UnicodeRange``, ``CodePageRange``
-    or ``Panose``, in which case it should be an array of integers."""
-
     def __init__(self, key, value, location=None):
         Statement.__init__(self, location)
         self.key = key
         self.value = value
 
     def build(self, builder):
-        """Calls the builder object's ``add_os2_field`` callback."""
         builder.add_os2_field(self.key, self.value)
 
     def asFea(self, indent=""):
         def intarr2str(x):
             return " ".join(map(str, x))
-
-        numbers = (
-            "FSType",
-            "TypoAscender",
-            "TypoDescender",
-            "TypoLineGap",
-            "winAscent",
-            "winDescent",
-            "XHeight",
-            "CapHeight",
-            "WeightClass",
-            "WidthClass",
-            "LowerOpSize",
-            "UpperOpSize",
-        )
+        numbers = ("FSType", "TypoAscender", "TypoDescender", "TypoLineGap",
+                   "winAscent", "winDescent", "XHeight", "CapHeight",
+                   "WeightClass", "WidthClass", "LowerOpSize", "UpperOpSize")
         ranges = ("UnicodeRange", "CodePageRange")
         keywords = dict([(x.lower(), [x, str]) for x in numbers])
         keywords.update([(x.lower(), [x, intarr2str]) for x in ranges])
         keywords["panose"] = ["Panose", intarr2str]
         keywords["vendor"] = ["Vendor", lambda y: '"{}"'.format(y)]
         if self.key in keywords:
-            return "{} {};".format(
-                keywords[self.key][0], keywords[self.key][1](self.value)
-            )
-        return ""  # should raise exception
+            return "{} {};".format(keywords[self.key][0], keywords[self.key][1](self.value))
+        return ""   # should raise exception
 
 
 class HheaField(Statement):
-    """An entry in the ``hhea`` table."""
-
     def __init__(self, key, value, location=None):
         Statement.__init__(self, location)
         self.key = key
         self.value = value
 
     def build(self, builder):
-        """Calls the builder object's ``add_hhea_field`` callback."""
         builder.add_hhea_field(self.key, self.value)
 
     def asFea(self, indent=""):
@@ -1883,147 +1372,15 @@
 
 
 class VheaField(Statement):
-    """An entry in the ``vhea`` table."""
-
     def __init__(self, key, value, location=None):
         Statement.__init__(self, location)
         self.key = key
         self.value = value
 
     def build(self, builder):
-        """Calls the builder object's ``add_vhea_field`` callback."""
         builder.add_vhea_field(self.key, self.value)
 
     def asFea(self, indent=""):
         fields = ("VertTypoAscender", "VertTypoDescender", "VertTypoLineGap")
         keywords = dict([(x.lower(), x) for x in fields])
         return "{} {};".format(keywords[self.key], self.value)
-
-
-class STATDesignAxisStatement(Statement):
-    """A STAT table Design Axis
-
-    Args:
-        tag (str): a 4 letter axis tag
-        axisOrder (int): an int
-        names (list): a list of :class:`STATNameStatement` objects
-    """
-
-    def __init__(self, tag, axisOrder, names, location=None):
-        Statement.__init__(self, location)
-        self.tag = tag
-        self.axisOrder = axisOrder
-        self.names = names
-        self.location = location
-
-    def build(self, builder):
-        builder.addDesignAxis(self, self.location)
-
-    def asFea(self, indent=""):
-        indent += SHIFT
-        res = f"DesignAxis {self.tag} {self.axisOrder} {{ \n"
-        res += ("\n" + indent).join([s.asFea(indent=indent) for s in self.names]) + "\n"
-        res += "};"
-        return res
-
-
-class ElidedFallbackName(Statement):
-    """STAT table ElidedFallbackName
-
-    Args:
-        names: a list of :class:`STATNameStatement` objects
-    """
-
-    def __init__(self, names, location=None):
-        Statement.__init__(self, location)
-        self.names = names
-        self.location = location
-
-    def build(self, builder):
-        builder.setElidedFallbackName(self.names, self.location)
-
-    def asFea(self, indent=""):
-        indent += SHIFT
-        res = "ElidedFallbackName { \n"
-        res += ("\n" + indent).join([s.asFea(indent=indent) for s in self.names]) + "\n"
-        res += "};"
-        return res
-
-
-class ElidedFallbackNameID(Statement):
-    """STAT table ElidedFallbackNameID
-
-    Args:
-        value: an int pointing to an existing name table name ID
-    """
-
-    def __init__(self, value, location=None):
-        Statement.__init__(self, location)
-        self.value = value
-        self.location = location
-
-    def build(self, builder):
-        builder.setElidedFallbackName(self.value, self.location)
-
-    def asFea(self, indent=""):
-        return f"ElidedFallbackNameID {self.value};"
-
-
-class STATAxisValueStatement(Statement):
-    """A STAT table Axis Value Record
-
-    Args:
-        names (list): a list of :class:`STATNameStatement` objects
-        locations (list): a list of :class:`AxisValueLocationStatement` objects
-        flags (int): an int
-    """
-
-    def __init__(self, names, locations, flags, location=None):
-        Statement.__init__(self, location)
-        self.names = names
-        self.locations = locations
-        self.flags = flags
-
-    def build(self, builder):
-        builder.addAxisValueRecord(self, self.location)
-
-    def asFea(self, indent=""):
-        res = "AxisValue {\n"
-        for location in self.locations:
-            res += location.asFea()
-
-        for nameRecord in self.names:
-            res += nameRecord.asFea()
-            res += "\n"
-
-        if self.flags:
-            flags = ["OlderSiblingFontAttribute", "ElidableAxisValueName"]
-            flagStrings = []
-            curr = 1
-            for i in range(len(flags)):
-                if self.flags & curr != 0:
-                    flagStrings.append(flags[i])
-                curr = curr << 1
-            res += f"flag {' '.join(flagStrings)};\n"
-        res += "};"
-        return res
-
-
-class AxisValueLocationStatement(Statement):
-    """
-    A STAT table Axis Value Location
-
-    Args:
-        tag (str): a 4 letter axis tag
-        values (list): a list of ints and/or floats
-    """
-
-    def __init__(self, tag, values, location=None):
-        Statement.__init__(self, location)
-        self.tag = tag
-        self.values = values
-
-    def asFea(self, res=""):
-        res += f"location {self.tag} "
-        res += f"{' '.join(str(i) for i in self.values)};\n"
-        return res
diff --git a/Lib/fontTools/feaLib/builder.py b/Lib/fontTools/feaLib/builder.py
index 4a7d957..8880acf 100644
--- a/Lib/fontTools/feaLib/builder.py
+++ b/Lib/fontTools/feaLib/builder.py
@@ -1,107 +1,50 @@
-from fontTools.misc.py23 import Tag, tostr
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from fontTools.misc.textTools import binary2num, safeEval
 from fontTools.feaLib.error import FeatureLibError
-from fontTools.feaLib.lookupDebugInfo import (
-    LookupDebugInfo,
-    LOOKUP_DEBUG_INFO_KEY,
-    LOOKUP_DEBUG_ENV_VAR,
-)
 from fontTools.feaLib.parser import Parser
 from fontTools.feaLib.ast import FeatureFile
 from fontTools.otlLib import builder as otl
 from fontTools.otlLib.maxContextCalc import maxCtxFont
 from fontTools.ttLib import newTable, getTableModule
 from fontTools.ttLib.tables import otBase, otTables
-from fontTools.otlLib.builder import (
-    AlternateSubstBuilder,
-    ChainContextPosBuilder,
-    ChainContextSubstBuilder,
-    LigatureSubstBuilder,
-    MultipleSubstBuilder,
-    CursivePosBuilder,
-    MarkBasePosBuilder,
-    MarkLigPosBuilder,
-    MarkMarkPosBuilder,
-    ReverseChainSingleSubstBuilder,
-    SingleSubstBuilder,
-    ClassPairPosSubtableBuilder,
-    PairPosBuilder,
-    SinglePosBuilder,
-    ChainContextualRule,
-)
-from fontTools.otlLib.error import OpenTypeLibError
-from collections import defaultdict
+from collections import defaultdict, OrderedDict
 import itertools
-from io import StringIO
 import logging
-import warnings
-import os
 
 
 log = logging.getLogger(__name__)
 
 
-def addOpenTypeFeatures(font, featurefile, tables=None, debug=False):
-    """Add features from a file to a font. Note that this replaces any features
-    currently present.
-
-    Args:
-        font (feaLib.ttLib.TTFont): The font object.
-        featurefile: Either a path or file object (in which case we
-            parse it into an AST), or a pre-parsed AST instance.
-        tables: If passed, restrict the set of affected tables to those in the
-            list.
-        debug: Whether to add source debugging information to the font in the
-            ``Debg`` table
-
-    """
+def addOpenTypeFeatures(font, featurefile, tables=None):
     builder = Builder(font, featurefile)
-    builder.build(tables=tables, debug=debug)
+    builder.build(tables=tables)
 
 
-def addOpenTypeFeaturesFromString(
-    font, features, filename=None, tables=None, debug=False
-):
-    """Add features from a string to a font. Note that this replaces any
-    features currently present.
-
-    Args:
-        font (feaLib.ttLib.TTFont): The font object.
-        features: A string containing feature code.
-        filename: The directory containing ``filename`` is used as the root of
-            relative ``include()`` paths; if ``None`` is provided, the current
-            directory is assumed.
-        tables: If passed, restrict the set of affected tables to those in the
-            list.
-        debug: Whether to add source debugging information to the font in the
-            ``Debg`` table
-
-    """
-
-    featurefile = StringIO(tostr(features))
+def addOpenTypeFeaturesFromString(font, features, filename=None, tables=None):
+    featurefile = UnicodeIO(tounicode(features))
     if filename:
+        # the directory containing 'filename' is used as the root of relative
+        # include paths; if None is provided, the current directory is assumed
         featurefile.name = filename
-    addOpenTypeFeatures(font, featurefile, tables=tables, debug=debug)
+    addOpenTypeFeatures(font, featurefile, tables=tables)
 
 
 class Builder(object):
 
-    supportedTables = frozenset(
-        Tag(tag)
-        for tag in [
-            "BASE",
-            "GDEF",
-            "GPOS",
-            "GSUB",
-            "OS/2",
-            "head",
-            "hhea",
-            "name",
-            "vhea",
-            "STAT",
-        ]
-    )
+    supportedTables = frozenset(Tag(tag) for tag in [
+        "BASE",
+        "GDEF",
+        "GPOS",
+        "GSUB",
+        "OS/2",
+        "head",
+        "hhea",
+        "name",
+        "vhea",
+    ])
 
     def __init__(self, font, featurefile):
         self.font = font
@@ -123,7 +66,6 @@
         self.cur_lookup_name_ = None
         self.cur_feature_name_ = None
         self.lookups_ = []
-        self.lookup_locations = {"GSUB": {}, "GPOS": {}}
         self.features_ = {}  # ('latn', 'DEU ', 'smcp') --> [LookupBuilder*]
         self.required_features_ = {}  # ('latn', 'DEU ') --> 'scmp'
         # for feature 'aalt'
@@ -161,10 +103,8 @@
         self.hhea_ = {}
         # for table 'vhea'
         self.vhea_ = {}
-        # for table 'STAT'
-        self.stat_ = {}
 
-    def build(self, tables=None, debug=False):
+    def build(self, tables=None):
         if self.parseTree is None:
             self.parseTree = Parser(self.file, self.glyphMap).parse()
         self.parseTree.build(self)
@@ -174,12 +114,7 @@
         else:
             tables = frozenset(tables)
             unsupported = tables - self.supportedTables
-            if unsupported:
-                unsupported_string = ", ".join(sorted(unsupported))
-                raise NotImplementedError(
-                    "The following tables were requested but are unsupported: "
-                    f"{unsupported_string}."
-                )
+            assert not unsupported, unsupported
         if "GSUB" in tables:
             self.build_feature_aalt_()
         if "head" in tables:
@@ -192,22 +127,19 @@
             self.build_name()
         if "OS/2" in tables:
             self.build_OS_2()
-        if "STAT" in tables:
-            self.build_STAT()
-        for tag in ("GPOS", "GSUB"):
+        for tag in ('GPOS', 'GSUB'):
             if tag not in tables:
                 continue
             table = self.makeTable(tag)
-            if (
-                table.ScriptList.ScriptCount > 0
-                or table.FeatureList.FeatureCount > 0
-                or table.LookupList.LookupCount > 0
-            ):
+            if (table.ScriptList.ScriptCount > 0 or
+                    table.FeatureList.FeatureCount > 0 or
+                    table.LookupList.LookupCount > 0):
                 fontTable = self.font[tag] = newTable(tag)
                 fontTable.table = table
             elif tag in self.font:
                 del self.font[tag]
-        if any(tag in self.font for tag in ("GPOS", "GSUB")) and "OS/2" in self.font:
+        if (any(tag in self.font for tag in ("GPOS", "GSUB")) and
+                "OS/2" in self.font):
             self.font["OS/2"].usMaxContext = maxCtxFont(self.font)
         if "GDEF" in tables:
             gdef = self.buildGDEF()
@@ -221,8 +153,6 @@
                 self.font["BASE"] = base
             elif "BASE" in self.font:
                 del self.font["BASE"]
-        if debug or os.environ.get(LOOKUP_DEBUG_ENV_VAR):
-            self.buildDebg()
 
     def get_chained_lookup_(self, location, builder_class):
         result = builder_class(self.font, location)
@@ -237,19 +167,16 @@
             self.features_.setdefault(key, []).append(lookup)
 
     def get_lookup_(self, location, builder_class):
-        if (
-            self.cur_lookup_
-            and type(self.cur_lookup_) == builder_class
-            and self.cur_lookup_.lookupflag == self.lookupflag_
-            and self.cur_lookup_.markFilterSet == self.lookupflag_markFilterSet_
-        ):
+        if (self.cur_lookup_ and
+            type(self.cur_lookup_) == builder_class and
+            self.cur_lookup_.lookupflag == self.lookupflag_ and
+            self.cur_lookup_.markFilterSet ==
+                self.lookupflag_markFilterSet_):
             return self.cur_lookup_
         if self.cur_lookup_name_ and self.cur_lookup_:
             raise FeatureLibError(
                 "Within a named lookup block, all rules must be of "
-                "the same lookup type and flag",
-                location,
-            )
+                "the same lookup type and flag", location)
         self.cur_lookup_ = builder_class(self.font, location)
         self.cur_lookup_.lookupflag = self.lookupflag_
         self.cur_lookup_.markFilterSet = self.lookupflag_markFilterSet_
@@ -260,7 +187,8 @@
         if self.cur_feature_name_:
             # We are starting a lookup rule inside a feature. This includes
             # lookup rules inside named lookups inside features.
-            self.add_lookup_to_feature_(self.cur_lookup_, self.cur_feature_name_)
+            self.add_lookup_to_feature_(self.cur_lookup_,
+                                        self.cur_feature_name_)
         return self.cur_lookup_
 
     def build_feature_aalt_(self):
@@ -268,40 +196,31 @@
             return
         alternates = {g: set(a) for g, a in self.aalt_alternates_.items()}
         for location, name in self.aalt_features_ + [(None, "aalt")]:
-            feature = [
-                (script, lang, feature, lookups)
-                for (script, lang, feature), lookups in self.features_.items()
-                if feature == name
-            ]
+            feature = [(script, lang, feature, lookups)
+                       for (script, lang, feature), lookups
+                       in self.features_.items()
+                       if feature == name]
             # "aalt" does not have to specify its own lookups, but it might.
             if not feature and name != "aalt":
-                raise FeatureLibError(
-                    "Feature %s has not been defined" % name, location
-                )
+                raise FeatureLibError("Feature %s has not been defined" % name,
+                                      location)
             for script, lang, feature, lookups in feature:
-                for lookuplist in lookups:
-                    if not isinstance(lookuplist, list):
-                        lookuplist = [lookuplist]
-                    for lookup in lookuplist:
-                        for glyph, alts in lookup.getAlternateGlyphs().items():
-                            alternates.setdefault(glyph, set()).update(alts)
-        single = {
-            glyph: list(repl)[0] for glyph, repl in alternates.items() if len(repl) == 1
-        }
+                for lookup in lookups:
+                    for glyph, alts in lookup.getAlternateGlyphs().items():
+                        alternates.setdefault(glyph, set()).update(alts)
+        single = {glyph: list(repl)[0] for glyph, repl in alternates.items()
+                  if len(repl) == 1}
         # TODO: Figure out the glyph alternate ordering used by makeotf.
         # https://github.com/fonttools/fonttools/issues/836
-        multi = {
-            glyph: sorted(repl, key=self.font.getGlyphID)
-            for glyph, repl in alternates.items()
-            if len(repl) > 1
-        }
+        multi = {glyph: sorted(repl, key=self.font.getGlyphID)
+                 for glyph, repl in alternates.items()
+                 if len(repl) > 1}
         if not single and not multi:
             return
-        self.features_ = {
-            (script, lang, feature): lookups
-            for (script, lang, feature), lookups in self.features_.items()
-            if feature != "aalt"
-        }
+        self.features_ = {(script, lang, feature): lookups
+                          for (script, lang, feature), lookups
+                          in self.features_.items()
+                          if feature != "aalt"}
         old_lookups = self.lookups_
         self.lookups_ = []
         self.start_feature(self.aalt_location_, "aalt")
@@ -368,12 +287,8 @@
         params = None
         if tag == "size":
             params = otTables.FeatureParamsSize()
-            (
-                params.DesignSize,
-                params.SubfamilyID,
-                params.RangeStart,
-                params.RangeEnd,
-            ) = self.size_parameters_
+            params.DesignSize, params.SubfamilyID, params.RangeStart, \
+                    params.RangeEnd = self.size_parameters_
             if tag in self.featureNames_ids_:
                 params.SubfamilyNameID = self.featureNames_ids_[tag]
             else:
@@ -391,18 +306,14 @@
             params = otTables.FeatureParamsCharacterVariants()
             params.Format = 0
             params.FeatUILabelNameID = self.cv_parameters_ids_.get(
-                (tag, "FeatUILabelNameID"), 0
-            )
+                (tag, 'FeatUILabelNameID'), 0)
             params.FeatUITooltipTextNameID = self.cv_parameters_ids_.get(
-                (tag, "FeatUITooltipTextNameID"), 0
-            )
+                (tag, 'FeatUITooltipTextNameID'), 0)
             params.SampleTextNameID = self.cv_parameters_ids_.get(
-                (tag, "SampleTextNameID"), 0
-            )
+                (tag, 'SampleTextNameID'), 0)
             params.NumNamedParameters = self.cv_num_named_params_.get(tag, 0)
             params.FirstParamUILabelNameID = self.cv_parameters_ids_.get(
-                (tag, "ParamUILabelNameID_0"), 0
-            )
+                (tag, 'ParamUILabelNameID_0'), 0)
             params.CharCount = len(self.cv_characters_[tag])
             params.Character = self.cv_characters_[tag]
         return params
@@ -445,18 +356,10 @@
             table.fsType = self.os2_["fstype"]
         if "panose" in self.os2_:
             panose = getTableModule("OS/2").Panose()
-            (
-                panose.bFamilyType,
-                panose.bSerifStyle,
-                panose.bWeight,
-                panose.bProportion,
-                panose.bContrast,
-                panose.bStrokeVariation,
-                panose.bArmStyle,
-                panose.bLetterForm,
-                panose.bMidline,
-                panose.bXHeight,
-            ) = self.os2_["panose"]
+            panose.bFamilyType, panose.bSerifStyle, panose.bWeight,\
+                panose.bProportion, panose.bContrast, panose.bStrokeVariation,\
+                panose.bArmStyle, panose.bLetterForm, panose.bMidline, \
+                panose.bXHeight = self.os2_["panose"]
             table.panose = panose
         if "typoascender" in self.os2_:
             table.sTypoAscender = self.os2_["typoascender"]
@@ -492,197 +395,28 @@
         if "upperopsize" in self.os2_:
             table.usUpperOpticalPointSize = self.os2_["upperopsize"]
             version = 5
-
         def checkattr(table, attrs):
             for attr in attrs:
                 if not hasattr(table, attr):
                     setattr(table, attr, 0)
-
         table.version = max(version, table.version)
         # this only happens for unit tests
         if version >= 1:
             checkattr(table, ("ulCodePageRange1", "ulCodePageRange2"))
         if version >= 2:
-            checkattr(
-                table,
-                (
-                    "sxHeight",
-                    "sCapHeight",
-                    "usDefaultChar",
-                    "usBreakChar",
-                    "usMaxContext",
-                ),
-            )
+            checkattr(table, ("sxHeight", "sCapHeight", "usDefaultChar",
+                              "usBreakChar", "usMaxContext"))
         if version >= 5:
-            checkattr(table, ("usLowerOpticalPointSize", "usUpperOpticalPointSize"))
-
-    def setElidedFallbackName(self, value, location):
-        # ElidedFallbackName is a convenience method for setting
-        # ElidedFallbackNameID so only one can be allowed
-        for token in ("ElidedFallbackName", "ElidedFallbackNameID"):
-            if token in self.stat_:
-                raise FeatureLibError(
-                    f"{token} is already set.",
-                    location,
-                )
-        if isinstance(value, int):
-            self.stat_["ElidedFallbackNameID"] = value
-        elif isinstance(value, list):
-            self.stat_["ElidedFallbackName"] = value
-        else:
-            raise AssertionError(value)
-
-    def addDesignAxis(self, designAxis, location):
-        if "DesignAxes" not in self.stat_:
-            self.stat_["DesignAxes"] = []
-        if designAxis.tag in (r.tag for r in self.stat_["DesignAxes"]):
-            raise FeatureLibError(
-                f'DesignAxis already defined for tag "{designAxis.tag}".',
-                location,
-            )
-        if designAxis.axisOrder in (r.axisOrder for r in self.stat_["DesignAxes"]):
-            raise FeatureLibError(
-                f"DesignAxis already defined for axis number {designAxis.axisOrder}.",
-                location,
-            )
-        self.stat_["DesignAxes"].append(designAxis)
-
-    def addAxisValueRecord(self, axisValueRecord, location):
-        if "AxisValueRecords" not in self.stat_:
-            self.stat_["AxisValueRecords"] = []
-        # Check for duplicate AxisValueRecords
-        for record_ in self.stat_["AxisValueRecords"]:
-            if (
-                {n.asFea() for n in record_.names}
-                == {n.asFea() for n in axisValueRecord.names}
-                and {n.asFea() for n in record_.locations}
-                == {n.asFea() for n in axisValueRecord.locations}
-                and record_.flags == axisValueRecord.flags
-            ):
-                raise FeatureLibError(
-                    "An AxisValueRecord with these values is already defined.",
-                    location,
-                )
-        self.stat_["AxisValueRecords"].append(axisValueRecord)
-
-    def build_STAT(self):
-        if not self.stat_:
-            return
-
-        axes = self.stat_.get("DesignAxes")
-        if not axes:
-            raise FeatureLibError("DesignAxes not defined", None)
-        axisValueRecords = self.stat_.get("AxisValueRecords")
-        axisValues = {}
-        format4_locations = []
-        for tag in axes:
-            axisValues[tag.tag] = []
-        if axisValueRecords is not None:
-            for avr in axisValueRecords:
-                valuesDict = {}
-                if avr.flags > 0:
-                    valuesDict["flags"] = avr.flags
-                if len(avr.locations) == 1:
-                    location = avr.locations[0]
-                    values = location.values
-                    if len(values) == 1:  # format1
-                        valuesDict.update({"value": values[0], "name": avr.names})
-                    if len(values) == 2:  # format3
-                        valuesDict.update(
-                            {
-                                "value": values[0],
-                                "linkedValue": values[1],
-                                "name": avr.names,
-                            }
-                        )
-                    if len(values) == 3:  # format2
-                        nominal, minVal, maxVal = values
-                        valuesDict.update(
-                            {
-                                "nominalValue": nominal,
-                                "rangeMinValue": minVal,
-                                "rangeMaxValue": maxVal,
-                                "name": avr.names,
-                            }
-                        )
-                    axisValues[location.tag].append(valuesDict)
-                else:
-                    valuesDict.update(
-                        {
-                            "location": {i.tag: i.values[0] for i in avr.locations},
-                            "name": avr.names,
-                        }
-                    )
-                    format4_locations.append(valuesDict)
-
-        designAxes = [
-            {
-                "ordering": a.axisOrder,
-                "tag": a.tag,
-                "name": a.names,
-                "values": axisValues[a.tag],
-            }
-            for a in axes
-        ]
-
-        nameTable = self.font.get("name")
-        if not nameTable:  # this only happens for unit tests
-            nameTable = self.font["name"] = newTable("name")
-            nameTable.names = []
-
-        if "ElidedFallbackNameID" in self.stat_:
-            nameID = self.stat_["ElidedFallbackNameID"]
-            name = nameTable.getDebugName(nameID)
-            if not name:
-                raise FeatureLibError(
-                    f"ElidedFallbackNameID {nameID} points "
-                    "to a nameID that does not exist in the "
-                    '"name" table',
-                    None,
-                )
-        elif "ElidedFallbackName" in self.stat_:
-            nameID = self.stat_["ElidedFallbackName"]
-
-        otl.buildStatTable(
-            self.font,
-            designAxes,
-            locations=format4_locations,
-            elidedFallbackName=nameID,
-        )
+            checkattr(table, ("usLowerOpticalPointSize",
+                              "usUpperOpticalPointSize"))
 
     def build_codepages_(self, pages):
         pages2bits = {
-            1252: 0,
-            1250: 1,
-            1251: 2,
-            1253: 3,
-            1254: 4,
-            1255: 5,
-            1256: 6,
-            1257: 7,
-            1258: 8,
-            874: 16,
-            932: 17,
-            936: 18,
-            949: 19,
-            950: 20,
-            1361: 21,
-            869: 48,
-            866: 49,
-            865: 50,
-            864: 51,
-            863: 52,
-            862: 53,
-            861: 54,
-            860: 55,
-            857: 56,
-            855: 57,
-            852: 58,
-            775: 59,
-            737: 60,
-            708: 61,
-            850: 62,
-            437: 63,
+            1252: 0,  1250: 1, 1251: 2, 1253: 3, 1254: 4, 1255: 5, 1256: 6,
+            1257: 7,  1258: 8, 874: 16, 932: 17, 936: 18, 949: 19, 950: 20,
+            1361: 21, 869: 48, 866: 49, 865: 50, 864: 51, 863: 52, 862: 53,
+            861:  54, 860: 55, 857: 56, 855: 57, 852: 58, 775: 59, 737: 60,
+            708:  61, 850: 62, 437: 63,
         }
         bits = [pages2bits[p] for p in pages if p in pages2bits]
         pages = []
@@ -738,22 +472,16 @@
     def buildGDEF(self):
         gdef = otTables.GDEF()
         gdef.GlyphClassDef = self.buildGDEFGlyphClassDef_()
-        gdef.AttachList = otl.buildAttachList(self.attachPoints_, self.glyphMap)
-        gdef.LigCaretList = otl.buildLigCaretList(
-            self.ligCaretCoords_, self.ligCaretPoints_, self.glyphMap
-        )
+        gdef.AttachList = \
+            otl.buildAttachList(self.attachPoints_, self.glyphMap)
+        gdef.LigCaretList = \
+            otl.buildLigCaretList(self.ligCaretCoords_, self.ligCaretPoints_,
+                                  self.glyphMap)
         gdef.MarkAttachClassDef = self.buildGDEFMarkAttachClassDef_()
         gdef.MarkGlyphSetsDef = self.buildGDEFMarkGlyphSetsDef_()
         gdef.Version = 0x00010002 if gdef.MarkGlyphSetsDef else 0x00010000
-        if any(
-            (
-                gdef.GlyphClassDef,
-                gdef.AttachList,
-                gdef.LigCaretList,
-                gdef.MarkAttachClassDef,
-                gdef.MarkGlyphSetsDef,
-            )
-        ):
+        if any((gdef.GlyphClassDef, gdef.AttachList, gdef.LigCaretList,
+                gdef.MarkAttachClassDef, gdef.MarkGlyphSetsDef)):
             result = newTable("GDEF")
             result.table = gdef
             return result
@@ -788,20 +516,13 @@
 
     def buildGDEFMarkGlyphSetsDef_(self):
         sets = []
-        for glyphs, id_ in sorted(
-            self.markFilterSets_.items(), key=lambda item: item[1]
-        ):
+        for glyphs, id_ in sorted(self.markFilterSets_.items(),
+                                 key=lambda item: item[1]):
             sets.append(glyphs)
         return otl.buildMarkGlyphSetsDef(sets, self.glyphMap)
 
-    def buildDebg(self):
-        if "Debg" not in self.font:
-            self.font["Debg"] = newTable("Debg")
-            self.font["Debg"].data = {}
-        self.font["Debg"].data[LOOKUP_DEBUG_INFO_KEY] = self.lookup_locations
-
     def buildLookups_(self, tag):
-        assert tag in ("GPOS", "GSUB"), tag
+        assert tag in ('GPOS', 'GSUB'), tag
         for lookup in self.lookups_:
             lookup.lookup_index = None
         lookups = []
@@ -809,17 +530,8 @@
             if lookup.table != tag:
                 continue
             lookup.lookup_index = len(lookups)
-            self.lookup_locations[tag][str(lookup.lookup_index)] = LookupDebugInfo(
-                location=str(lookup.location),
-                name=self.get_lookup_name_(lookup),
-                feature=None,
-            )
             lookups.append(lookup)
-        try:
-            otLookups = [l.build() for l in lookups]
-        except OpenTypeLibError as e:
-            raise FeatureLibError(str(e), e.location) from e
-        return otLookups
+        return [l.build() for l in lookups]
 
     def makeTable(self, tag):
         table = getattr(otTables, tag, None)()
@@ -844,25 +556,13 @@
             # l.lookup_index will be None when a lookup is not needed
             # for the table under construction. For example, substitution
             # rules will have no lookup_index while building GPOS tables.
-            lookup_indices = tuple(
-                [l.lookup_index for l in lookups if l.lookup_index is not None]
-            )
+            lookup_indices = tuple([l.lookup_index for l in lookups
+                                    if l.lookup_index is not None])
 
-            size_feature = tag == "GPOS" and feature_tag == "size"
+            size_feature = (tag == "GPOS" and feature_tag == "size")
             if len(lookup_indices) == 0 and not size_feature:
                 continue
 
-            for ix in lookup_indices:
-                try:
-                    self.lookup_locations[tag][str(ix)] = self.lookup_locations[tag][
-                        str(ix)
-                    ]._replace(feature=key)
-                except KeyError:
-                    warnings.warn(
-                        "feaLib.Builder subclass needs upgrading to "
-                        "stash debug information. See fonttools#2065."
-                    )
-
             feature_key = (feature_tag, lookup_indices)
             feature_index = feature_indices.get(feature_key)
             if feature_index is None:
@@ -870,12 +570,14 @@
                 frec = otTables.FeatureRecord()
                 frec.FeatureTag = feature_tag
                 frec.Feature = otTables.Feature()
-                frec.Feature.FeatureParams = self.buildFeatureParams(feature_tag)
+                frec.Feature.FeatureParams = self.buildFeatureParams(
+                                                feature_tag)
                 frec.Feature.LookupListIndex = list(lookup_indices)
                 frec.Feature.LookupCount = len(lookup_indices)
                 table.FeatureList.FeatureRecord.append(frec)
                 feature_indices[feature_key] = feature_index
-            scripts.setdefault(script, {}).setdefault(lang, []).append(feature_index)
+            scripts.setdefault(script, {}).setdefault(lang, []).append(
+                feature_index)
             if self.required_features_.get((script, lang)) == feature_tag:
                 required_feature_indices[(script, lang)] = feature_index
 
@@ -891,16 +593,17 @@
                 langrec.LangSys = otTables.LangSys()
                 langrec.LangSys.LookupOrder = None
 
-                req_feature_index = required_feature_indices.get((script, lang))
+                req_feature_index = \
+                    required_feature_indices.get((script, lang))
                 if req_feature_index is None:
                     langrec.LangSys.ReqFeatureIndex = 0xFFFF
                 else:
                     langrec.LangSys.ReqFeatureIndex = req_feature_index
 
-                langrec.LangSys.FeatureIndex = [
-                    i for i in feature_indices if i != req_feature_index
-                ]
-                langrec.LangSys.FeatureCount = len(langrec.LangSys.FeatureIndex)
+                langrec.LangSys.FeatureIndex = [i for i in feature_indices
+                                                if i != req_feature_index]
+                langrec.LangSys.FeatureCount = \
+                    len(langrec.LangSys.FeatureIndex)
 
                 if lang == "dflt":
                     srec.Script.DefaultLangSys = langrec.LangSys
@@ -915,35 +618,26 @@
         table.LookupList.LookupCount = len(table.LookupList.Lookup)
         return table
 
-    def get_lookup_name_(self, lookup):
-        rev = {v: k for k, v in self.named_lookups_.items()}
-        if lookup in rev:
-            return rev[lookup]
-        return None
-
     def add_language_system(self, location, script, language):
         # OpenType Feature File Specification, section 4.b.i
-        if script == "DFLT" and language == "dflt" and self.default_language_systems_:
+        if (script == "DFLT" and language == "dflt" and
+                self.default_language_systems_):
             raise FeatureLibError(
                 'If "languagesystem DFLT dflt" is present, it must be '
-                "the first of the languagesystem statements",
-                location,
-            )
+                'the first of the languagesystem statements', location)
         if script == "DFLT":
             if self.seen_non_DFLT_script_:
                 raise FeatureLibError(
                     'languagesystems using the "DFLT" script tag must '
                     "precede all other languagesystems",
-                    location,
+                    location
                 )
         else:
             self.seen_non_DFLT_script_ = True
         if (script, language) in self.default_language_systems_:
             raise FeatureLibError(
-                '"languagesystem %s %s" has already been specified'
-                % (script.strip(), language.strip()),
-                location,
-            )
+                '"languagesystem %s %s" has already been specified' %
+                (script.strip(), language.strip()), location)
         self.default_language_systems_.add((script, language))
 
     def get_default_language_systems_(self):
@@ -955,11 +649,11 @@
         if self.default_language_systems_:
             return frozenset(self.default_language_systems_)
         else:
-            return frozenset({("DFLT", "dflt")})
+            return frozenset({('DFLT', 'dflt')})
 
     def start_feature(self, location, name):
         self.language_systems = self.get_default_language_systems_()
-        self.script_ = "DFLT"
+        self.script_ = 'DFLT'
         self.cur_lookup_ = None
         self.cur_feature_name_ = name
         self.lookupflag_ = 0
@@ -978,28 +672,24 @@
     def start_lookup_block(self, location, name):
         if name in self.named_lookups_:
             raise FeatureLibError(
-                'Lookup "%s" has already been defined' % name, location
-            )
+                'Lookup "%s" has already been defined' % name, location)
         if self.cur_feature_name_ == "aalt":
             raise FeatureLibError(
                 "Lookup blocks cannot be placed inside 'aalt' features; "
                 "move it out, and then refer to it with a lookup statement",
-                location,
-            )
+                location)
         self.cur_lookup_name_ = name
         self.named_lookups_[name] = None
         self.cur_lookup_ = None
-        if self.cur_feature_name_ is None:
-            self.lookupflag_ = 0
-            self.lookupflag_markFilterSet_ = None
+        self.lookupflag_ = 0
+        self.lookupflag_markFilterSet_ = None
 
     def end_lookup_block(self):
         assert self.cur_lookup_name_ is not None
         self.cur_lookup_name_ = None
         self.cur_lookup_ = None
-        if self.cur_feature_name_ is None:
-            self.lookupflag_ = 0
-            self.lookupflag_markFilterSet_ = None
+        self.lookupflag_ = 0
+        self.lookupflag_markFilterSet_ = None
 
     def add_lookup_call(self, lookup_name):
         assert lookup_name in self.named_lookups_, lookup_name
@@ -1011,24 +701,16 @@
         self.fontRevision_ = revision
 
     def set_language(self, location, language, include_default, required):
-        assert len(language) == 4
-        if self.cur_feature_name_ in ("aalt", "size"):
+        assert(len(language) == 4)
+        if self.cur_feature_name_ in ('aalt', 'size'):
             raise FeatureLibError(
                 "Language statements are not allowed "
-                'within "feature %s"' % self.cur_feature_name_,
-                location,
-            )
-        if self.cur_feature_name_ is None:
-            raise FeatureLibError(
-                "Language statements are not allowed "
-                "within standalone lookup blocks",
-                location,
-            )
+                "within \"feature %s\"" % self.cur_feature_name_, location)
         self.cur_lookup_ = None
 
         key = (self.script_, language, self.cur_feature_name_)
-        lookups = self.features_.get((key[0], "dflt", key[2]))
-        if (language == "dflt" or include_default) and lookups:
+        lookups = self.features_.get((key[0], 'dflt', key[2]))
+        if (language == 'dflt' or include_default) and lookups:
             self.features_[key] = lookups[:]
         else:
             self.features_[key] = []
@@ -1039,14 +721,10 @@
             if key in self.required_features_:
                 raise FeatureLibError(
                     "Language %s (script %s) has already "
-                    "specified feature %s as its required feature"
-                    % (
-                        language.strip(),
-                        self.script_.strip(),
-                        self.required_features_[key].strip(),
-                    ),
-                    location,
-                )
+                    "specified feature %s as its required feature" % (
+                        language.strip(), self.script_.strip(),
+                        self.required_features_[key].strip()),
+                    location)
             self.required_features_[key] = self.cur_feature_name_
 
     def getMarkAttachClass_(self, location, glyphs):
@@ -1061,9 +739,9 @@
                 _, loc = self.markAttach_[glyph]
                 raise FeatureLibError(
                     "Glyph %s already has been assigned "
-                    "a MarkAttachmentType at %s" % (glyph, loc),
-                    location,
-                )
+                    "a MarkAttachmentType at %s:%d:%d" % (
+                        glyph, loc[0], loc[1], loc[2]),
+                    location)
             self.markAttach_[glyph] = (id_, location)
         return id_
 
@@ -1090,25 +768,16 @@
         self.lookupflag_ = value
 
     def set_script(self, location, script):
-        if self.cur_feature_name_ in ("aalt", "size"):
+        if self.cur_feature_name_ in ('aalt', 'size'):
             raise FeatureLibError(
                 "Script statements are not allowed "
-                'within "feature %s"' % self.cur_feature_name_,
-                location,
-            )
-        if self.cur_feature_name_ is None:
-            raise FeatureLibError(
-                "Script statements are not allowed " "within standalone lookup blocks",
-                location,
-            )
-        if self.language_systems == {(script, "dflt")}:
-            # Nothing to do.
-            return
+                "within \"feature %s\"" % self.cur_feature_name_, location)
         self.cur_lookup_ = None
         self.script_ = script
         self.lookupflag_ = 0
         self.lookupflag_markFilterSet_ = None
-        self.set_language(location, "dflt", include_default=True, required=False)
+        self.set_language(location, "dflt",
+                          include_default=True, required=False)
 
     def find_lookup_builders_(self, lookups):
         """Helper for building chain contextual substitutions
@@ -1117,11 +786,9 @@
         If an input name is None, it gets mapped to a None LookupBuilder.
         """
         lookup_builders = []
-        for lookuplist in lookups:
-            if lookuplist is not None:
-                lookup_builders.append(
-                    [self.named_lookups_.get(l.name) for l in lookuplist]
-                )
+        for lookup in lookups:
+            if lookup is not None:
+                lookup_builders.append(self.named_lookups_.get(lookup.name))
             else:
                 lookup_builders.append(None)
         return lookup_builders
@@ -1132,21 +799,17 @@
 
     def add_chain_context_pos(self, location, prefix, glyphs, suffix, lookups):
         lookup = self.get_lookup_(location, ChainContextPosBuilder)
-        lookup.rules.append(
-            ChainContextualRule(
-                prefix, glyphs, suffix, self.find_lookup_builders_(lookups)
-            )
-        )
+        lookup.rules.append((prefix, glyphs, suffix,
+                            self.find_lookup_builders_(lookups)))
 
-    def add_chain_context_subst(self, location, prefix, glyphs, suffix, lookups):
+    def add_chain_context_subst(self, location,
+                                prefix, glyphs, suffix, lookups):
         lookup = self.get_lookup_(location, ChainContextSubstBuilder)
-        lookup.rules.append(
-            ChainContextualRule(
-                prefix, glyphs, suffix, self.find_lookup_builders_(lookups)
-            )
-        )
+        lookup.substitutions.append((prefix, glyphs, suffix,
+                                     self.find_lookup_builders_(lookups)))
 
-    def add_alternate_subst(self, location, prefix, glyph, suffix, replacement):
+    def add_alternate_subst(self, location,
+                            prefix, glyph, suffix, replacement):
         if self.cur_feature_name_ == "aalt":
             alts = self.aalt_alternates_.setdefault(glyph, set())
             alts.update(replacement)
@@ -1154,20 +817,20 @@
         if prefix or suffix:
             chain = self.get_lookup_(location, ChainContextSubstBuilder)
             lookup = self.get_chained_lookup_(location, AlternateSubstBuilder)
-            chain.rules.append(ChainContextualRule(prefix, [{glyph}], suffix, [lookup]))
+            chain.substitutions.append((prefix, [glyph], suffix, [lookup]))
         else:
             lookup = self.get_lookup_(location, AlternateSubstBuilder)
         if glyph in lookup.alternates:
             raise FeatureLibError(
-                'Already defined alternates for glyph "%s"' % glyph, location
-            )
+                'Already defined alternates for glyph "%s"' % glyph,
+                location)
         lookup.alternates[glyph] = replacement
 
     def add_feature_reference(self, location, featureName):
         if self.cur_feature_name_ != "aalt":
             raise FeatureLibError(
-                'Feature references are only allowed inside "feature aalt"', location
-            )
+                'Feature references are only allowed inside "feature aalt"',
+                location)
         self.aalt_features_.append((location, featureName))
 
     def add_featureName(self, tag):
@@ -1177,7 +840,7 @@
         self.cv_parameters_.add(tag)
 
     def add_to_cv_num_named_params(self, tag):
-        """Adds new items to ``self.cv_num_named_params_``
+        """Adds new items to self.cv_num_named_params_
         or increments the count of existing items."""
         if tag in self.cv_num_named_params_:
             self.cv_num_named_params_[tag] += 1
@@ -1193,27 +856,23 @@
         else:
             self.base_horiz_axis_ = (bases, scripts)
 
-    def set_size_parameters(
-        self, location, DesignSize, SubfamilyID, RangeStart, RangeEnd
-    ):
-        if self.cur_feature_name_ != "size":
+    def set_size_parameters(self, location, DesignSize, SubfamilyID,
+                            RangeStart, RangeEnd):
+        if self.cur_feature_name_ != 'size':
             raise FeatureLibError(
                 "Parameters statements are not allowed "
-                'within "feature %s"' % self.cur_feature_name_,
-                location,
-            )
+                "within \"feature %s\"" % self.cur_feature_name_, location)
         self.size_parameters_ = [DesignSize, SubfamilyID, RangeStart, RangeEnd]
         for script, lang in self.language_systems:
             key = (script, lang, self.cur_feature_name_)
             self.features_.setdefault(key, [])
 
-    def add_ligature_subst(
-        self, location, prefix, glyphs, suffix, replacement, forceChain
-    ):
+    def add_ligature_subst(self, location,
+                           prefix, glyphs, suffix, replacement, forceChain):
         if prefix or suffix or forceChain:
             chain = self.get_lookup_(location, ChainContextSubstBuilder)
             lookup = self.get_chained_lookup_(location, LigatureSubstBuilder)
-            chain.rules.append(ChainContextualRule(prefix, glyphs, suffix, [lookup]))
+            chain.substitutions.append((prefix, glyphs, suffix, [lookup]))
         else:
             lookup = self.get_lookup_(location, LigatureSubstBuilder)
 
@@ -1225,34 +884,25 @@
         for g in sorted(itertools.product(*glyphs)):
             lookup.ligatures[g] = replacement
 
-    def add_multiple_subst(
-        self, location, prefix, glyph, suffix, replacements, forceChain=False
-    ):
+    def add_multiple_subst(self, location,
+                           prefix, glyph, suffix, replacements, forceChain=False):
         if prefix or suffix or forceChain:
             chain = self.get_lookup_(location, ChainContextSubstBuilder)
             sub = self.get_chained_lookup_(location, MultipleSubstBuilder)
             sub.mapping[glyph] = replacements
-            chain.rules.append(ChainContextualRule(prefix, [{glyph}], suffix, [sub]))
+            chain.substitutions.append((prefix, [{glyph}], suffix, [sub]))
             return
         lookup = self.get_lookup_(location, MultipleSubstBuilder)
         if glyph in lookup.mapping:
-            if replacements == lookup.mapping[glyph]:
-                log.info(
-                    "Removing duplicate multiple substitution from glyph"
-                    ' "%s" to %s%s',
-                    glyph,
-                    replacements,
-                    f" at {location}" if location else "",
-                )
-            else:
-                raise FeatureLibError(
-                    'Already defined substitution for glyph "%s"' % glyph, location
-                )
+            raise FeatureLibError(
+                'Already defined substitution for glyph "%s"' % glyph,
+                location)
         lookup.mapping[glyph] = replacements
 
-    def add_reverse_chain_single_subst(self, location, old_prefix, old_suffix, mapping):
+    def add_reverse_chain_single_subst(self, location, old_prefix,
+                                       old_suffix, mapping):
         lookup = self.get_lookup_(location, ReverseChainSingleSubstBuilder)
-        lookup.rules.append((old_prefix, old_suffix, mapping))
+        lookup.substitutions.append((old_prefix, old_suffix, mapping))
 
     def add_single_subst(self, location, prefix, suffix, mapping, forceChain):
         if self.cur_feature_name_ == "aalt":
@@ -1266,20 +916,10 @@
         lookup = self.get_lookup_(location, SingleSubstBuilder)
         for (from_glyph, to_glyph) in mapping.items():
             if from_glyph in lookup.mapping:
-                if to_glyph == lookup.mapping[from_glyph]:
-                    log.info(
-                        "Removing duplicate single substitution from glyph"
-                        ' "%s" to "%s" at %s',
-                        from_glyph,
-                        to_glyph,
-                        location,
-                    )
-                else:
-                    raise FeatureLibError(
-                        'Already defined rule for replacing glyph "%s" by "%s"'
-                        % (from_glyph, lookup.mapping[from_glyph]),
-                        location,
-                    )
+                raise FeatureLibError(
+                    'Already defined rule for replacing glyph "%s" by "%s"' %
+                    (from_glyph, lookup.mapping[from_glyph]),
+                    location)
             lookup.mapping[from_glyph] = to_glyph
 
     def add_single_subst_chained_(self, location, prefix, suffix, mapping):
@@ -1289,18 +929,14 @@
         if sub is None:
             sub = self.get_chained_lookup_(location, SingleSubstBuilder)
         sub.mapping.update(mapping)
-        chain.rules.append(
-            ChainContextualRule(prefix, [list(mapping.keys())], suffix, [sub])
-        )
+        chain.substitutions.append((prefix, [mapping.keys()], suffix, [sub]))
 
     def add_cursive_pos(self, location, glyphclass, entryAnchor, exitAnchor):
         lookup = self.get_lookup_(location, CursivePosBuilder)
         lookup.add_attachment(
-            location,
-            glyphclass,
+            location, glyphclass,
             makeOpenTypeAnchor(entryAnchor),
-            makeOpenTypeAnchor(exitAnchor),
-        )
+            makeOpenTypeAnchor(exitAnchor))
 
     def add_marks_(self, location, lookupBuilder, marks):
         """Helper for add_mark_{base,liga,mark}_pos."""
@@ -1309,15 +945,15 @@
                 for mark in markClassDef.glyphs.glyphSet():
                     if mark not in lookupBuilder.marks:
                         otMarkAnchor = makeOpenTypeAnchor(markClassDef.anchor)
-                        lookupBuilder.marks[mark] = (markClass.name, otMarkAnchor)
+                        lookupBuilder.marks[mark] = (
+                            markClass.name, otMarkAnchor)
                     else:
                         existingMarkClass = lookupBuilder.marks[mark][0]
                         if markClass.name != existingMarkClass:
                             raise FeatureLibError(
-                                "Glyph %s cannot be in both @%s and @%s"
-                                % (mark, existingMarkClass, markClass.name),
-                                location,
-                            )
+                                "Glyph %s cannot be in both @%s and @%s" % (
+                                    mark, existingMarkClass, markClass.name),
+                                location)
 
     def add_mark_base_pos(self, location, bases, marks):
         builder = self.get_lookup_(location, MarkBasePosBuilder)
@@ -1325,7 +961,8 @@
         for baseAnchor, markClass in marks:
             otBaseAnchor = makeOpenTypeAnchor(baseAnchor)
             for base in bases:
-                builder.bases.setdefault(base, {})[markClass.name] = otBaseAnchor
+                builder.bases.setdefault(base, {})[markClass.name] = (
+                    otBaseAnchor)
 
     def add_mark_lig_pos(self, location, ligatures, components):
         builder = self.get_lookup_(location, MarkLigPosBuilder)
@@ -1345,24 +982,20 @@
         for baseAnchor, markClass in marks:
             otBaseAnchor = makeOpenTypeAnchor(baseAnchor)
             for baseMark in baseMarks:
-                builder.baseMarks.setdefault(baseMark, {})[
-                    markClass.name
-                ] = otBaseAnchor
+                builder.baseMarks.setdefault(baseMark, {})[markClass.name] = (
+                    otBaseAnchor)
 
-    def add_class_pair_pos(self, location, glyphclass1, value1, glyphclass2, value2):
+    def add_class_pair_pos(self, location, glyphclass1, value1,
+                           glyphclass2, value2):
         lookup = self.get_lookup_(location, PairPosBuilder)
-        v1 = makeOpenTypeValueRecord(value1, pairPosContext=True)
-        v2 = makeOpenTypeValueRecord(value2, pairPosContext=True)
-        lookup.addClassPair(location, glyphclass1, v1, glyphclass2, v2)
+        lookup.addClassPair(location, glyphclass1, value1, glyphclass2, value2)
 
     def add_subtable_break(self, location):
         self.cur_lookup_.add_subtable_break(location)
 
     def add_specific_pair_pos(self, location, glyph1, value1, glyph2, value2):
         lookup = self.get_lookup_(location, PairPosBuilder)
-        v1 = makeOpenTypeValueRecord(value1, pairPosContext=True)
-        v2 = makeOpenTypeValueRecord(value2, pairPosContext=True)
-        lookup.addGlyphPair(location, glyph1, v1, glyph2, v2)
+        lookup.addGlyphPair(location, glyph1, value1, glyph2, value2)
 
     def add_single_pos(self, location, prefix, suffix, pos, forceChain):
         if prefix or suffix or forceChain:
@@ -1370,12 +1003,8 @@
         else:
             lookup = self.get_lookup_(location, SinglePosBuilder)
             for glyphs, value in pos:
-                otValueRecord = makeOpenTypeValueRecord(value, pairPosContext=False)
                 for glyph in glyphs:
-                    try:
-                        lookup.add_pos(location, glyph, otValueRecord)
-                    except OpenTypeLibError as e:
-                        raise FeatureLibError(str(e), e.location) from e
+                    lookup.add_pos(location, glyph, value)
 
     def add_single_pos_chained_(self, location, prefix, suffix, pos):
         # https://github.com/fonttools/fonttools/issues/514
@@ -1388,32 +1017,29 @@
             if value is None:
                 subs.append(None)
                 continue
-            otValue = makeOpenTypeValueRecord(value, pairPosContext=False)
+            otValue, _ = makeOpenTypeValueRecord(value, pairPosContext=False)
             sub = chain.find_chainable_single_pos(targets, glyphs, otValue)
             if sub is None:
                 sub = self.get_chained_lookup_(location, SinglePosBuilder)
                 targets.append(sub)
             for glyph in glyphs:
-                sub.add_pos(location, glyph, otValue)
+                sub.add_pos(location, glyph, value)
             subs.append(sub)
         assert len(pos) == len(subs), (pos, subs)
         chain.rules.append(
-            ChainContextualRule(prefix, [g for g, v in pos], suffix, subs)
-        )
+            (prefix, [g for g, v in pos], suffix, subs))
 
     def setGlyphClass_(self, location, glyph, glyphClass):
         oldClass, oldLocation = self.glyphClassDefs_.get(glyph, (None, None))
         if oldClass and oldClass != glyphClass:
             raise FeatureLibError(
-                "Glyph %s was assigned to a different class at %s"
-                % (glyph, oldLocation),
-                location,
-            )
+                "Glyph %s was assigned to a different class at %s:%s:%s" %
+                (glyph, oldLocation[0], oldLocation[1], oldLocation[2]),
+                location)
         self.glyphClassDefs_[glyph] = (glyphClass, location)
 
-    def add_glyphClassDef(
-        self, location, baseGlyphs, ligatureGlyphs, markGlyphs, componentGlyphs
-    ):
+    def add_glyphClassDef(self, location, baseGlyphs, ligatureGlyphs,
+                          markGlyphs, componentGlyphs):
         for glyph in baseGlyphs:
             self.setGlyphClass_(location, glyph, 1)
         for glyph in ligatureGlyphs:
@@ -1425,15 +1051,14 @@
 
     def add_ligatureCaretByIndex_(self, location, glyphs, carets):
         for glyph in glyphs:
-            if glyph not in self.ligCaretPoints_:
-                self.ligCaretPoints_[glyph] = carets
+            self.ligCaretPoints_.setdefault(glyph, set()).update(carets)
 
     def add_ligatureCaretByPos_(self, location, glyphs, carets):
         for glyph in glyphs:
-            if glyph not in self.ligCaretCoords_:
-                self.ligCaretCoords_[glyph] = carets
+            self.ligCaretCoords_.setdefault(glyph, set()).update(carets)
 
-    def add_name_record(self, location, nameID, platformID, platEncID, langID, string):
+    def add_name_record(self, location, nameID, platformID, platEncID,
+                        langID, string):
         self.names_.append([nameID, platformID, platEncID, langID, string])
 
     def add_os2_field(self, key, value):
@@ -1455,7 +1080,8 @@
         deviceX = otl.buildDevice(dict(anchor.xDeviceTable))
     if anchor.yDeviceTable is not None:
         deviceY = otl.buildDevice(dict(anchor.yDeviceTable))
-    return otl.buildAnchor(anchor.x, anchor.y, anchor.contourpoint, deviceX, deviceY)
+    return otl.buildAnchor(anchor.x, anchor.y, anchor.contourpoint,
+                           deviceX, deviceY)
 
 
 _VALUEREC_ATTRS = {
@@ -1466,9 +1092,9 @@
 
 
 def makeOpenTypeValueRecord(v, pairPosContext):
-    """ast.ValueRecord --> otBase.ValueRecord"""
+    """ast.ValueRecord --> (otBase.ValueRecord, int ValueFormat)"""
     if not v:
-        return None
+        return None, 0
 
     vr = {}
     for astName, (otName, isDevice) in _VALUEREC_ATTRS.items():
@@ -1478,4 +1104,547 @@
     if pairPosContext and not vr:
         vr = {"YAdvance": 0} if v.vertical else {"XAdvance": 0}
     valRec = otl.buildValue(vr)
-    return valRec
+    return valRec, valRec.getFormat()
+
+
+class LookupBuilder(object):
+    SUBTABLE_BREAK_ = "SUBTABLE_BREAK"
+
+    def __init__(self, font, location, table, lookup_type):
+        self.font = font
+        self.glyphMap = font.getReverseGlyphMap()
+        self.location = location
+        self.table, self.lookup_type = table, lookup_type
+        self.lookupflag = 0
+        self.markFilterSet = None
+        self.lookup_index = None  # assigned when making final tables
+        assert table in ('GPOS', 'GSUB')
+
+    def equals(self, other):
+        return (isinstance(other, self.__class__) and
+                self.table == other.table and
+                self.lookupflag == other.lookupflag and
+                self.markFilterSet == other.markFilterSet)
+
+    def inferGlyphClasses(self):
+        """Infers glyph glasses for the GDEF table, such as {"cedilla":3}."""
+        return {}
+
+    def getAlternateGlyphs(self):
+        """Helper for building 'aalt' features."""
+        return {}
+
+    def buildLookup_(self, subtables):
+        return otl.buildLookup(subtables, self.lookupflag, self.markFilterSet)
+
+    def buildMarkClasses_(self, marks):
+        """{"cedilla": ("BOTTOM", ast.Anchor), ...} --> {"BOTTOM":0, "TOP":1}
+
+        Helper for MarkBasePostBuilder, MarkLigPosBuilder, and
+        MarkMarkPosBuilder. Seems to return the same numeric IDs
+        for mark classes as the AFDKO makeotf tool.
+        """
+        ids = {}
+        for mark in sorted(marks.keys(), key=self.font.getGlyphID):
+            markClassName, _markAnchor = marks[mark]
+            if markClassName not in ids:
+                ids[markClassName] = len(ids)
+        return ids
+
+    def setBacktrackCoverage_(self, prefix, subtable):
+        subtable.BacktrackGlyphCount = len(prefix)
+        subtable.BacktrackCoverage = []
+        for p in reversed(prefix):
+            coverage = otl.buildCoverage(p, self.glyphMap)
+            subtable.BacktrackCoverage.append(coverage)
+
+    def setLookAheadCoverage_(self, suffix, subtable):
+        subtable.LookAheadGlyphCount = len(suffix)
+        subtable.LookAheadCoverage = []
+        for s in suffix:
+            coverage = otl.buildCoverage(s, self.glyphMap)
+            subtable.LookAheadCoverage.append(coverage)
+
+    def setInputCoverage_(self, glyphs, subtable):
+        subtable.InputGlyphCount = len(glyphs)
+        subtable.InputCoverage = []
+        for g in glyphs:
+            coverage = otl.buildCoverage(g, self.glyphMap)
+            subtable.InputCoverage.append(coverage)
+
+    def build_subst_subtables(self, mapping, klass):
+        substitutions = [{}]
+        for key in mapping:
+            if key[0] == self.SUBTABLE_BREAK_:
+                substitutions.append({})
+            else:
+                substitutions[-1][key] = mapping[key]
+        subtables = [klass(s) for s in substitutions]
+        return subtables
+
+    def add_subtable_break(self, location):
+        log.warning(FeatureLibError(
+            'unsupported "subtable" statement for lookup type',
+            location
+        ))
+
+
+class AlternateSubstBuilder(LookupBuilder):
+    def __init__(self, font, location):
+        LookupBuilder.__init__(self, font, location, 'GSUB', 3)
+        self.alternates = OrderedDict()
+
+    def equals(self, other):
+        return (LookupBuilder.equals(self, other) and
+                self.alternates == other.alternates)
+
+    def build(self):
+        subtables = self.build_subst_subtables(self.alternates,
+                otl.buildAlternateSubstSubtable)
+        return self.buildLookup_(subtables)
+
+    def getAlternateGlyphs(self):
+        return self.alternates
+
+    def add_subtable_break(self, location):
+        self.alternates[(self.SUBTABLE_BREAK_, location)] = self.SUBTABLE_BREAK_
+
+
+class ChainContextPosBuilder(LookupBuilder):
+    def __init__(self, font, location):
+        LookupBuilder.__init__(self, font, location, 'GPOS', 8)
+        self.rules = []  # (prefix, input, suffix, lookups)
+
+    def equals(self, other):
+        return (LookupBuilder.equals(self, other) and
+                self.rules == other.rules)
+
+    def build(self):
+        subtables = []
+        for (prefix, glyphs, suffix, lookups) in self.rules:
+            if prefix == self.SUBTABLE_BREAK_:
+                continue
+            st = otTables.ChainContextPos()
+            subtables.append(st)
+            st.Format = 3
+            self.setBacktrackCoverage_(prefix, st)
+            self.setLookAheadCoverage_(suffix, st)
+            self.setInputCoverage_(glyphs, st)
+
+            st.PosCount = len([l for l in lookups if l is not None])
+            st.PosLookupRecord = []
+            for sequenceIndex, l in enumerate(lookups):
+                if l is not None:
+                    rec = otTables.PosLookupRecord()
+                    rec.SequenceIndex = sequenceIndex
+                    rec.LookupListIndex = l.lookup_index
+                    st.PosLookupRecord.append(rec)
+        return self.buildLookup_(subtables)
+
+    def find_chainable_single_pos(self, lookups, glyphs, value):
+        """Helper for add_single_pos_chained_()"""
+        res = None
+        for lookup in lookups[::-1]:
+            if lookup == self.SUBTABLE_BREAK_:
+                return res
+            if isinstance(lookup, SinglePosBuilder) and \
+                    all(lookup.can_add(glyph, value) for glyph in glyphs):
+                res = lookup
+        return res
+
+    def add_subtable_break(self, location):
+        self.rules.append((self.SUBTABLE_BREAK_, self.SUBTABLE_BREAK_,
+                           self.SUBTABLE_BREAK_, [self.SUBTABLE_BREAK_]))
+
+
+class ChainContextSubstBuilder(LookupBuilder):
+    def __init__(self, font, location):
+        LookupBuilder.__init__(self, font, location, 'GSUB', 6)
+        self.substitutions = []  # (prefix, input, suffix, lookups)
+
+    def equals(self, other):
+        return (LookupBuilder.equals(self, other) and
+                self.substitutions == other.substitutions)
+
+    def build(self):
+        subtables = []
+        for (prefix, input, suffix, lookups) in self.substitutions:
+            if prefix == self.SUBTABLE_BREAK_:
+                continue
+            st = otTables.ChainContextSubst()
+            subtables.append(st)
+            st.Format = 3
+            self.setBacktrackCoverage_(prefix, st)
+            self.setLookAheadCoverage_(suffix, st)
+            self.setInputCoverage_(input, st)
+
+            st.SubstCount = len([l for l in lookups if l is not None])
+            st.SubstLookupRecord = []
+            for sequenceIndex, l in enumerate(lookups):
+                if l is not None:
+                    rec = otTables.SubstLookupRecord()
+                    rec.SequenceIndex = sequenceIndex
+                    rec.LookupListIndex = l.lookup_index
+                    st.SubstLookupRecord.append(rec)
+        return self.buildLookup_(subtables)
+
+    def getAlternateGlyphs(self):
+        result = {}
+        for (_, _, _, lookups) in self.substitutions:
+            if lookups == self.SUBTABLE_BREAK_:
+                continue
+            for lookup in lookups:
+                alts = lookup.getAlternateGlyphs()
+                for glyph, replacements in alts.items():
+                    result.setdefault(glyph, set()).update(replacements)
+        return result
+
+    def find_chainable_single_subst(self, glyphs):
+        """Helper for add_single_subst_chained_()"""
+        res = None
+        for _, _, _, substitutions in self.substitutions[::-1]:
+            if substitutions == self.SUBTABLE_BREAK_:
+                return res
+            for sub in substitutions:
+                if (isinstance(sub, SingleSubstBuilder) and
+                        not any(g in glyphs for g in sub.mapping.keys())):
+                    res = sub
+        return res
+
+    def add_subtable_break(self, location):
+        self.substitutions.append((self.SUBTABLE_BREAK_, self.SUBTABLE_BREAK_,
+                                   self.SUBTABLE_BREAK_, self.SUBTABLE_BREAK_))
+
+
+class LigatureSubstBuilder(LookupBuilder):
+    def __init__(self, font, location):
+        LookupBuilder.__init__(self, font, location, 'GSUB', 4)
+        self.ligatures = OrderedDict()  # {('f','f','i'): 'f_f_i'}
+
+    def equals(self, other):
+        return (LookupBuilder.equals(self, other) and
+                self.ligatures == other.ligatures)
+
+    def build(self):
+        subtables = self.build_subst_subtables(self.ligatures,
+                otl.buildLigatureSubstSubtable)
+        return self.buildLookup_(subtables)
+
+    def add_subtable_break(self, location):
+        self.ligatures[(self.SUBTABLE_BREAK_, location)] = self.SUBTABLE_BREAK_
+
+
+class MultipleSubstBuilder(LookupBuilder):
+    def __init__(self, font, location):
+        LookupBuilder.__init__(self, font, location, 'GSUB', 2)
+        self.mapping = OrderedDict()
+
+    def equals(self, other):
+        return (LookupBuilder.equals(self, other) and
+                self.mapping == other.mapping)
+
+    def build(self):
+        subtables = self.build_subst_subtables(self.mapping,
+                otl.buildMultipleSubstSubtable)
+        return self.buildLookup_(subtables)
+
+    def add_subtable_break(self, location):
+        self.mapping[(self.SUBTABLE_BREAK_, location)] = self.SUBTABLE_BREAK_
+
+
+class CursivePosBuilder(LookupBuilder):
+    def __init__(self, font, location):
+        LookupBuilder.__init__(self, font, location, 'GPOS', 3)
+        self.attachments = {}
+
+    def equals(self, other):
+        return (LookupBuilder.equals(self, other) and
+                self.attachments == other.attachments)
+
+    def add_attachment(self, location, glyphs, entryAnchor, exitAnchor):
+        for glyph in glyphs:
+            self.attachments[glyph] = (entryAnchor, exitAnchor)
+
+    def build(self):
+        st = otl.buildCursivePosSubtable(self.attachments, self.glyphMap)
+        return self.buildLookup_([st])
+
+
+class MarkBasePosBuilder(LookupBuilder):
+    def __init__(self, font, location):
+        LookupBuilder.__init__(self, font, location, 'GPOS', 4)
+        self.marks = {}  # glyphName -> (markClassName, anchor)
+        self.bases = {}  # glyphName -> {markClassName: anchor}
+
+    def equals(self, other):
+        return (LookupBuilder.equals(self, other) and
+                self.marks == other.marks and
+                self.bases == other.bases)
+
+    def inferGlyphClasses(self):
+        result = {glyph: 1 for glyph in self.bases}
+        result.update({glyph: 3 for glyph in self.marks})
+        return result
+
+    def build(self):
+        markClasses = self.buildMarkClasses_(self.marks)
+        marks = {mark: (markClasses[mc], anchor)
+                 for mark, (mc, anchor) in self.marks.items()}
+        bases = {}
+        for glyph, anchors in self.bases.items():
+            bases[glyph] = {markClasses[mc]: anchor
+                            for (mc, anchor) in anchors.items()}
+        subtables = otl.buildMarkBasePos(marks, bases, self.glyphMap)
+        return self.buildLookup_(subtables)
+
+
+class MarkLigPosBuilder(LookupBuilder):
+    def __init__(self, font, location):
+        LookupBuilder.__init__(self, font, location, 'GPOS', 5)
+        self.marks = {}  # glyphName -> (markClassName, anchor)
+        self.ligatures = {}  # glyphName -> [{markClassName: anchor}, ...]
+
+    def equals(self, other):
+        return (LookupBuilder.equals(self, other) and
+                self.marks == other.marks and
+                self.ligatures == other.ligatures)
+
+    def inferGlyphClasses(self):
+        result = {glyph: 2 for glyph in self.ligatures}
+        result.update({glyph: 3 for glyph in self.marks})
+        return result
+
+    def build(self):
+        markClasses = self.buildMarkClasses_(self.marks)
+        marks = {mark: (markClasses[mc], anchor)
+                 for mark, (mc, anchor) in self.marks.items()}
+        ligs = {}
+        for lig, components in self.ligatures.items():
+            ligs[lig] = []
+            for c in components:
+                ligs[lig].append({markClasses[mc]: a for mc, a in c.items()})
+        subtables = otl.buildMarkLigPos(marks, ligs, self.glyphMap)
+        return self.buildLookup_(subtables)
+
+
+class MarkMarkPosBuilder(LookupBuilder):
+    def __init__(self, font, location):
+        LookupBuilder.__init__(self, font, location, 'GPOS', 6)
+        self.marks = {}      # glyphName -> (markClassName, anchor)
+        self.baseMarks = {}  # glyphName -> {markClassName: anchor}
+
+    def equals(self, other):
+        return (LookupBuilder.equals(self, other) and
+                self.marks == other.marks and
+                self.baseMarks == other.baseMarks)
+
+    def inferGlyphClasses(self):
+        result = {glyph: 3 for glyph in self.baseMarks}
+        result.update({glyph: 3 for glyph in self.marks})
+        return result
+
+    def build(self):
+        markClasses = self.buildMarkClasses_(self.marks)
+        markClassList = sorted(markClasses.keys(), key=markClasses.get)
+        marks = {mark: (markClasses[mc], anchor)
+                 for mark, (mc, anchor) in self.marks.items()}
+
+        st = otTables.MarkMarkPos()
+        st.Format = 1
+        st.ClassCount = len(markClasses)
+        st.Mark1Coverage = otl.buildCoverage(marks, self.glyphMap)
+        st.Mark2Coverage = otl.buildCoverage(self.baseMarks, self.glyphMap)
+        st.Mark1Array = otl.buildMarkArray(marks, self.glyphMap)
+        st.Mark2Array = otTables.Mark2Array()
+        st.Mark2Array.Mark2Count = len(st.Mark2Coverage.glyphs)
+        st.Mark2Array.Mark2Record = []
+        for base in st.Mark2Coverage.glyphs:
+            anchors = [self.baseMarks[base].get(mc) for mc in markClassList]
+            st.Mark2Array.Mark2Record.append(otl.buildMark2Record(anchors))
+        return self.buildLookup_([st])
+
+
+class ReverseChainSingleSubstBuilder(LookupBuilder):
+    def __init__(self, font, location):
+        LookupBuilder.__init__(self, font, location, 'GSUB', 8)
+        self.substitutions = []  # (prefix, suffix, mapping)
+
+    def equals(self, other):
+        return (LookupBuilder.equals(self, other) and
+                self.substitutions == other.substitutions)
+
+    def build(self):
+        subtables = []
+        for prefix, suffix, mapping in self.substitutions:
+            st = otTables.ReverseChainSingleSubst()
+            st.Format = 1
+            self.setBacktrackCoverage_(prefix, st)
+            self.setLookAheadCoverage_(suffix, st)
+            st.Coverage = otl.buildCoverage(mapping.keys(), self.glyphMap)
+            st.GlyphCount = len(mapping)
+            st.Substitute = [mapping[g] for g in st.Coverage.glyphs]
+            subtables.append(st)
+        return self.buildLookup_(subtables)
+
+    def add_subtable_break(self, location):
+        # Nothing to do here, each substitution is in its own subtable.
+        pass
+
+
+class SingleSubstBuilder(LookupBuilder):
+    def __init__(self, font, location):
+        LookupBuilder.__init__(self, font, location, 'GSUB', 1)
+        self.mapping = OrderedDict()
+
+    def equals(self, other):
+        return (LookupBuilder.equals(self, other) and
+                self.mapping == other.mapping)
+
+    def build(self):
+        subtables = self.build_subst_subtables(self.mapping,
+                otl.buildSingleSubstSubtable)
+        return self.buildLookup_(subtables)
+
+    def getAlternateGlyphs(self):
+        return {glyph: set([repl]) for glyph, repl in self.mapping.items()}
+
+    def add_subtable_break(self, location):
+        self.mapping[(self.SUBTABLE_BREAK_, location)] = self.SUBTABLE_BREAK_
+
+
+class ClassPairPosSubtableBuilder(object):
+    def __init__(self, builder, valueFormat1, valueFormat2):
+        self.builder_ = builder
+        self.classDef1_, self.classDef2_ = None, None
+        self.values_ = {}  # (glyphclass1, glyphclass2) --> (value1, value2)
+        self.valueFormat1_, self.valueFormat2_ = valueFormat1, valueFormat2
+        self.forceSubtableBreak_ = False
+        self.subtables_ = []
+
+    def addPair(self, gc1, value1, gc2, value2):
+        mergeable = (not self.forceSubtableBreak_ and
+                     self.classDef1_ is not None and
+                     self.classDef1_.canAdd(gc1) and
+                     self.classDef2_ is not None and
+                     self.classDef2_.canAdd(gc2))
+        if not mergeable:
+            self.flush_()
+            self.classDef1_ = otl.ClassDefBuilder(useClass0=True)
+            self.classDef2_ = otl.ClassDefBuilder(useClass0=False)
+            self.values_ = {}
+        self.classDef1_.add(gc1)
+        self.classDef2_.add(gc2)
+        self.values_[(gc1, gc2)] = (value1, value2)
+
+    def addSubtableBreak(self):
+        self.forceSubtableBreak_ = True
+
+    def subtables(self):
+        self.flush_()
+        return self.subtables_
+
+    def flush_(self):
+        if self.classDef1_ is None or self.classDef2_ is None:
+            return
+        st = otl.buildPairPosClassesSubtable(self.values_,
+                                             self.builder_.glyphMap)
+        if st.Coverage is None:
+            return
+        self.subtables_.append(st)
+        self.forceSubtableBreak_ = False
+
+
+class PairPosBuilder(LookupBuilder):
+    def __init__(self, font, location):
+        LookupBuilder.__init__(self, font, location, 'GPOS', 2)
+        self.pairs = []  # [(gc1, value1, gc2, value2)*]
+        self.glyphPairs = {}  # (glyph1, glyph2) --> (value1, value2)
+        self.locations = {}  # (gc1, gc2) --> (filepath, line, column)
+
+    def addClassPair(self, location, glyphclass1, value1, glyphclass2, value2):
+        self.pairs.append((glyphclass1, value1, glyphclass2, value2))
+
+    def addGlyphPair(self, location, glyph1, value1, glyph2, value2):
+        key = (glyph1, glyph2)
+        oldValue = self.glyphPairs.get(key, None)
+        if oldValue is not None:
+            # the Feature File spec explicitly allows specific pairs generated
+            # by an 'enum' rule to be overridden by preceding single pairs
+            otherLoc = self.locations[key]
+            log.debug(
+                'Already defined position for pair %s %s at %s:%d:%d; '
+                'choosing the first value',
+                glyph1, glyph2, otherLoc[0], otherLoc[1], otherLoc[2])
+        else:
+            val1, _ = makeOpenTypeValueRecord(value1, pairPosContext=True)
+            val2, _ = makeOpenTypeValueRecord(value2, pairPosContext=True)
+            self.glyphPairs[key] = (val1, val2)
+            self.locations[key] = location
+
+    def add_subtable_break(self, location):
+        self.pairs.append((self.SUBTABLE_BREAK_, self.SUBTABLE_BREAK_,
+                           self.SUBTABLE_BREAK_, self.SUBTABLE_BREAK_))
+
+    def equals(self, other):
+        return (LookupBuilder.equals(self, other) and
+                self.glyphPairs == other.glyphPairs and
+                self.pairs == other.pairs)
+
+    def build(self):
+        builders = {}
+        builder = None
+        for glyphclass1, value1, glyphclass2, value2 in self.pairs:
+            if glyphclass1 is self.SUBTABLE_BREAK_:
+                if builder is not None:
+                    builder.addSubtableBreak()
+                continue
+            val1, valFormat1 = makeOpenTypeValueRecord(
+                value1, pairPosContext=True)
+            val2, valFormat2 = makeOpenTypeValueRecord(
+                value2, pairPosContext=True)
+            builder = builders.get((valFormat1, valFormat2))
+            if builder is None:
+                builder = ClassPairPosSubtableBuilder(
+                    self, valFormat1, valFormat2)
+                builders[(valFormat1, valFormat2)] = builder
+            builder.addPair(glyphclass1, val1, glyphclass2, val2)
+        subtables = []
+        if self.glyphPairs:
+            subtables.extend(
+                otl.buildPairPosGlyphs(self.glyphPairs, self.glyphMap))
+        for key in sorted(builders.keys()):
+            subtables.extend(builders[key].subtables())
+        return self.buildLookup_(subtables)
+
+
+class SinglePosBuilder(LookupBuilder):
+    def __init__(self, font, location):
+        LookupBuilder.__init__(self, font, location, 'GPOS', 1)
+        self.locations = {}  # glyph -> (filename, line, column)
+        self.mapping = {}  # glyph -> otTables.ValueRecord
+
+    def add_pos(self, location, glyph, valueRecord):
+        otValueRecord, _ = makeOpenTypeValueRecord(
+            valueRecord, pairPosContext=False)
+        if not self.can_add(glyph, otValueRecord):
+            otherLoc = self.locations[glyph]
+            raise FeatureLibError(
+                'Already defined different position for glyph "%s" at %s:%d:%d'
+                % (glyph, otherLoc[0], otherLoc[1], otherLoc[2]),
+                location)
+        if otValueRecord:
+            self.mapping[glyph] = otValueRecord
+        self.locations[glyph] = location
+
+    def can_add(self, glyph, value):
+        assert isinstance(value, otl.ValueRecord)
+        curValue = self.mapping.get(glyph)
+        return curValue is None or curValue == value
+
+    def equals(self, other):
+        return (LookupBuilder.equals(self, other) and
+                self.mapping == other.mapping)
+
+    def build(self):
+        subtables = otl.buildSinglePos(self.mapping, self.glyphMap)
+        return self.buildLookup_(subtables)
diff --git a/Lib/fontTools/feaLib/error.py b/Lib/fontTools/feaLib/error.py
index a2c5f9d..8281f95 100644
--- a/Lib/fontTools/feaLib/error.py
+++ b/Lib/fontTools/feaLib/error.py
@@ -1,3 +1,7 @@
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
+
+
 class FeatureLibError(Exception):
     def __init__(self, message, location):
         Exception.__init__(self, message)
@@ -6,17 +10,11 @@
     def __str__(self):
         message = Exception.__str__(self)
         if self.location:
-            return f"{self.location}: {message}"
+            path, line, column = self.location
+            return "%s:%d:%d: %s" % (path, line, column, message)
         else:
             return message
 
 
 class IncludedFeaNotFound(FeatureLibError):
-    def __str__(self):
-        assert self.location is not None
-
-        message = (
-            "The following feature file should be included but cannot be found: "
-            f"{Exception.__str__(self)}"
-        )
-        return f"{self.location}: {message}"
+    pass
diff --git a/Lib/fontTools/feaLib/lexer.py b/Lib/fontTools/feaLib/lexer.py
index 140fbd8..095cb66 100644
--- a/Lib/fontTools/feaLib/lexer.py
+++ b/Lib/fontTools/feaLib/lexer.py
@@ -1,14 +1,13 @@
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.feaLib.error import FeatureLibError, IncludedFeaNotFound
-from fontTools.feaLib.location import FeatureLibLocation
 import re
 import os
 
 
 class Lexer(object):
     NUMBER = "NUMBER"
-    HEXADECIMAL = "HEXADECIMAL"
-    OCTAL = "OCTAL"
-    NUMBERS = (NUMBER, HEXADECIMAL, OCTAL)
     FLOAT = "FLOAT"
     STRING = "STRING"
     NAME = "NAME"
@@ -57,7 +56,7 @@
 
     def location_(self):
         column = self.pos_ - self.line_start_ + 1
-        return FeatureLibLocation(self.filename_ or "<features>", self.line_, column)
+        return (self.filename_ or "<features>", self.line_, column)
 
     def next_(self):
         self.scan_over_(Lexer.CHAR_WHITESPACE_)
@@ -76,75 +75,72 @@
             self.line_start_ = self.pos_
             return (Lexer.NEWLINE, None, location)
         if cur_char == "\r":
-            self.pos_ += 2 if next_char == "\n" else 1
+            self.pos_ += (2 if next_char == "\n" else 1)
             self.line_ += 1
             self.line_start_ = self.pos_
             return (Lexer.NEWLINE, None, location)
         if cur_char == "#":
             self.scan_until_(Lexer.CHAR_NEWLINE_)
-            return (Lexer.COMMENT, text[start : self.pos_], location)
+            return (Lexer.COMMENT, text[start:self.pos_], location)
 
         if self.mode_ is Lexer.MODE_FILENAME_:
             if cur_char != "(":
-                raise FeatureLibError("Expected '(' before file name", location)
+                raise FeatureLibError("Expected '(' before file name",
+                                      location)
             self.scan_until_(")")
             cur_char = text[self.pos_] if self.pos_ < limit else None
             if cur_char != ")":
-                raise FeatureLibError("Expected ')' after file name", location)
+                raise FeatureLibError("Expected ')' after file name",
+                                      location)
             self.pos_ += 1
             self.mode_ = Lexer.MODE_NORMAL_
-            return (Lexer.FILENAME, text[start + 1 : self.pos_ - 1], location)
+            return (Lexer.FILENAME, text[start + 1:self.pos_ - 1], location)
 
         if cur_char == "\\" and next_char in Lexer.CHAR_DIGIT_:
             self.pos_ += 1
             self.scan_over_(Lexer.CHAR_DIGIT_)
-            return (Lexer.CID, int(text[start + 1 : self.pos_], 10), location)
+            return (Lexer.CID, int(text[start + 1:self.pos_], 10), location)
         if cur_char == "@":
             self.pos_ += 1
             self.scan_over_(Lexer.CHAR_NAME_CONTINUATION_)
-            glyphclass = text[start + 1 : self.pos_]
+            glyphclass = text[start + 1:self.pos_]
             if len(glyphclass) < 1:
                 raise FeatureLibError("Expected glyph class name", location)
             if len(glyphclass) > 63:
                 raise FeatureLibError(
-                    "Glyph class names must not be longer than 63 characters", location
-                )
+                    "Glyph class names must not be longer than 63 characters",
+                    location)
             if not Lexer.RE_GLYPHCLASS.match(glyphclass):
                 raise FeatureLibError(
                     "Glyph class names must consist of letters, digits, "
-                    "underscore, period or hyphen",
-                    location,
-                )
+                    "underscore, period or hyphen", location)
             return (Lexer.GLYPHCLASS, glyphclass, location)
         if cur_char in Lexer.CHAR_NAME_START_:
             self.pos_ += 1
             self.scan_over_(Lexer.CHAR_NAME_CONTINUATION_)
-            token = text[start : self.pos_]
+            token = text[start:self.pos_]
             if token == "include":
                 self.mode_ = Lexer.MODE_FILENAME_
             return (Lexer.NAME, token, location)
         if cur_char == "0" and next_char in "xX":
             self.pos_ += 2
             self.scan_over_(Lexer.CHAR_HEXDIGIT_)
-            return (Lexer.HEXADECIMAL, int(text[start : self.pos_], 16), location)
-        if cur_char == "0" and next_char in Lexer.CHAR_DIGIT_:
-            self.scan_over_(Lexer.CHAR_DIGIT_)
-            return (Lexer.OCTAL, int(text[start : self.pos_], 8), location)
+            return (Lexer.NUMBER, int(text[start:self.pos_], 16), location)
         if cur_char in Lexer.CHAR_DIGIT_:
             self.scan_over_(Lexer.CHAR_DIGIT_)
             if self.pos_ >= limit or text[self.pos_] != ".":
-                return (Lexer.NUMBER, int(text[start : self.pos_], 10), location)
+                return (Lexer.NUMBER, int(text[start:self.pos_], 10), location)
             self.scan_over_(".")
             self.scan_over_(Lexer.CHAR_DIGIT_)
-            return (Lexer.FLOAT, float(text[start : self.pos_]), location)
+            return (Lexer.FLOAT, float(text[start:self.pos_]), location)
         if cur_char == "-" and next_char in Lexer.CHAR_DIGIT_:
             self.pos_ += 1
             self.scan_over_(Lexer.CHAR_DIGIT_)
             if self.pos_ >= limit or text[self.pos_] != ".":
-                return (Lexer.NUMBER, int(text[start : self.pos_], 10), location)
+                return (Lexer.NUMBER, int(text[start:self.pos_], 10), location)
             self.scan_over_(".")
             self.scan_over_(Lexer.CHAR_DIGIT_)
-            return (Lexer.FLOAT, float(text[start : self.pos_]), location)
+            return (Lexer.FLOAT, float(text[start:self.pos_]), location)
         if cur_char in Lexer.CHAR_SYMBOL_:
             self.pos_ += 1
             return (Lexer.SYMBOL, cur_char, location)
@@ -154,11 +150,13 @@
             if self.pos_ < self.text_length_ and self.text_[self.pos_] == '"':
                 self.pos_ += 1
                 # strip newlines embedded within a string
-                string = re.sub("[\r\n]", "", text[start + 1 : self.pos_ - 1])
+                string = re.sub("[\r\n]", "", text[start + 1:self.pos_ - 1])
                 return (Lexer.STRING, string, location)
             else:
-                raise FeatureLibError("Expected '\"' to terminate string", location)
-        raise FeatureLibError("Unexpected character: %r" % cur_char, location)
+                raise FeatureLibError("Expected '\"' to terminate string",
+                                      location)
+        raise FeatureLibError("Unexpected character: %r" % cur_char,
+                              location)
 
     def scan_over_(self, valid):
         p = self.pos_
@@ -177,44 +175,20 @@
         tag = tag.strip()
         self.scan_until_(Lexer.CHAR_NEWLINE_)
         self.scan_over_(Lexer.CHAR_NEWLINE_)
-        regexp = r"}\s*" + tag + r"\s*;"
-        split = re.split(regexp, self.text_[self.pos_ :], maxsplit=1)
+        regexp = r'}\s*' + tag + r'\s*;'
+        split = re.split(regexp, self.text_[self.pos_:], maxsplit=1)
         if len(split) != 2:
             raise FeatureLibError(
-                "Expected '} %s;' to terminate anonymous block" % tag, location
-            )
+                "Expected '} %s;' to terminate anonymous block" % tag,
+                location)
         self.pos_ += len(split[0])
         return (Lexer.ANONYMOUS_BLOCK, split[0], location)
 
 
 class IncludingLexer(object):
-    """A Lexer that follows include statements.
-
-    The OpenType feature file specification states that due to
-    historical reasons, relative imports should be resolved in this 
-    order:
-
-    1. If the source font is UFO format, then relative to the UFO's
-       font directory
-    2. relative to the top-level include file
-    3. relative to the parent include file
-
-    We only support 1 (via includeDir) and 2.
-    """
-
-    def __init__(self, featurefile, *, includeDir=None):
-        """Initializes an IncludingLexer.
-
-        Behavior:
-            If includeDir is passed, it will be used to determine the top-level
-            include directory to use for all encountered include statements. If it is
-            not passed, ``os.path.dirname(featurefile)`` will be considered the
-            include directory.
-        """
-
+    def __init__(self, featurefile):
         self.lexers_ = [self.make_lexer_(featurefile)]
         self.featurefilepath = self.lexers_[0].filename_
-        self.includeDir = includeDir
 
     def __iter__(self):
         return self
@@ -234,15 +208,13 @@
                 fname_type, fname_token, fname_location = lexer.next()
                 if fname_type is not Lexer.FILENAME:
                     raise FeatureLibError("Expected file name", fname_location)
-                # semi_type, semi_token, semi_location = lexer.next()
-                # if semi_type is not Lexer.SYMBOL or semi_token != ";":
+                #semi_type, semi_token, semi_location = lexer.next()
+                #if semi_type is not Lexer.SYMBOL or semi_token != ";":
                 #    raise FeatureLibError("Expected ';'", semi_location)
                 if os.path.isabs(fname_token):
                     path = fname_token
                 else:
-                    if self.includeDir is not None:
-                        curpath = self.includeDir
-                    elif self.featurefilepath is not None:
+                    if self.featurefilepath is not None:
                         curpath = os.path.dirname(self.featurefilepath)
                     else:
                         # if the IncludingLexer was initialized from an in-memory
@@ -252,11 +224,16 @@
                         curpath = os.getcwd()
                     path = os.path.join(curpath, fname_token)
                 if len(self.lexers_) >= 5:
-                    raise FeatureLibError("Too many recursive includes", fname_location)
+                    raise FeatureLibError("Too many recursive includes",
+                                          fname_location)
                 try:
                     self.lexers_.append(self.make_lexer_(path))
-                except FileNotFoundError as err:
-                    raise IncludedFeaNotFound(fname_token, fname_location) from err
+                except IOError as err:
+                    # FileNotFoundError does not exist on Python < 3.3
+                    import errno
+                    if err.errno == errno.ENOENT:
+                        raise IncludedFeaNotFound(fname_token, fname_location)
+                    raise  # pragma: no cover
             else:
                 return (token_type, token, location)
         raise StopIteration()
@@ -280,6 +257,5 @@
 
 class NonIncludingLexer(IncludingLexer):
     """Lexer that does not follow `include` statements, emits them as-is."""
-
     def __next__(self):  # Python 3
         return next(self.lexers_[0])
diff --git a/Lib/fontTools/feaLib/location.py b/Lib/fontTools/feaLib/location.py
deleted file mode 100644
index 50f761d..0000000
--- a/Lib/fontTools/feaLib/location.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from typing import NamedTuple
-
-
-class FeatureLibLocation(NamedTuple):
-    """A location in a feature file"""
-
-    file: str
-    line: int
-    column: int
-
-    def __str__(self):
-        return f"{self.file}:{self.line}:{self.column}"
diff --git a/Lib/fontTools/feaLib/lookupDebugInfo.py b/Lib/fontTools/feaLib/lookupDebugInfo.py
deleted file mode 100644
index 876cadf..0000000
--- a/Lib/fontTools/feaLib/lookupDebugInfo.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from typing import NamedTuple
-
-LOOKUP_DEBUG_INFO_KEY = "com.github.fonttools.feaLib"
-LOOKUP_DEBUG_ENV_VAR  = "FONTTOOLS_LOOKUP_DEBUGGING"
-
-class LookupDebugInfo(NamedTuple):
-    """Information about where a lookup came from, to be embedded in a font"""
-
-    location: str
-    name: str
-    feature: list
diff --git a/Lib/fontTools/feaLib/parser.py b/Lib/fontTools/feaLib/parser.py
index 804cba9..9edfc46 100644
--- a/Lib/fontTools/feaLib/parser.py
+++ b/Lib/fontTools/feaLib/parser.py
@@ -1,7 +1,9 @@
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
 from fontTools.feaLib.error import FeatureLibError
 from fontTools.feaLib.lexer import Lexer, IncludingLexer, NonIncludingLexer
 from fontTools.misc.encodingTools import getEncoding
-from fontTools.misc.py23 import bytechr, tobytes, tostr
+from fontTools.misc.py23 import *
 import fontTools.feaLib.ast as ast
 import logging
 import os
@@ -12,53 +14,24 @@
 
 
 class Parser(object):
-    """Initializes a Parser object.
-
-    Example:
-
-        .. code:: python
-
-            from fontTools.feaLib.parser import Parser
-            parser = Parser(file, font.getReverseGlyphMap())
-            parsetree = parser.parse()
-
-    Note: the ``glyphNames`` iterable serves a double role to help distinguish
-    glyph names from ranges in the presence of hyphens and to ensure that glyph
-    names referenced in a feature file are actually part of a font's glyph set.
-    If the iterable is left empty, no glyph name in glyph set checking takes
-    place, and all glyph tokens containing hyphens are treated as literal glyph
-    names, not as ranges. (Adding a space around the hyphen can, in any case,
-    help to disambiguate ranges from glyph names containing hyphens.)
-
-    By default, the parser will follow ``include()`` statements in the feature
-    file. To turn this off, pass ``followIncludes=False``. Pass a directory string as
-    ``includeDir`` to explicitly declare a directory to search included feature files
-    in.
-    """
-
     extensions = {}
     ast = ast
-    SS_FEATURE_TAGS = {"ss%02d" % i for i in range(1, 20 + 1)}
-    CV_FEATURE_TAGS = {"cv%02d" % i for i in range(1, 99 + 1)}
+    SS_FEATURE_TAGS = {"ss%02d" % i for i in range(1, 20+1)}
+    CV_FEATURE_TAGS = {"cv%02d" % i for i in range(1, 99+1)}
 
-    def __init__(
-        self, featurefile, glyphNames=(), followIncludes=True, includeDir=None, **kwargs
-    ):
-
+    def __init__(self, featurefile, glyphNames=(), followIncludes=True,
+                 **kwargs):
         if "glyphMap" in kwargs:
             from fontTools.misc.loggingTools import deprecateArgument
-
             deprecateArgument("glyphMap", "use 'glyphNames' (iterable) instead")
             if glyphNames:
-                raise TypeError(
-                    "'glyphNames' and (deprecated) 'glyphMap' are " "mutually exclusive"
-                )
+                raise TypeError("'glyphNames' and (deprecated) 'glyphMap' are "
+                                "mutually exclusive")
             glyphNames = kwargs.pop("glyphMap")
         if kwargs:
-            raise TypeError(
-                "unsupported keyword argument%s: %s"
-                % ("" if len(kwargs) == 1 else "s", ", ".join(repr(k) for k in kwargs))
-            )
+            raise TypeError("unsupported keyword argument%s: %s"
+                            % ("" if len(kwargs) == 1 else "s",
+                               ", ".join(repr(k) for k in kwargs)))
 
         self.glyphNames_ = set(glyphNames)
         self.doc_ = self.ast.FeatureFile()
@@ -66,25 +39,24 @@
         self.glyphclasses_ = SymbolTable()
         self.lookups_ = SymbolTable()
         self.valuerecords_ = SymbolTable()
-        self.symbol_tables_ = {self.anchors_, self.valuerecords_}
+        self.symbol_tables_ = {
+            self.anchors_, self.valuerecords_
+        }
         self.next_token_type_, self.next_token_ = (None, None)
         self.cur_comments_ = []
         self.next_token_location_ = None
         lexerClass = IncludingLexer if followIncludes else NonIncludingLexer
-        self.lexer_ = lexerClass(featurefile, includeDir=includeDir)
+        self.lexer_ = lexerClass(featurefile)
         self.advance_lexer_(comments=True)
 
     def parse(self):
-        """Parse the file, and return a :class:`fontTools.feaLib.ast.FeatureFile`
-        object representing the root of the abstract syntax tree containing the
-        parsed contents of the file."""
         statements = self.doc_.statements
         while self.next_token_type_ is not None or self.cur_comments_:
             self.advance_lexer_(comments=True)
             if self.cur_token_type_ is Lexer.COMMENT:
                 statements.append(
-                    self.ast.Comment(self.cur_token_, location=self.cur_token_location_)
-                )
+                    self.ast.Comment(self.cur_token_,
+                                     location=self.cur_token_location_))
             elif self.is_cur_keyword_("include"):
                 statements.append(self.parse_include_())
             elif self.cur_token_type_ is Lexer.GLYPHCLASS:
@@ -104,80 +76,65 @@
             elif self.is_cur_keyword_("table"):
                 statements.append(self.parse_table_())
             elif self.is_cur_keyword_("valueRecordDef"):
-                statements.append(self.parse_valuerecord_definition_(vertical=False))
-            elif (
-                self.cur_token_type_ is Lexer.NAME
-                and self.cur_token_ in self.extensions
-            ):
+                statements.append(
+                    self.parse_valuerecord_definition_(vertical=False))
+            elif self.cur_token_type_ is Lexer.NAME and self.cur_token_ in self.extensions:
                 statements.append(self.extensions[self.cur_token_](self))
             elif self.cur_token_type_ is Lexer.SYMBOL and self.cur_token_ == ";":
                 continue
             else:
                 raise FeatureLibError(
                     "Expected feature, languagesystem, lookup, markClass, "
-                    'table, or glyph class definition, got {} "{}"'.format(
-                        self.cur_token_type_, self.cur_token_
-                    ),
-                    self.cur_token_location_,
-                )
+                    "table, or glyph class definition, got {} \"{}\"".format(self.cur_token_type_, self.cur_token_),
+                    self.cur_token_location_)
         return self.doc_
 
     def parse_anchor_(self):
-        # Parses an anchor in any of the four formats given in the feature
-        # file specification (2.e.vii).
         self.expect_symbol_("<")
         self.expect_keyword_("anchor")
         location = self.cur_token_location_
 
-        if self.next_token_ == "NULL":  # Format D
+        if self.next_token_ == "NULL":
             self.expect_keyword_("NULL")
             self.expect_symbol_(">")
             return None
 
-        if self.next_token_type_ == Lexer.NAME:  # Format E
+        if self.next_token_type_ == Lexer.NAME:
             name = self.expect_name_()
             anchordef = self.anchors_.resolve(name)
             if anchordef is None:
                 raise FeatureLibError(
-                    'Unknown anchor "%s"' % name, self.cur_token_location_
-                )
+                    'Unknown anchor "%s"' % name,
+                    self.cur_token_location_)
             self.expect_symbol_(">")
-            return self.ast.Anchor(
-                anchordef.x,
-                anchordef.y,
-                name=name,
-                contourpoint=anchordef.contourpoint,
-                xDeviceTable=None,
-                yDeviceTable=None,
-                location=location,
-            )
+            return self.ast.Anchor(anchordef.x, anchordef.y,
+                                   name=name,
+                                   contourpoint=anchordef.contourpoint,
+                                   xDeviceTable=None, yDeviceTable=None,
+                                   location=location)
 
         x, y = self.expect_number_(), self.expect_number_()
 
         contourpoint = None
-        if self.next_token_ == "contourpoint":  # Format B
+        if self.next_token_ == "contourpoint":
             self.expect_keyword_("contourpoint")
             contourpoint = self.expect_number_()
 
-        if self.next_token_ == "<":  # Format C
+        if self.next_token_ == "<":
             xDeviceTable = self.parse_device_()
             yDeviceTable = self.parse_device_()
         else:
             xDeviceTable, yDeviceTable = None, None
 
         self.expect_symbol_(">")
-        return self.ast.Anchor(
-            x,
-            y,
-            name=None,
-            contourpoint=contourpoint,
-            xDeviceTable=xDeviceTable,
-            yDeviceTable=yDeviceTable,
-            location=location,
-        )
+        return self.ast.Anchor(x, y, name=None,
+                               contourpoint=contourpoint,
+                               xDeviceTable=xDeviceTable,
+                               yDeviceTable=yDeviceTable,
+                               location=location)
 
     def parse_anchor_marks_(self):
-        # Parses a sequence of ``[<anchor> mark @MARKCLASS]*.``
+        """Parses a sequence of [<anchor> mark @MARKCLASS]*."""
         anchorMarks = []  # [(self.ast.Anchor, markClassName)*]
         while self.next_token_ == "<":
             anchor = self.parse_anchor_()
@@ -189,7 +146,6 @@
         return anchorMarks
 
     def parse_anchordef_(self):
-        # Parses a named anchor definition (`section 2.e.viii <https://adobe-type-tools.github.io/afdko/OpenTypeFeatureFileSpecification.html#2.e.vii>`_).
         assert self.is_cur_keyword_("anchorDef")
         location = self.cur_token_location_
         x, y = self.expect_number_(), self.expect_number_()
@@ -199,26 +155,24 @@
             contourpoint = self.expect_number_()
         name = self.expect_name_()
         self.expect_symbol_(";")
-        anchordef = self.ast.AnchorDefinition(
-            name, x, y, contourpoint=contourpoint, location=location
-        )
+        anchordef = self.ast.AnchorDefinition(name, x, y,
+                                              contourpoint=contourpoint,
+                                              location=location)
         self.anchors_.define(name, anchordef)
         return anchordef
 
     def parse_anonymous_(self):
-        # Parses an anonymous data block (`section 10 <https://adobe-type-tools.github.io/afdko/OpenTypeFeatureFileSpecification.html#10>`_).
         assert self.is_cur_keyword_(("anon", "anonymous"))
         tag = self.expect_tag_()
         _, content, location = self.lexer_.scan_anonymous_block(tag)
         self.advance_lexer_()
-        self.expect_symbol_("}")
+        self.expect_symbol_('}')
         end_tag = self.expect_tag_()
         assert tag == end_tag, "bad splitting in Lexer.scan_anonymous_block()"
-        self.expect_symbol_(";")
+        self.expect_symbol_(';')
         return self.ast.AnonymousBlock(tag, content, location=location)
 
     def parse_attach_(self):
-        # Parses a GDEF Attach statement (`section 9.b <https://adobe-type-tools.github.io/afdko/OpenTypeFeatureFileSpecification.html#9.b>`_)
         assert self.is_cur_keyword_("Attach")
         location = self.cur_token_location_
         glyphs = self.parse_glyphclass_(accept_glyphname=True)
@@ -226,16 +180,16 @@
         while self.next_token_ != ";":
             contourPoints.add(self.expect_number_())
         self.expect_symbol_(";")
-        return self.ast.AttachStatement(glyphs, contourPoints, location=location)
+        return self.ast.AttachStatement(glyphs, contourPoints,
+                                        location=location)
 
     def parse_enumerate_(self, vertical):
-        # Parse an enumerated pair positioning rule (`section 6.b.ii <https://adobe-type-tools.github.io/afdko/OpenTypeFeatureFileSpecification.html#6.b.ii>`_).
         assert self.cur_token_ in {"enumerate", "enum"}
         self.advance_lexer_()
         return self.parse_position_(enumerated=True, vertical=vertical)
 
     def parse_GlyphClassDef_(self):
-        # Parses 'GlyphClassDef @BASE, @LIGATURES, @MARKS, @COMPONENTS;'
+        """Parses 'GlyphClassDef @BASE, @LIGATURES, @MARKS, @COMPONENTS;'"""
         assert self.is_cur_keyword_("GlyphClassDef")
         location = self.cur_token_location_
         if self.next_token_ != ",":
@@ -258,17 +212,18 @@
         else:
             componentGlyphs = None
         self.expect_symbol_(";")
-        return self.ast.GlyphClassDefStatement(
-            baseGlyphs, markGlyphs, ligatureGlyphs, componentGlyphs, location=location
-        )
+        return self.ast.GlyphClassDefStatement(baseGlyphs, markGlyphs,
+                                               ligatureGlyphs, componentGlyphs,
+                                               location=location)
 
     def parse_glyphclass_definition_(self):
-        # Parses glyph class definitions such as '@UPPERCASE = [A-Z];'
+        """Parses glyph class definitions such as '@UPPERCASE = [A-Z];'"""
         location, name = self.cur_token_location_, self.cur_token_
         self.expect_symbol_("=")
         glyphs = self.parse_glyphclass_(accept_glyphname=False)
         self.expect_symbol_(";")
-        glyphclass = self.ast.GlyphClassDefinition(name, glyphs, location=location)
+        glyphclass = self.ast.GlyphClassDefinition(name, glyphs,
+                                                   location=location)
         self.glyphclasses_.define(name, glyphclass)
         return glyphclass
 
@@ -302,29 +257,19 @@
             return start, limit
         elif len(solutions) == 0:
             raise FeatureLibError(
-                '"%s" is not a glyph in the font, and it can not be split '
-                "into a range of known glyphs" % name,
-                location,
-            )
+                "\"%s\" is not a glyph in the font, and it can not be split "
+                "into a range of known glyphs" % name, location)
         else:
-            ranges = " or ".join(['"%s - %s"' % (s, l) for s, l in solutions])
+            ranges = " or ".join(["\"%s - %s\"" % (s, l) for s, l in solutions])
             raise FeatureLibError(
-                'Ambiguous glyph range "%s"; '
+                "Ambiguous glyph range \"%s\"; "
                 "please use %s to clarify what you mean" % (name, ranges),
-                location,
-            )
+                location)
 
-    def parse_glyphclass_(self, accept_glyphname, accept_null=False):
-        # Parses a glyph class, either named or anonymous, or (if
-        # ``bool(accept_glyphname)``) a glyph name. If ``bool(accept_null)`` then
-        # also accept the special NULL glyph.
-        if accept_glyphname and self.next_token_type_ in (Lexer.NAME, Lexer.CID):
-            if accept_null and self.next_token_ == "NULL":
-                # If you want a glyph called NULL, you should escape it.
-                self.advance_lexer_()
-                return self.ast.NullGlyph(location=self.cur_token_location_)
+    def parse_glyphclass_(self, accept_glyphname):
+        if (accept_glyphname and
+                self.next_token_type_ in (Lexer.NAME, Lexer.CID)):
             glyph = self.expect_glyph_()
-            self.check_glyph_name_in_glyph_set(glyph)
             return self.ast.GlyphName(glyph, location=self.cur_token_location_)
         if self.next_token_type_ is Lexer.GLYPHCLASS:
             self.advance_lexer_()
@@ -332,12 +277,13 @@
             if gc is None:
                 raise FeatureLibError(
                     "Unknown glyph class @%s" % self.cur_token_,
-                    self.cur_token_location_,
-                )
+                    self.cur_token_location_)
             if isinstance(gc, self.ast.MarkClass):
-                return self.ast.MarkClassName(gc, location=self.cur_token_location_)
+                return self.ast.MarkClassName(
+                    gc, location=self.cur_token_location_)
             else:
-                return self.ast.GlyphClassName(gc, location=self.cur_token_location_)
+                return self.ast.GlyphClassName(
+                    gc, location=self.cur_token_location_)
 
         self.expect_symbol_("[")
         location = self.cur_token_location_
@@ -346,31 +292,19 @@
             if self.next_token_type_ is Lexer.NAME:
                 glyph = self.expect_glyph_()
                 location = self.cur_token_location_
-                if "-" in glyph and self.glyphNames_ and glyph not in self.glyphNames_:
+                if '-' in glyph and glyph not in self.glyphNames_:
                     start, limit = self.split_glyph_range_(glyph, location)
-                    self.check_glyph_name_in_glyph_set(start, limit)
                     glyphs.add_range(
-                        start, limit, self.make_glyph_range_(location, start, limit)
-                    )
+                        start, limit,
+                        self.make_glyph_range_(location, start, limit))
                 elif self.next_token_ == "-":
                     start = glyph
                     self.expect_symbol_("-")
                     limit = self.expect_glyph_()
-                    self.check_glyph_name_in_glyph_set(start, limit)
                     glyphs.add_range(
-                        start, limit, self.make_glyph_range_(location, start, limit)
-                    )
+                        start, limit,
+                        self.make_glyph_range_(location, start, limit))
                 else:
-                    if "-" in glyph and not self.glyphNames_:
-                        log.warning(
-                            str(
-                                FeatureLibError(
-                                    f"Ambiguous glyph name that looks like a range: {glyph!r}",
-                                    location,
-                                )
-                            )
-                        )
-                    self.check_glyph_name_in_glyph_set(glyph)
                     glyphs.append(glyph)
             elif self.next_token_type_ is Lexer.CID:
                 glyph = self.expect_glyph_()
@@ -379,47 +313,48 @@
                     range_start = self.cur_token_
                     self.expect_symbol_("-")
                     range_end = self.expect_cid_()
-                    self.check_glyph_name_in_glyph_set(
-                        f"cid{range_start:05d}",
-                        f"cid{range_end:05d}",
-                    )
-                    glyphs.add_cid_range(
-                        range_start,
-                        range_end,
-                        self.make_cid_range_(range_location, range_start, range_end),
-                    )
+                    glyphs.add_cid_range(range_start, range_end,
+                                         self.make_cid_range_(range_location,
+                                                              range_start, range_end))
                 else:
-                    glyph_name = f"cid{self.cur_token_:05d}"
-                    self.check_glyph_name_in_glyph_set(glyph_name)
-                    glyphs.append(glyph_name)
+                    glyphs.append("cid%05d" % self.cur_token_)
             elif self.next_token_type_ is Lexer.GLYPHCLASS:
                 self.advance_lexer_()
                 gc = self.glyphclasses_.resolve(self.cur_token_)
                 if gc is None:
                     raise FeatureLibError(
                         "Unknown glyph class @%s" % self.cur_token_,
-                        self.cur_token_location_,
-                    )
+                        self.cur_token_location_)
                 if isinstance(gc, self.ast.MarkClass):
-                    gc = self.ast.MarkClassName(gc, location=self.cur_token_location_)
+                    gc = self.ast.MarkClassName(
+                        gc, location=self.cur_token_location_)
                 else:
-                    gc = self.ast.GlyphClassName(gc, location=self.cur_token_location_)
+                    gc = self.ast.GlyphClassName(
+                        gc, location=self.cur_token_location_)
                 glyphs.add_class(gc)
             else:
                 raise FeatureLibError(
                     "Expected glyph name, glyph range, "
-                    f"or glyph class reference, found {self.next_token_!r}",
-                    self.next_token_location_,
-                )
+                    "or glyph class reference",
+                    self.next_token_location_)
         self.expect_symbol_("]")
         return glyphs
 
+    def parse_class_name_(self):
+        name = self.expect_class_name_()
+        gc = self.glyphclasses_.resolve(name)
+        if gc is None:
+            raise FeatureLibError(
+                "Unknown glyph class @%s" % name,
+                self.cur_token_location_)
+        if isinstance(gc, self.ast.MarkClass):
+            return self.ast.MarkClassName(
+                gc, location=self.cur_token_location_)
+        else:
+            return self.ast.GlyphClassName(
+                gc, location=self.cur_token_location_)
+
     def parse_glyph_pattern_(self, vertical):
-        # Parses a glyph pattern, including lookups and context, e.g.::
-        #
-        #    a b
-        #    a b c' d e
-        #    a b c' lookup ChangeC d e
         prefix, glyphs, lookups, values, suffix = ([], [], [], [], [])
         hasMarks = False
         while self.next_token_ not in {"by", "from", ";", ","}:
@@ -436,8 +371,7 @@
                     raise FeatureLibError(
                         "Unsupported contextual target sequence: at most "
                         "one run of marked (') glyph/class names allowed",
-                        self.cur_token_location_,
-                    )
+                        self.cur_token_location_)
                 glyphs.append(gc)
             elif glyphs:
                 suffix.append(gc)
@@ -449,64 +383,48 @@
             else:
                 values.append(None)
 
-            lookuplist = None
-            while self.next_token_ == "lookup":
-                if lookuplist is None:
-                    lookuplist = []
+            lookup = None
+            if self.next_token_ == "lookup":
                 self.expect_keyword_("lookup")
                 if not marked:
                     raise FeatureLibError(
                         "Lookups can only follow marked glyphs",
-                        self.cur_token_location_,
-                    )
+                        self.cur_token_location_)
                 lookup_name = self.expect_name_()
                 lookup = self.lookups_.resolve(lookup_name)
                 if lookup is None:
                     raise FeatureLibError(
-                        'Unknown lookup "%s"' % lookup_name, self.cur_token_location_
-                    )
-                lookuplist.append(lookup)
+                        'Unknown lookup "%s"' % lookup_name,
+                        self.cur_token_location_)
             if marked:
-                lookups.append(lookuplist)
+                lookups.append(lookup)
 
         if not glyphs and not suffix:  # eg., "sub f f i by"
             assert lookups == []
             return ([], prefix, [None] * len(prefix), values, [], hasMarks)
         else:
-            assert not any(values[: len(prefix)]), values
-            format1 = values[len(prefix) :][: len(glyphs)]
-            format2 = values[(len(prefix) + len(glyphs)) :][: len(suffix)]
-            values = (
-                format2
-                if format2 and isinstance(format2[0], self.ast.ValueRecord)
-                else format1
-            )
+            assert not any(values[:len(prefix)]), values
+            format1 = values[len(prefix):][:len(glyphs)]
+            format2 = values[(len(prefix) + len(glyphs)):][:len(suffix)]
+            values = format2 if format2 and isinstance(format2[0], self.ast.ValueRecord) else format1
             return (prefix, glyphs, lookups, values, suffix, hasMarks)
 
     def parse_chain_context_(self):
         location = self.cur_token_location_
-        prefix, glyphs, lookups, values, suffix, hasMarks = self.parse_glyph_pattern_(
-            vertical=False
-        )
+        prefix, glyphs, lookups, values, suffix, hasMarks = \
+            self.parse_glyph_pattern_(vertical=False)
         chainContext = [(prefix, glyphs, suffix)]
         hasLookups = any(lookups)
         while self.next_token_ == ",":
             self.expect_symbol_(",")
-            (
-                prefix,
-                glyphs,
-                lookups,
-                values,
-                suffix,
-                hasMarks,
-            ) = self.parse_glyph_pattern_(vertical=False)
+            prefix, glyphs, lookups, values, suffix, hasMarks = \
+                self.parse_glyph_pattern_(vertical=False)
             chainContext.append((prefix, glyphs, suffix))
             hasLookups = hasLookups or any(lookups)
         self.expect_symbol_(";")
         return chainContext, hasLookups
 
     def parse_ignore_(self):
-        # Parses an ignore sub/pos rule.
         assert self.is_cur_keyword_("ignore")
         location = self.cur_token_location_
         self.advance_lexer_()
@@ -514,19 +432,21 @@
             chainContext, hasLookups = self.parse_chain_context_()
             if hasLookups:
                 raise FeatureLibError(
-                    'No lookups can be specified for "ignore sub"', location
-                )
-            return self.ast.IgnoreSubstStatement(chainContext, location=location)
+                    "No lookups can be specified for \"ignore sub\"",
+                    location)
+            return self.ast.IgnoreSubstStatement(chainContext,
+                                                 location=location)
         if self.cur_token_ in ["position", "pos"]:
             chainContext, hasLookups = self.parse_chain_context_()
             if hasLookups:
                 raise FeatureLibError(
-                    'No lookups can be specified for "ignore pos"', location
-                )
-            return self.ast.IgnorePosStatement(chainContext, location=location)
+                    "No lookups can be specified for \"ignore pos\"",
+                    location)
+            return self.ast.IgnorePosStatement(chainContext,
+                                               location=location)
         raise FeatureLibError(
-            'Expected "substitute" or "position"', self.cur_token_location_
-        )
+            "Expected \"substitute\" or \"position\"",
+            self.cur_token_location_)
 
     def parse_include_(self):
         assert self.cur_token_ == "include"
@@ -541,14 +461,14 @@
         language = self.expect_language_tag_()
         include_default, required = (True, False)
         if self.next_token_ in {"exclude_dflt", "include_dflt"}:
-            include_default = self.expect_name_() == "include_dflt"
+            include_default = (self.expect_name_() == "include_dflt")
         if self.next_token_ == "required":
             self.expect_keyword_("required")
             required = True
         self.expect_symbol_(";")
-        return self.ast.LanguageStatement(
-            language, include_default, required, location=location
-        )
+        return self.ast.LanguageStatement(language,
+                                          include_default, required,
+                                          location=location)
 
     def parse_ligatureCaretByIndex_(self):
         assert self.is_cur_keyword_("LigatureCaretByIndex")
@@ -558,7 +478,8 @@
         while self.next_token_ != ";":
             carets.append(self.expect_number_())
         self.expect_symbol_(";")
-        return self.ast.LigatureCaretByIndexStatement(glyphs, carets, location=location)
+        return self.ast.LigatureCaretByIndexStatement(glyphs, carets,
+                                                      location=location)
 
     def parse_ligatureCaretByPos_(self):
         assert self.is_cur_keyword_("LigatureCaretByPos")
@@ -568,22 +489,21 @@
         while self.next_token_ != ";":
             carets.append(self.expect_number_())
         self.expect_symbol_(";")
-        return self.ast.LigatureCaretByPosStatement(glyphs, carets, location=location)
+        return self.ast.LigatureCaretByPosStatement(glyphs, carets,
+                                                    location=location)
 
     def parse_lookup_(self, vertical):
-        # Parses a ``lookup`` - either a lookup block, or a lookup reference
-        # inside a feature.
         assert self.is_cur_keyword_("lookup")
         location, name = self.cur_token_location_, self.expect_name_()
 
         if self.next_token_ == ";":
             lookup = self.lookups_.resolve(name)
             if lookup is None:
-                raise FeatureLibError(
-                    'Unknown lookup "%s"' % name, self.cur_token_location_
-                )
+                raise FeatureLibError("Unknown lookup \"%s\"" % name,
+                                      self.cur_token_location_)
             self.expect_symbol_(";")
-            return self.ast.LookupReferenceStatement(lookup, location=location)
+            return self.ast.LookupReferenceStatement(lookup,
+                                                     location=location)
 
         use_extension = False
         if self.next_token_ == "useExtension":
@@ -596,8 +516,6 @@
         return block
 
     def parse_lookupflag_(self):
-        # Parses a ``lookupflag`` statement, either specified by number or
-        # in words.
         assert self.is_cur_keyword_("lookupflag")
         location = self.cur_token_location_
 
@@ -611,46 +529,39 @@
         value_seen = False
         value, markAttachment, markFilteringSet = 0, None, None
         flags = {
-            "RightToLeft": 1,
-            "IgnoreBaseGlyphs": 2,
-            "IgnoreLigatures": 4,
-            "IgnoreMarks": 8,
+            "RightToLeft": 1, "IgnoreBaseGlyphs": 2,
+            "IgnoreLigatures": 4, "IgnoreMarks": 8
         }
         seen = set()
         while self.next_token_ != ";":
             if self.next_token_ in seen:
                 raise FeatureLibError(
                     "%s can be specified only once" % self.next_token_,
-                    self.next_token_location_,
-                )
+                    self.next_token_location_)
             seen.add(self.next_token_)
             if self.next_token_ == "MarkAttachmentType":
                 self.expect_keyword_("MarkAttachmentType")
-                markAttachment = self.parse_glyphclass_(accept_glyphname=False)
+                markAttachment = self.parse_class_name_()
             elif self.next_token_ == "UseMarkFilteringSet":
                 self.expect_keyword_("UseMarkFilteringSet")
-                markFilteringSet = self.parse_glyphclass_(accept_glyphname=False)
+                markFilteringSet = self.parse_class_name_()
             elif self.next_token_ in flags:
                 value_seen = True
                 value = value | flags[self.expect_name_()]
             else:
                 raise FeatureLibError(
                     '"%s" is not a recognized lookupflag' % self.next_token_,
-                    self.next_token_location_,
-                )
+                    self.next_token_location_)
         self.expect_symbol_(";")
 
         if not any([value_seen, markAttachment, markFilteringSet]):
             raise FeatureLibError(
-                "lookupflag must have a value", self.next_token_location_
-            )
+                'lookupflag must have a value', self.next_token_location_)
 
-        return self.ast.LookupFlagStatement(
-            value,
-            markAttachment=markAttachment,
-            markFilteringSet=markFilteringSet,
-            location=location,
-        )
+        return self.ast.LookupFlagStatement(value,
+                                            markAttachment=markAttachment,
+                                            markFilteringSet=markFilteringSet,
+                                            location=location)
 
     def parse_markClass_(self):
         assert self.is_cur_keyword_("markClass")
@@ -664,9 +575,8 @@
             markClass = self.ast.MarkClass(name)
             self.doc_.markClasses[name] = markClass
             self.glyphclasses_.define(name, markClass)
-        mcdef = self.ast.MarkClassDefinition(
-            markClass, anchor, glyphs, location=location
-        )
+        mcdef = self.ast.MarkClassDefinition(markClass, anchor, glyphs,
+                                             location=location)
         markClass.addDefinition(mcdef)
         return mcdef
 
@@ -674,28 +584,26 @@
         assert self.cur_token_ in {"position", "pos"}
         if self.next_token_ == "cursive":  # GPOS type 3
             return self.parse_position_cursive_(enumerated, vertical)
-        elif self.next_token_ == "base":  # GPOS type 4
+        elif self.next_token_ == "base":   # GPOS type 4
             return self.parse_position_base_(enumerated, vertical)
-        elif self.next_token_ == "ligature":  # GPOS type 5
+        elif self.next_token_ == "ligature":   # GPOS type 5
             return self.parse_position_ligature_(enumerated, vertical)
-        elif self.next_token_ == "mark":  # GPOS type 6
+        elif self.next_token_ == "mark":   # GPOS type 6
             return self.parse_position_mark_(enumerated, vertical)
 
         location = self.cur_token_location_
-        prefix, glyphs, lookups, values, suffix, hasMarks = self.parse_glyph_pattern_(
-            vertical
-        )
+        prefix, glyphs, lookups, values, suffix, hasMarks = \
+            self.parse_glyph_pattern_(vertical)
         self.expect_symbol_(";")
 
         if any(lookups):
             # GPOS type 8: Chaining contextual positioning; explicit lookups
             if any(values):
                 raise FeatureLibError(
-                    'If "lookup" is present, no values must be specified', location
-                )
+                    "If \"lookup\" is present, no values must be specified",
+                    location)
             return self.ast.ChainContextPosStatement(
-                prefix, glyphs, suffix, lookups, location=location
-            )
+                prefix, glyphs, suffix, lookups, location=location)
 
         # Pair positioning, format A: "pos V 10 A -10;"
         # Pair positioning, format B: "pos V A -20;"
@@ -703,41 +611,31 @@
             if values[0] is None:  # Format B: "pos V A -20;"
                 values.reverse()
             return self.ast.PairPosStatement(
-                glyphs[0],
-                values[0],
-                glyphs[1],
-                values[1],
+                glyphs[0], values[0], glyphs[1], values[1],
                 enumerated=enumerated,
-                location=location,
-            )
+                location=location)
 
         if enumerated:
             raise FeatureLibError(
-                '"enumerate" is only allowed with pair positionings', location
-            )
-        return self.ast.SinglePosStatement(
-            list(zip(glyphs, values)),
-            prefix,
-            suffix,
-            forceChain=hasMarks,
-            location=location,
-        )
+                '"enumerate" is only allowed with pair positionings', location)
+        return self.ast.SinglePosStatement(list(zip(glyphs, values)),
+                                           prefix, suffix, forceChain=hasMarks,
+                                           location=location)
 
     def parse_position_cursive_(self, enumerated, vertical):
         location = self.cur_token_location_
         self.expect_keyword_("cursive")
         if enumerated:
             raise FeatureLibError(
-                '"enumerate" is not allowed with ' "cursive attachment positioning",
-                location,
-            )
+                '"enumerate" is not allowed with '
+                'cursive attachment positioning',
+                location)
         glyphclass = self.parse_glyphclass_(accept_glyphname=True)
         entryAnchor = self.parse_anchor_()
         exitAnchor = self.parse_anchor_()
         self.expect_symbol_(";")
         return self.ast.CursivePosStatement(
-            glyphclass, entryAnchor, exitAnchor, location=location
-        )
+            glyphclass, entryAnchor, exitAnchor, location=location)
 
     def parse_position_base_(self, enumerated, vertical):
         location = self.cur_token_location_
@@ -745,9 +643,8 @@
         if enumerated:
             raise FeatureLibError(
                 '"enumerate" is not allowed with '
-                "mark-to-base attachment positioning",
-                location,
-            )
+                'mark-to-base attachment positioning',
+                location)
         base = self.parse_glyphclass_(accept_glyphname=True)
         marks = self.parse_anchor_marks_()
         self.expect_symbol_(";")
@@ -759,9 +656,8 @@
         if enumerated:
             raise FeatureLibError(
                 '"enumerate" is not allowed with '
-                "mark-to-ligature attachment positioning",
-                location,
-            )
+                'mark-to-ligature attachment positioning',
+                location)
         ligatures = self.parse_glyphclass_(accept_glyphname=True)
         marks = [self.parse_anchor_marks_()]
         while self.next_token_ == "ligComponent":
@@ -776,13 +672,13 @@
         if enumerated:
             raise FeatureLibError(
                 '"enumerate" is not allowed with '
-                "mark-to-mark attachment positioning",
-                location,
-            )
+                'mark-to-mark attachment positioning',
+                location)
         baseMarks = self.parse_glyphclass_(accept_glyphname=True)
         marks = self.parse_anchor_marks_()
         self.expect_symbol_(";")
-        return self.ast.MarkMarkPosStatement(baseMarks, marks, location=location)
+        return self.ast.MarkMarkPosStatement(baseMarks, marks,
+                                             location=location)
 
     def parse_script_(self):
         assert self.is_cur_keyword_("script")
@@ -794,23 +690,16 @@
         assert self.cur_token_ in {"substitute", "sub", "reversesub", "rsub"}
         location = self.cur_token_location_
         reverse = self.cur_token_ in {"reversesub", "rsub"}
-        (
-            old_prefix,
-            old,
-            lookups,
-            values,
-            old_suffix,
-            hasMarks,
-        ) = self.parse_glyph_pattern_(vertical=False)
+        old_prefix, old, lookups, values, old_suffix, hasMarks = \
+            self.parse_glyph_pattern_(vertical=False)
         if any(values):
             raise FeatureLibError(
-                "Substitution statements cannot contain values", location
-            )
+                "Substitution statements cannot contain values", location)
         new = []
         if self.next_token_ == "by":
             keyword = self.expect_keyword_("by")
             while self.next_token_ != ";":
-                gc = self.parse_glyphclass_(accept_glyphname=True, accept_null=True)
+                gc = self.parse_glyphclass_(accept_glyphname=True)
                 new.append(gc)
         elif self.next_token_ == "from":
             keyword = self.expect_keyword_("from")
@@ -818,41 +707,37 @@
         else:
             keyword = None
         self.expect_symbol_(";")
-        if len(new) == 0 and not any(lookups):
+        if len(new) is 0 and not any(lookups):
             raise FeatureLibError(
                 'Expected "by", "from" or explicit lookup references',
-                self.cur_token_location_,
-            )
+                self.cur_token_location_)
 
         # GSUB lookup type 3: Alternate substitution.
         # Format: "substitute a from [a.1 a.2 a.3];"
         if keyword == "from":
             if reverse:
                 raise FeatureLibError(
-                    'Reverse chaining substitutions do not support "from"', location
-                )
+                    'Reverse chaining substitutions do not support "from"',
+                    location)
             if len(old) != 1 or len(old[0].glyphSet()) != 1:
-                raise FeatureLibError('Expected a single glyph before "from"', location)
+                raise FeatureLibError(
+                    'Expected a single glyph before "from"',
+                    location)
             if len(new) != 1:
                 raise FeatureLibError(
-                    'Expected a single glyphclass after "from"', location
-                )
+                    'Expected a single glyphclass after "from"',
+                    location)
             return self.ast.AlternateSubstStatement(
-                old_prefix, old[0], old_suffix, new[0], location=location
-            )
+                old_prefix, old[0], old_suffix, new[0], location=location)
 
         num_lookups = len([l for l in lookups if l is not None])
 
-        is_deletion = False
-        if len(new) == 1 and len(new[0].glyphSet()) == 0:
-            new = []  # Deletion
-            is_deletion = True
-
         # GSUB lookup type 1: Single substitution.
         # Format A: "substitute a by a.sc;"
         # Format B: "substitute [one.fitted one.oldstyle] by one;"
         # Format C: "substitute [a-d] by [A.sc-D.sc];"
-        if not reverse and len(old) == 1 and len(new) == 1 and num_lookups == 0:
+        if (not reverse and len(old) == 1 and len(new) == 1 and
+                num_lookups == 0):
             glyphs = list(old[0].glyphSet())
             replacements = list(new[0].glyphSet())
             if len(replacements) == 1:
@@ -860,52 +745,36 @@
             if len(glyphs) != len(replacements):
                 raise FeatureLibError(
                     'Expected a glyph class with %d elements after "by", '
-                    "but found a glyph class with %d elements"
-                    % (len(glyphs), len(replacements)),
-                    location,
-                )
+                    'but found a glyph class with %d elements' %
+                    (len(glyphs), len(replacements)), location)
             return self.ast.SingleSubstStatement(
-                old, new, old_prefix, old_suffix, forceChain=hasMarks, location=location
+                old, new,
+                old_prefix, old_suffix,
+                forceChain=hasMarks,
+                location=location
             )
 
         # GSUB lookup type 2: Multiple substitution.
         # Format: "substitute f_f_i by f f i;"
-        if (
-            not reverse
-            and len(old) == 1
-            and len(old[0].glyphSet()) == 1
-            and (
-                (len(new) > 1 and max([len(n.glyphSet()) for n in new]) == 1)
-                or len(new) == 0
-            )
-            and num_lookups == 0
-        ):
+        if (not reverse and
+                len(old) == 1 and len(old[0].glyphSet()) == 1 and
+                len(new) > 1 and max([len(n.glyphSet()) for n in new]) == 1 and
+                num_lookups == 0):
             return self.ast.MultipleSubstStatement(
-                old_prefix,
-                tuple(old[0].glyphSet())[0],
-                old_suffix,
+                old_prefix, tuple(old[0].glyphSet())[0], old_suffix,
                 tuple([list(n.glyphSet())[0] for n in new]),
-                forceChain=hasMarks,
-                location=location,
-            )
+                forceChain=hasMarks, location=location)
 
         # GSUB lookup type 4: Ligature substitution.
         # Format: "substitute f f i by f_f_i;"
-        if (
-            not reverse
-            and len(old) > 1
-            and len(new) == 1
-            and len(new[0].glyphSet()) == 1
-            and num_lookups == 0
-        ):
+        if (not reverse and
+                len(old) > 1 and len(new) == 1 and
+                len(new[0].glyphSet()) == 1 and
+                num_lookups == 0):
             return self.ast.LigatureSubstStatement(
-                old_prefix,
-                old,
-                old_suffix,
-                list(new[0].glyphSet())[0],
-                forceChain=hasMarks,
-                location=location,
-            )
+                old_prefix, old, old_suffix,
+                list(new[0].glyphSet())[0], forceChain=hasMarks,
+                location=location)
 
         # GSUB lookup type 8: Reverse chaining substitution.
         if reverse:
@@ -913,19 +782,16 @@
                 raise FeatureLibError(
                     "In reverse chaining single substitutions, "
                     "only a single glyph or glyph class can be replaced",
-                    location,
-                )
+                    location)
             if len(new) != 1:
                 raise FeatureLibError(
-                    "In reverse chaining single substitutions, "
+                    'In reverse chaining single substitutions, '
                     'the replacement (after "by") must be a single glyph '
-                    "or glyph class",
-                    location,
-                )
+                    'or glyph class', location)
             if num_lookups != 0:
                 raise FeatureLibError(
-                    "Reverse chaining substitutions cannot call named lookups", location
-                )
+                    "Reverse chaining substitutions cannot call named lookups",
+                    location)
             glyphs = sorted(list(old[0].glyphSet()))
             replacements = sorted(list(new[0].glyphSet()))
             if len(replacements) == 1:
@@ -933,29 +799,21 @@
             if len(glyphs) != len(replacements):
                 raise FeatureLibError(
                     'Expected a glyph class with %d elements after "by", '
-                    "but found a glyph class with %d elements"
-                    % (len(glyphs), len(replacements)),
-                    location,
-                )
+                    'but found a glyph class with %d elements' %
+                    (len(glyphs), len(replacements)), location)
             return self.ast.ReverseChainSingleSubstStatement(
-                old_prefix, old_suffix, old, new, location=location
-            )
+                old_prefix, old_suffix, old, new, location=location)
 
         if len(old) > 1 and len(new) > 1:
             raise FeatureLibError(
-                "Direct substitution of multiple glyphs by multiple glyphs "
-                "is not supported",
-                location,
-            )
-
-        # If there are remaining glyphs to parse, this is an invalid GSUB statement
-        if len(new) != 0 or is_deletion:
-            raise FeatureLibError("Invalid substitution statement", location)
+                'Direct substitution of multiple glyphs by multiple glyphs '
+                'is not supported',
+                location)
 
         # GSUB lookup type 6: Chaining contextual substitution.
+        assert len(new) == 0, new
         rule = self.ast.ChainContextSubstStatement(
-            old_prefix, old, old_suffix, lookups, location=location
-        )
+            old_prefix, old, old_suffix, lookups, location=location)
         return rule
 
     def parse_subtable_(self):
@@ -965,30 +823,29 @@
         return self.ast.SubtableStatement(location=location)
 
     def parse_size_parameters_(self):
-        # Parses a ``parameters`` statement used in ``size`` features. See
-        # `section 8.b <https://adobe-type-tools.github.io/afdko/OpenTypeFeatureFileSpecification.html#8.b>`_.
         assert self.is_cur_keyword_("parameters")
         location = self.cur_token_location_
         DesignSize = self.expect_decipoint_()
         SubfamilyID = self.expect_number_()
-        RangeStart = 0.
-        RangeEnd = 0.
-        if self.next_token_type_ in (Lexer.NUMBER, Lexer.FLOAT) or SubfamilyID != 0:
+        RangeStart = 0
+        RangeEnd = 0
+        if self.next_token_type_ in (Lexer.NUMBER, Lexer.FLOAT) or \
+                SubfamilyID != 0:
             RangeStart = self.expect_decipoint_()
             RangeEnd = self.expect_decipoint_()
 
         self.expect_symbol_(";")
-        return self.ast.SizeParameters(
-            DesignSize, SubfamilyID, RangeStart, RangeEnd, location=location
-        )
+        return self.ast.SizeParameters(DesignSize, SubfamilyID,
+                                       RangeStart, RangeEnd,
+                                       location=location)
 
     def parse_size_menuname_(self):
         assert self.is_cur_keyword_("sizemenuname")
         location = self.cur_token_location_
         platformID, platEncID, langID, string = self.parse_name_()
-        return self.ast.FeatureNameStatement(
-            "size", platformID, platEncID, langID, string, location=location
-        )
+        return self.ast.FeatureNameStatement("size", platformID,
+                                             platEncID, langID, string,
+                                             location=location)
 
     def parse_table_(self):
         assert self.is_cur_keyword_("table")
@@ -1003,20 +860,17 @@
             "name": self.parse_table_name_,
             "BASE": self.parse_table_BASE_,
             "OS/2": self.parse_table_OS_2_,
-            "STAT": self.parse_table_STAT_,
         }.get(name)
         if handler:
             handler(table)
         else:
-            raise FeatureLibError(
-                '"table %s" is not supported' % name.strip(), location
-            )
+            raise FeatureLibError('"table %s" is not supported' % name.strip(),
+                                  location)
         self.expect_symbol_("}")
         end_tag = self.expect_tag_()
         if end_tag != name:
-            raise FeatureLibError(
-                'Expected "%s"' % name.strip(), self.cur_token_location_
-            )
+            raise FeatureLibError('Expected "%s"' % name.strip(),
+                                  self.cur_token_location_)
         self.expect_symbol_(";")
         return table
 
@@ -1025,9 +879,8 @@
         while self.next_token_ != "}" or self.cur_comments_:
             self.advance_lexer_(comments=True)
             if self.cur_token_type_ is Lexer.COMMENT:
-                statements.append(
-                    self.ast.Comment(self.cur_token_, location=self.cur_token_location_)
-                )
+                statements.append(self.ast.Comment(
+                    self.cur_token_, location=self.cur_token_location_))
             elif self.is_cur_keyword_("Attach"):
                 statements.append(self.parse_attach_())
             elif self.is_cur_keyword_("GlyphClassDef"):
@@ -1040,24 +893,24 @@
                 continue
             else:
                 raise FeatureLibError(
-                    "Expected Attach, LigatureCaretByIndex, " "or LigatureCaretByPos",
-                    self.cur_token_location_,
-                )
+                    "Expected Attach, LigatureCaretByIndex, "
+                    "or LigatureCaretByPos",
+                    self.cur_token_location_)
 
     def parse_table_head_(self, table):
         statements = table.statements
         while self.next_token_ != "}" or self.cur_comments_:
             self.advance_lexer_(comments=True)
             if self.cur_token_type_ is Lexer.COMMENT:
-                statements.append(
-                    self.ast.Comment(self.cur_token_, location=self.cur_token_location_)
-                )
+                statements.append(self.ast.Comment(
+                    self.cur_token_, location=self.cur_token_location_))
             elif self.is_cur_keyword_("FontRevision"):
                 statements.append(self.parse_FontRevision_())
             elif self.cur_token_ == ";":
                 continue
             else:
-                raise FeatureLibError("Expected FontRevision", self.cur_token_location_)
+                raise FeatureLibError("Expected FontRevision",
+                                      self.cur_token_location_)
 
     def parse_table_hhea_(self, table):
         statements = table.statements
@@ -1065,26 +918,22 @@
         while self.next_token_ != "}" or self.cur_comments_:
             self.advance_lexer_(comments=True)
             if self.cur_token_type_ is Lexer.COMMENT:
-                statements.append(
-                    self.ast.Comment(self.cur_token_, location=self.cur_token_location_)
-                )
+                statements.append(self.ast.Comment(
+                    self.cur_token_, location=self.cur_token_location_))
             elif self.cur_token_type_ is Lexer.NAME and self.cur_token_ in fields:
                 key = self.cur_token_.lower()
                 value = self.expect_number_()
                 statements.append(
-                    self.ast.HheaField(key, value, location=self.cur_token_location_)
-                )
+                    self.ast.HheaField(key, value,
+                                       location=self.cur_token_location_))
                 if self.next_token_ != ";":
-                    raise FeatureLibError(
-                        "Incomplete statement", self.next_token_location_
-                    )
+                    raise FeatureLibError("Incomplete statement", self.next_token_location_)
             elif self.cur_token_ == ";":
                 continue
             else:
-                raise FeatureLibError(
-                    "Expected CaretOffset, Ascender, " "Descender or LineGap",
-                    self.cur_token_location_,
-                )
+                raise FeatureLibError("Expected CaretOffset, Ascender, "
+                                      "Descender or LineGap",
+                                      self.cur_token_location_)
 
     def parse_table_vhea_(self, table):
         statements = table.statements
@@ -1092,36 +941,30 @@
         while self.next_token_ != "}" or self.cur_comments_:
             self.advance_lexer_(comments=True)
             if self.cur_token_type_ is Lexer.COMMENT:
-                statements.append(
-                    self.ast.Comment(self.cur_token_, location=self.cur_token_location_)
-                )
+                statements.append(self.ast.Comment(
+                    self.cur_token_, location=self.cur_token_location_))
             elif self.cur_token_type_ is Lexer.NAME and self.cur_token_ in fields:
                 key = self.cur_token_.lower()
                 value = self.expect_number_()
                 statements.append(
-                    self.ast.VheaField(key, value, location=self.cur_token_location_)
-                )
+                    self.ast.VheaField(key, value,
+                                       location=self.cur_token_location_))
                 if self.next_token_ != ";":
-                    raise FeatureLibError(
-                        "Incomplete statement", self.next_token_location_
-                    )
+                    raise FeatureLibError("Incomplete statement", self.next_token_location_)
             elif self.cur_token_ == ";":
                 continue
             else:
-                raise FeatureLibError(
-                    "Expected VertTypoAscender, "
-                    "VertTypoDescender or VertTypoLineGap",
-                    self.cur_token_location_,
-                )
+                raise FeatureLibError("Expected VertTypoAscender, "
+                                      "VertTypoDescender or VertTypoLineGap",
+                                      self.cur_token_location_)
 
     def parse_table_name_(self, table):
         statements = table.statements
         while self.next_token_ != "}" or self.cur_comments_:
             self.advance_lexer_(comments=True)
             if self.cur_token_type_ is Lexer.COMMENT:
-                statements.append(
-                    self.ast.Comment(self.cur_token_, location=self.cur_token_location_)
-                )
+                statements.append(self.ast.Comment(
+                    self.cur_token_, location=self.cur_token_location_))
             elif self.is_cur_keyword_("nameid"):
                 statement = self.parse_nameid_()
                 if statement:
@@ -1129,30 +972,30 @@
             elif self.cur_token_ == ";":
                 continue
             else:
-                raise FeatureLibError("Expected nameid", self.cur_token_location_)
+                raise FeatureLibError("Expected nameid",
+                                      self.cur_token_location_)
 
     def parse_name_(self):
-        """Parses a name record. See `section 9.e <https://adobe-type-tools.github.io/afdko/OpenTypeFeatureFileSpecification.html#9.e>`_."""
         platEncID = None
         langID = None
-        if self.next_token_type_ in Lexer.NUMBERS:
-            platformID = self.expect_any_number_()
+        if self.next_token_type_ == Lexer.NUMBER:
+            platformID = self.expect_number_()
             location = self.cur_token_location_
             if platformID not in (1, 3):
                 raise FeatureLibError("Expected platform id 1 or 3", location)
-            if self.next_token_type_ in Lexer.NUMBERS:
-                platEncID = self.expect_any_number_()
-                langID = self.expect_any_number_()
+            if self.next_token_type_ == Lexer.NUMBER:
+                platEncID = self.expect_number_()
+                langID = self.expect_number_()
         else:
             platformID = 3
             location = self.cur_token_location_
 
-        if platformID == 1:  # Macintosh
-            platEncID = platEncID or 0  # Roman
-            langID = langID or 0  # English
-        else:  # 3, Windows
-            platEncID = platEncID or 1  # Unicode
-            langID = langID or 0x0409  # English
+        if platformID == 1:                # Macintosh
+            platEncID = platEncID or 0     # Roman
+            langID = langID or 0           # English
+        else:                              # 3, Windows
+            platEncID = platEncID or 1     # Unicode
+            langID = langID or 0x0409      # English
 
         string = self.expect_string_()
         self.expect_symbol_(";")
@@ -1163,54 +1006,21 @@
         unescaped = self.unescape_string_(string, encoding)
         return platformID, platEncID, langID, unescaped
 
-    def parse_stat_name_(self):
-        platEncID = None
-        langID = None
-        if self.next_token_type_ in Lexer.NUMBERS:
-            platformID = self.expect_any_number_()
-            location = self.cur_token_location_
-            if platformID not in (1, 3):
-                raise FeatureLibError("Expected platform id 1 or 3", location)
-            if self.next_token_type_ in Lexer.NUMBERS:
-                platEncID = self.expect_any_number_()
-                langID = self.expect_any_number_()
-        else:
-            platformID = 3
-            location = self.cur_token_location_
-
-        if platformID == 1:  # Macintosh
-            platEncID = platEncID or 0  # Roman
-            langID = langID or 0  # English
-        else:  # 3, Windows
-            platEncID = platEncID or 1  # Unicode
-            langID = langID or 0x0409  # English
-
-        string = self.expect_string_()
-        encoding = getEncoding(platformID, platEncID, langID)
-        if encoding is None:
-            raise FeatureLibError("Unsupported encoding", location)
-        unescaped = self.unescape_string_(string, encoding)
-        return platformID, platEncID, langID, unescaped
-
     def parse_nameid_(self):
         assert self.cur_token_ == "nameid", self.cur_token_
-        location, nameID = self.cur_token_location_, self.expect_any_number_()
+        location, nameID = self.cur_token_location_, self.expect_number_()
         if nameID > 32767:
-            raise FeatureLibError(
-                "Name id value cannot be greater than 32767", self.cur_token_location_
-            )
+            raise FeatureLibError("Name id value cannot be greater than 32767",
+                                  self.cur_token_location_)
         if 1 <= nameID <= 6:
-            log.warning(
-                "Name id %d cannot be set from the feature file. "
-                "Ignoring record" % nameID
-            )
+            log.warning("Name id %d cannot be set from the feature file. "
+                        "Ignoring record" % nameID)
             self.parse_name_()  # skip to the next record
             return None
 
         platformID, platEncID, langID, string = self.parse_name_()
-        return self.ast.NameRecord(
-            nameID, platformID, platEncID, langID, string, location=location
-        )
+        return self.ast.NameRecord(nameID, platformID, platEncID,
+                                   langID, string, location=location)
 
     def unescape_string_(self, string, encoding):
         if encoding == "utf_16_be":
@@ -1222,12 +1032,12 @@
         # We convert surrogates to actual Unicode by round-tripping through
         # Python's UTF-16 codec in a special mode.
         utf16 = tobytes(s, "utf_16_be", "surrogatepass")
-        return tostr(utf16, "utf_16_be")
+        return tounicode(utf16, "utf_16_be")
 
     @staticmethod
     def unescape_unichr_(match):
         n = match.group(0)[1:]
-        return chr(int(n, 16))
+        return unichr(int(n, 16))
 
     @staticmethod
     def unescape_byte_(match, encoding):
@@ -1239,59 +1049,38 @@
         while self.next_token_ != "}" or self.cur_comments_:
             self.advance_lexer_(comments=True)
             if self.cur_token_type_ is Lexer.COMMENT:
-                statements.append(
-                    self.ast.Comment(self.cur_token_, location=self.cur_token_location_)
-                )
+                statements.append(self.ast.Comment(
+                    self.cur_token_, location=self.cur_token_location_))
             elif self.is_cur_keyword_("HorizAxis.BaseTagList"):
                 horiz_bases = self.parse_base_tag_list_()
             elif self.is_cur_keyword_("HorizAxis.BaseScriptList"):
                 horiz_scripts = self.parse_base_script_list_(len(horiz_bases))
                 statements.append(
-                    self.ast.BaseAxis(
-                        horiz_bases,
-                        horiz_scripts,
-                        False,
-                        location=self.cur_token_location_,
-                    )
-                )
+                        self.ast.BaseAxis(horiz_bases,
+                                          horiz_scripts, False,
+                                          location=self.cur_token_location_))
             elif self.is_cur_keyword_("VertAxis.BaseTagList"):
                 vert_bases = self.parse_base_tag_list_()
             elif self.is_cur_keyword_("VertAxis.BaseScriptList"):
                 vert_scripts = self.parse_base_script_list_(len(vert_bases))
                 statements.append(
-                    self.ast.BaseAxis(
-                        vert_bases,
-                        vert_scripts,
-                        True,
-                        location=self.cur_token_location_,
-                    )
-                )
+                        self.ast.BaseAxis(vert_bases,
+                                          vert_scripts, True,
+                                          location=self.cur_token_location_))
             elif self.cur_token_ == ";":
                 continue
 
     def parse_table_OS_2_(self, table):
         statements = table.statements
-        numbers = (
-            "FSType",
-            "TypoAscender",
-            "TypoDescender",
-            "TypoLineGap",
-            "winAscent",
-            "winDescent",
-            "XHeight",
-            "CapHeight",
-            "WeightClass",
-            "WidthClass",
-            "LowerOpSize",
-            "UpperOpSize",
-        )
+        numbers = ("FSType", "TypoAscender", "TypoDescender", "TypoLineGap",
+                   "winAscent", "winDescent", "XHeight", "CapHeight",
+                   "WeightClass", "WidthClass", "LowerOpSize", "UpperOpSize")
         ranges = ("UnicodeRange", "CodePageRange")
         while self.next_token_ != "}" or self.cur_comments_:
             self.advance_lexer_(comments=True)
             if self.cur_token_type_ is Lexer.COMMENT:
-                statements.append(
-                    self.ast.Comment(self.cur_token_, location=self.cur_token_location_)
-                )
+                statements.append(self.ast.Comment(
+                    self.cur_token_, location=self.cur_token_location_))
             elif self.cur_token_type_ is Lexer.NAME:
                 key = self.cur_token_.lower()
                 value = None
@@ -1304,213 +1093,18 @@
                 elif self.cur_token_ in ranges:
                     value = []
                     while self.next_token_ != ";":
-                        value.append(self.expect_number_())
+                         value.append(self.expect_number_())
                 elif self.is_cur_keyword_("Vendor"):
                     value = self.expect_string_()
                 statements.append(
-                    self.ast.OS2Field(key, value, location=self.cur_token_location_)
-                )
-            elif self.cur_token_ == ";":
-                continue
-
-    def parse_STAT_ElidedFallbackName(self):
-        assert self.is_cur_keyword_("ElidedFallbackName")
-        self.expect_symbol_("{")
-        names = []
-        while self.next_token_ != "}" or self.cur_comments_:
-            self.advance_lexer_()
-            if self.is_cur_keyword_("name"):
-                platformID, platEncID, langID, string = self.parse_stat_name_()
-                nameRecord = self.ast.STATNameStatement(
-                    "stat",
-                    platformID,
-                    platEncID,
-                    langID,
-                    string,
-                    location=self.cur_token_location_,
-                )
-                names.append(nameRecord)
-            else:
-                if self.cur_token_ != ";":
-                    raise FeatureLibError(
-                        f"Unexpected token {self.cur_token_} " f"in ElidedFallbackName",
-                        self.cur_token_location_,
-                    )
-        self.expect_symbol_("}")
-        if not names:
-            raise FeatureLibError('Expected "name"', self.cur_token_location_)
-        return names
-
-    def parse_STAT_design_axis(self):
-        assert self.is_cur_keyword_("DesignAxis")
-        names = []
-        axisTag = self.expect_tag_()
-        if (
-            axisTag not in ("ital", "opsz", "slnt", "wdth", "wght")
-            and not axisTag.isupper()
-        ):
-            log.warning(f"Unregistered axis tag {axisTag} should be uppercase.")
-        axisOrder = self.expect_number_()
-        self.expect_symbol_("{")
-        while self.next_token_ != "}" or self.cur_comments_:
-            self.advance_lexer_()
-            if self.cur_token_type_ is Lexer.COMMENT:
-                continue
-            elif self.is_cur_keyword_("name"):
-                location = self.cur_token_location_
-                platformID, platEncID, langID, string = self.parse_stat_name_()
-                name = self.ast.STATNameStatement(
-                    "stat", platformID, platEncID, langID, string, location=location
-                )
-                names.append(name)
-            elif self.cur_token_ == ";":
-                continue
-            else:
-                raise FeatureLibError(
-                    f'Expected "name", got {self.cur_token_}', self.cur_token_location_
-                )
-
-        self.expect_symbol_("}")
-        return self.ast.STATDesignAxisStatement(
-            axisTag, axisOrder, names, self.cur_token_location_
-        )
-
-    def parse_STAT_axis_value_(self):
-        assert self.is_cur_keyword_("AxisValue")
-        self.expect_symbol_("{")
-        locations = []
-        names = []
-        flags = 0
-        while self.next_token_ != "}" or self.cur_comments_:
-            self.advance_lexer_(comments=True)
-            if self.cur_token_type_ is Lexer.COMMENT:
-                continue
-            elif self.is_cur_keyword_("name"):
-                location = self.cur_token_location_
-                platformID, platEncID, langID, string = self.parse_stat_name_()
-                name = self.ast.STATNameStatement(
-                    "stat", platformID, platEncID, langID, string, location=location
-                )
-                names.append(name)
-            elif self.is_cur_keyword_("location"):
-                location = self.parse_STAT_location()
-                locations.append(location)
-            elif self.is_cur_keyword_("flag"):
-                flags = self.expect_stat_flags()
-            elif self.cur_token_ == ";":
-                continue
-            else:
-                raise FeatureLibError(
-                    f"Unexpected token {self.cur_token_} " f"in AxisValue",
-                    self.cur_token_location_,
-                )
-        self.expect_symbol_("}")
-        if not names:
-            raise FeatureLibError('Expected "Axis Name"', self.cur_token_location_)
-        if not locations:
-            raise FeatureLibError('Expected "Axis location"', self.cur_token_location_)
-        if len(locations) > 1:
-            for location in locations:
-                if len(location.values) > 1:
-                    raise FeatureLibError(
-                        "Only one value is allowed in a "
-                        "Format 4 Axis Value Record, but "
-                        f"{len(location.values)} were found.",
-                        self.cur_token_location_,
-                    )
-            format4_tags = []
-            for location in locations:
-                tag = location.tag
-                if tag in format4_tags:
-                    raise FeatureLibError(
-                        f"Axis tag {tag} already " "defined.", self.cur_token_location_
-                    )
-                format4_tags.append(tag)
-
-        return self.ast.STATAxisValueStatement(
-            names, locations, flags, self.cur_token_location_
-        )
-
-    def parse_STAT_location(self):
-        values = []
-        tag = self.expect_tag_()
-        if len(tag.strip()) != 4:
-            raise FeatureLibError(
-                f"Axis tag {self.cur_token_} must be 4 " "characters",
-                self.cur_token_location_,
-            )
-
-        while self.next_token_ != ";":
-            if self.next_token_type_ is Lexer.FLOAT:
-                value = self.expect_float_()
-                values.append(value)
-            elif self.next_token_type_ is Lexer.NUMBER:
-                value = self.expect_number_()
-                values.append(value)
-            else:
-                raise FeatureLibError(
-                    f'Unexpected value "{self.next_token_}". '
-                    "Expected integer or float.",
-                    self.next_token_location_,
-                )
-        if len(values) == 3:
-            nominal, min_val, max_val = values
-            if nominal < min_val or nominal > max_val:
-                raise FeatureLibError(
-                    f"Default value {nominal} is outside "
-                    f"of specified range "
-                    f"{min_val}-{max_val}.",
-                    self.next_token_location_,
-                )
-        return self.ast.AxisValueLocationStatement(tag, values)
-
-    def parse_table_STAT_(self, table):
-        statements = table.statements
-        design_axes = []
-        while self.next_token_ != "}" or self.cur_comments_:
-            self.advance_lexer_(comments=True)
-            if self.cur_token_type_ is Lexer.COMMENT:
-                statements.append(
-                    self.ast.Comment(self.cur_token_, location=self.cur_token_location_)
-                )
-            elif self.cur_token_type_ is Lexer.NAME:
-                if self.is_cur_keyword_("ElidedFallbackName"):
-                    names = self.parse_STAT_ElidedFallbackName()
-                    statements.append(self.ast.ElidedFallbackName(names))
-                elif self.is_cur_keyword_("ElidedFallbackNameID"):
-                    value = self.expect_number_()
-                    statements.append(self.ast.ElidedFallbackNameID(value))
-                    self.expect_symbol_(";")
-                elif self.is_cur_keyword_("DesignAxis"):
-                    designAxis = self.parse_STAT_design_axis()
-                    design_axes.append(designAxis.tag)
-                    statements.append(designAxis)
-                    self.expect_symbol_(";")
-                elif self.is_cur_keyword_("AxisValue"):
-                    axisValueRecord = self.parse_STAT_axis_value_()
-                    for location in axisValueRecord.locations:
-                        if location.tag not in design_axes:
-                            # Tag must be defined in a DesignAxis before it
-                            # can be referenced
-                            raise FeatureLibError(
-                                "DesignAxis not defined for " f"{location.tag}.",
-                                self.cur_token_location_,
-                            )
-                    statements.append(axisValueRecord)
-                    self.expect_symbol_(";")
-                else:
-                    raise FeatureLibError(
-                        f"Unexpected token {self.cur_token_}", self.cur_token_location_
-                    )
+                    self.ast.OS2Field(key, value,
+                                      location=self.cur_token_location_))
             elif self.cur_token_ == ";":
                 continue
 
     def parse_base_tag_list_(self):
-        # Parses BASE table entries. (See `section 9.a <https://adobe-type-tools.github.io/afdko/OpenTypeFeatureFileSpecification.html#9.a>`_)
-        assert self.cur_token_ in (
-            "HorizAxis.BaseTagList",
-            "VertAxis.BaseTagList",
-        ), self.cur_token_
+        assert self.cur_token_ in ("HorizAxis.BaseTagList",
+                                   "VertAxis.BaseTagList"), self.cur_token_
         bases = []
         while self.next_token_ != ";":
             bases.append(self.expect_script_tag_())
@@ -1518,10 +1112,8 @@
         return bases
 
     def parse_base_script_list_(self, count):
-        assert self.cur_token_ in (
-            "HorizAxis.BaseScriptList",
-            "VertAxis.BaseScriptList",
-        ), self.cur_token_
+        assert self.cur_token_ in ("HorizAxis.BaseScriptList",
+                                   "VertAxis.BaseScriptList"), self.cur_token_
         scripts = [(self.parse_base_script_record_(count))]
         while self.next_token_ == ",":
             self.expect_symbol_(",")
@@ -1557,13 +1149,13 @@
         if self.next_token_type_ is Lexer.NUMBER:
             number, location = self.expect_number_(), self.cur_token_location_
             if vertical:
-                val = self.ast.ValueRecord(
-                    yAdvance=number, vertical=vertical, location=location
-                )
+                val = self.ast.ValueRecord(yAdvance=number,
+                                           vertical=vertical,
+                                           location=location)
             else:
-                val = self.ast.ValueRecord(
-                    xAdvance=number, vertical=vertical, location=location
-                )
+                val = self.ast.ValueRecord(xAdvance=number,
+                                           vertical=vertical,
+                                           location=location)
             return val
         self.expect_symbol_("<")
         location = self.cur_token_location_
@@ -1574,60 +1166,42 @@
                 return self.ast.ValueRecord()
             vrd = self.valuerecords_.resolve(name)
             if vrd is None:
-                raise FeatureLibError(
-                    'Unknown valueRecordDef "%s"' % name, self.cur_token_location_
-                )
+                raise FeatureLibError("Unknown valueRecordDef \"%s\"" % name,
+                                      self.cur_token_location_)
             value = vrd.value
             xPlacement, yPlacement = (value.xPlacement, value.yPlacement)
             xAdvance, yAdvance = (value.xAdvance, value.yAdvance)
         else:
             xPlacement, yPlacement, xAdvance, yAdvance = (
-                self.expect_number_(),
-                self.expect_number_(),
-                self.expect_number_(),
-                self.expect_number_(),
-            )
+                self.expect_number_(), self.expect_number_(),
+                self.expect_number_(), self.expect_number_())
 
         if self.next_token_ == "<":
             xPlaDevice, yPlaDevice, xAdvDevice, yAdvDevice = (
-                self.parse_device_(),
-                self.parse_device_(),
-                self.parse_device_(),
-                self.parse_device_(),
-            )
-            allDeltas = sorted(
-                [
-                    delta
-                    for size, delta in (xPlaDevice if xPlaDevice else ())
-                    + (yPlaDevice if yPlaDevice else ())
-                    + (xAdvDevice if xAdvDevice else ())
-                    + (yAdvDevice if yAdvDevice else ())
-                ]
-            )
+                self.parse_device_(), self.parse_device_(),
+                self.parse_device_(), self.parse_device_())
+            allDeltas = sorted([
+                delta
+                for size, delta
+                in (xPlaDevice if xPlaDevice else ()) +
+                (yPlaDevice if yPlaDevice else ()) +
+                (xAdvDevice if xAdvDevice else ()) +
+                (yAdvDevice if yAdvDevice else ())])
             if allDeltas[0] < -128 or allDeltas[-1] > 127:
                 raise FeatureLibError(
                     "Device value out of valid range (-128..127)",
-                    self.cur_token_location_,
-                )
+                    self.cur_token_location_)
         else:
-            xPlaDevice, yPlaDevice, xAdvDevice, yAdvDevice = (None, None, None, None)
+            xPlaDevice, yPlaDevice, xAdvDevice, yAdvDevice = (
+                None, None, None, None)
 
         self.expect_symbol_(">")
         return self.ast.ValueRecord(
-            xPlacement,
-            yPlacement,
-            xAdvance,
-            yAdvance,
-            xPlaDevice,
-            yPlaDevice,
-            xAdvDevice,
-            yAdvDevice,
-            vertical=vertical,
-            location=location,
-        )
+            xPlacement, yPlacement, xAdvance, yAdvance,
+            xPlaDevice, yPlaDevice, xAdvDevice, yAdvDevice,
+            vertical=vertical, location=location)
 
     def parse_valuerecord_definition_(self, vertical):
-        # Parses a named value record definition. (See section `2.e.v <https://adobe-type-tools.github.io/afdko/OpenTypeFeatureFileSpecification.html#2.e.v>`_)
         assert self.is_cur_keyword_("valueRecordDef")
         location = self.cur_token_location_
         value = self.parse_valuerecord_(vertical)
@@ -1643,13 +1217,14 @@
         script = self.expect_script_tag_()
         language = self.expect_language_tag_()
         self.expect_symbol_(";")
-        return self.ast.LanguageSystemStatement(script, language, location=location)
+        return self.ast.LanguageSystemStatement(script, language,
+                                                location=location)
 
     def parse_feature_block_(self):
         assert self.cur_token_ == "feature"
         location = self.cur_token_location_
         tag = self.expect_tag_()
-        vertical = tag in {"vkrn", "vpal", "vhal", "valt"}
+        vertical = (tag in {"vkrn", "vpal", "vhal", "valt"})
 
         stylisticset = None
         cv_feature = None
@@ -1666,10 +1241,10 @@
             self.expect_keyword_("useExtension")
             use_extension = True
 
-        block = self.ast.FeatureBlock(
-            tag, use_extension=use_extension, location=location
-        )
-        self.parse_block_(block, vertical, stylisticset, size_feature, cv_feature)
+        block = self.ast.FeatureBlock(tag, use_extension=use_extension,
+                                      location=location)
+        self.parse_block_(block, vertical, stylisticset, size_feature,
+                          cv_feature)
         return block
 
     def parse_feature_reference_(self):
@@ -1677,36 +1252,33 @@
         location = self.cur_token_location_
         featureName = self.expect_tag_()
         self.expect_symbol_(";")
-        return self.ast.FeatureReferenceStatement(featureName, location=location)
+        return self.ast.FeatureReferenceStatement(featureName,
+                                                  location=location)
 
     def parse_featureNames_(self, tag):
-        """Parses a ``featureNames`` statement found in stylistic set features.
-        See section `8.c <https://adobe-type-tools.github.io/afdko/OpenTypeFeatureFileSpecification.html#8.c>`_."""
         assert self.cur_token_ == "featureNames", self.cur_token_
-        block = self.ast.NestedBlock(
-            tag, self.cur_token_, location=self.cur_token_location_
-        )
+        block = self.ast.NestedBlock(tag, self.cur_token_,
+                                     location=self.cur_token_location_)
         self.expect_symbol_("{")
         for symtab in self.symbol_tables_:
             symtab.enter_scope()
         while self.next_token_ != "}" or self.cur_comments_:
             self.advance_lexer_(comments=True)
             if self.cur_token_type_ is Lexer.COMMENT:
-                block.statements.append(
-                    self.ast.Comment(self.cur_token_, location=self.cur_token_location_)
-                )
+                block.statements.append(self.ast.Comment(
+                    self.cur_token_, location=self.cur_token_location_))
             elif self.is_cur_keyword_("name"):
                 location = self.cur_token_location_
                 platformID, platEncID, langID, string = self.parse_name_()
                 block.statements.append(
-                    self.ast.FeatureNameStatement(
-                        tag, platformID, platEncID, langID, string, location=location
-                    )
-                )
+                    self.ast.FeatureNameStatement(tag, platformID,
+                                                  platEncID, langID, string,
+                                                  location=location))
             elif self.cur_token_ == ";":
                 continue
             else:
-                raise FeatureLibError('Expected "name"', self.cur_token_location_)
+                raise FeatureLibError('Expected "name"',
+                                      self.cur_token_location_)
         self.expect_symbol_("}")
         for symtab in self.symbol_tables_:
             symtab.exit_scope()
@@ -1714,12 +1286,9 @@
         return block
 
     def parse_cvParameters_(self, tag):
-        # Parses a ``cvParameters`` block found in Character Variant features.
-        # See section `8.d <https://adobe-type-tools.github.io/afdko/OpenTypeFeatureFileSpecification.html#8.d>`_.
         assert self.cur_token_ == "cvParameters", self.cur_token_
-        block = self.ast.NestedBlock(
-            tag, self.cur_token_, location=self.cur_token_location_
-        )
+        block = self.ast.NestedBlock(tag, self.cur_token_,
+                                     location=self.cur_token_location_)
         self.expect_symbol_("{")
         for symtab in self.symbol_tables_:
             symtab.enter_scope()
@@ -1728,17 +1297,12 @@
         while self.next_token_ != "}" or self.cur_comments_:
             self.advance_lexer_(comments=True)
             if self.cur_token_type_ is Lexer.COMMENT:
-                statements.append(
-                    self.ast.Comment(self.cur_token_, location=self.cur_token_location_)
-                )
-            elif self.is_cur_keyword_(
-                {
-                    "FeatUILabelNameID",
-                    "FeatUITooltipTextNameID",
-                    "SampleTextNameID",
-                    "ParamUILabelNameID",
-                }
-            ):
+                statements.append(self.ast.Comment(
+                    self.cur_token_, location=self.cur_token_location_))
+            elif self.is_cur_keyword_({"FeatUILabelNameID",
+                                       "FeatUITooltipTextNameID",
+                                       "SampleTextNameID",
+                                       "ParamUILabelNameID"}):
                 statements.append(self.parse_cvNameIDs_(tag, self.cur_token_))
             elif self.is_cur_keyword_("Character"):
                 statements.append(self.parse_cvCharacter_(tag))
@@ -1747,10 +1311,8 @@
             else:
                 raise FeatureLibError(
                     "Expected statement: got {} {}".format(
-                        self.cur_token_type_, self.cur_token_
-                    ),
-                    self.cur_token_location_,
-                )
+                        self.cur_token_type_, self.cur_token_),
+                    self.cur_token_location_)
 
         self.expect_symbol_("}")
         for symtab in self.symbol_tables_:
@@ -1760,34 +1322,28 @@
 
     def parse_cvNameIDs_(self, tag, block_name):
         assert self.cur_token_ == block_name, self.cur_token_
-        block = self.ast.NestedBlock(tag, block_name, location=self.cur_token_location_)
+        block = self.ast.NestedBlock(tag, block_name,
+                                     location=self.cur_token_location_)
         self.expect_symbol_("{")
         for symtab in self.symbol_tables_:
             symtab.enter_scope()
         while self.next_token_ != "}" or self.cur_comments_:
             self.advance_lexer_(comments=True)
             if self.cur_token_type_ is Lexer.COMMENT:
-                block.statements.append(
-                    self.ast.Comment(self.cur_token_, location=self.cur_token_location_)
-                )
+                block.statements.append(self.ast.Comment(
+                    self.cur_token_, location=self.cur_token_location_))
             elif self.is_cur_keyword_("name"):
                 location = self.cur_token_location_
                 platformID, platEncID, langID, string = self.parse_name_()
                 block.statements.append(
                     self.ast.CVParametersNameStatement(
-                        tag,
-                        platformID,
-                        platEncID,
-                        langID,
-                        string,
-                        block_name,
-                        location=location,
-                    )
-                )
+                        tag, platformID, platEncID, langID, string,
+                        block_name, location=location))
             elif self.cur_token_ == ";":
                 continue
             else:
-                raise FeatureLibError('Expected "name"', self.cur_token_location_)
+                raise FeatureLibError('Expected "name"',
+                                      self.cur_token_location_)
         self.expect_symbol_("}")
         for symtab in self.symbol_tables_:
             symtab.exit_scope()
@@ -1796,29 +1352,25 @@
 
     def parse_cvCharacter_(self, tag):
         assert self.cur_token_ == "Character", self.cur_token_
-        location, character = self.cur_token_location_, self.expect_any_number_()
+        location, character = self.cur_token_location_, self.expect_decimal_or_hexadecimal_()
         self.expect_symbol_(";")
         if not (0xFFFFFF >= character >= 0):
-            raise FeatureLibError(
-                "Character value must be between "
-                "{:#x} and {:#x}".format(0, 0xFFFFFF),
-                location,
-            )
+            raise FeatureLibError("Character value must be between "
+                                  "{:#x} and {:#x}".format(0, 0xFFFFFF),
+                                  location)
         return self.ast.CharacterStatement(character, tag, location=location)
 
     def parse_FontRevision_(self):
-        # Parses a ``FontRevision`` statement found in the head table. See
-        # `section 9.c <https://adobe-type-tools.github.io/afdko/OpenTypeFeatureFileSpecification.html#9.c>`_.
         assert self.cur_token_ == "FontRevision", self.cur_token_
         location, version = self.cur_token_location_, self.expect_float_()
         self.expect_symbol_(";")
         if version <= 0:
-            raise FeatureLibError("Font revision numbers must be positive", location)
+            raise FeatureLibError("Font revision numbers must be positive",
+                                  location)
         return self.ast.FontRevisionStatement(version, location=location)
 
-    def parse_block_(
-        self, block, vertical, stylisticset=None, size_feature=False, cv_feature=None
-    ):
+    def parse_block_(self, block, vertical, stylisticset=None,
+                     size_feature=False, cv_feature=None):
         self.expect_symbol_("{")
         for symtab in self.symbol_tables_:
             symtab.enter_scope()
@@ -1827,9 +1379,8 @@
         while self.next_token_ != "}" or self.cur_comments_:
             self.advance_lexer_(comments=True)
             if self.cur_token_type_ is Lexer.COMMENT:
-                statements.append(
-                    self.ast.Comment(self.cur_token_, location=self.cur_token_location_)
-                )
+                statements.append(self.ast.Comment(
+                    self.cur_token_, location=self.cur_token_location_))
             elif self.cur_token_type_ is Lexer.GLYPHCLASS:
                 statements.append(self.parse_glyphclass_definition_())
             elif self.is_cur_keyword_("anchorDef"):
@@ -1850,11 +1401,11 @@
                 statements.append(self.parse_markClass_())
             elif self.is_cur_keyword_({"pos", "position"}):
                 statements.append(
-                    self.parse_position_(enumerated=False, vertical=vertical)
-                )
+                    self.parse_position_(enumerated=False, vertical=vertical))
             elif self.is_cur_keyword_("script"):
                 statements.append(self.parse_script_())
-            elif self.is_cur_keyword_({"sub", "substitute", "rsub", "reversesub"}):
+            elif (self.is_cur_keyword_({"sub", "substitute",
+                                        "rsub", "reversesub"})):
                 statements.append(self.parse_substitute_())
             elif self.is_cur_keyword_("subtable"):
                 statements.append(self.parse_subtable_())
@@ -1868,20 +1419,14 @@
                 statements.append(self.parse_size_parameters_())
             elif size_feature and self.is_cur_keyword_("sizemenuname"):
                 statements.append(self.parse_size_menuname_())
-            elif (
-                self.cur_token_type_ is Lexer.NAME
-                and self.cur_token_ in self.extensions
-            ):
+            elif self.cur_token_type_ is Lexer.NAME and self.cur_token_ in self.extensions:
                 statements.append(self.extensions[self.cur_token_](self))
             elif self.cur_token_ == ";":
                 continue
             else:
                 raise FeatureLibError(
-                    "Expected glyph class definition or statement: got {} {}".format(
-                        self.cur_token_type_, self.cur_token_
-                    ),
-                    self.cur_token_location_,
-                )
+                    "Expected glyph class definition or statement: got {} {}".format(self.cur_token_type_, self.cur_token_),
+                    self.cur_token_location_)
 
         self.expect_symbol_("}")
         for symtab in self.symbol_tables_:
@@ -1889,9 +1434,8 @@
 
         name = self.expect_name_()
         if name != block.name.strip():
-            raise FeatureLibError(
-                'Expected "%s"' % block.name.strip(), self.cur_token_location_
-            )
+            raise FeatureLibError("Expected \"%s\"" % block.name.strip(),
+                                  self.cur_token_location_)
         self.expect_symbol_(";")
 
         # A multiple substitution may have a single destination, in which case
@@ -1910,27 +1454,12 @@
 
         # Upgrade all single substitutions to multiple substitutions.
         if has_single and has_multiple:
-            statements = []
-            for s in block.statements:
+            for i, s in enumerate(statements):
                 if isinstance(s, self.ast.SingleSubstStatement):
-                    glyphs = s.glyphs[0].glyphSet()
-                    replacements = s.replacements[0].glyphSet()
-                    if len(replacements) == 1:
-                        replacements *= len(glyphs)
-                    for i, glyph in enumerate(glyphs):
-                        statements.append(
-                            self.ast.MultipleSubstStatement(
-                                s.prefix,
-                                glyph,
-                                s.suffix,
-                                [replacements[i]],
-                                s.forceChain,
-                                location=s.location,
-                            )
-                        )
-                else:
-                    statements.append(s)
-            block.statements = statements
+                    statements[i] = self.ast.MultipleSubstStatement(
+                        s.prefix, s.glyphs[0].glyphSet()[0], s.suffix,
+                        [r.glyphSet()[0] for r in s.replacements],
+                        s.forceChain, location=s.location)
 
     def is_cur_keyword_(self, k):
         if self.cur_token_type_ is Lexer.NAME:
@@ -1955,7 +1484,8 @@
     def expect_filename_(self):
         self.advance_lexer_()
         if self.cur_token_type_ is not Lexer.FILENAME:
-            raise FeatureLibError("Expected file name", self.cur_token_location_)
+            raise FeatureLibError("Expected file name",
+                                  self.cur_token_location_)
         return self.cur_token_
 
     def expect_glyph_(self):
@@ -1965,39 +1495,22 @@
             if len(self.cur_token_) > 63:
                 raise FeatureLibError(
                     "Glyph names must not be longer than 63 characters",
-                    self.cur_token_location_,
-                )
+                    self.cur_token_location_)
             return self.cur_token_
         elif self.cur_token_type_ is Lexer.CID:
             return "cid%05d" % self.cur_token_
-        raise FeatureLibError("Expected a glyph name or CID", self.cur_token_location_)
-
-    def check_glyph_name_in_glyph_set(self, *names):
-        """Raises if glyph name (just `start`) or glyph names of a
-        range (`start` and `end`) are not in the glyph set.
-
-        If no glyph set is present, does nothing.
-        """
-        if self.glyphNames_:
-            missing = [name for name in names if name not in self.glyphNames_]
-            if missing:
-                raise FeatureLibError(
-                    "The following glyph names are referenced but are missing from the "
-                    f"glyph set: {', '.join(missing)}",
-                    self.cur_token_location_,
-                )
+        raise FeatureLibError("Expected a glyph name or CID",
+                              self.cur_token_location_)
 
     def expect_markClass_reference_(self):
         name = self.expect_class_name_()
         mc = self.glyphclasses_.resolve(name)
         if mc is None:
-            raise FeatureLibError(
-                "Unknown markClass @%s" % name, self.cur_token_location_
-            )
+            raise FeatureLibError("Unknown markClass @%s" % name,
+                                  self.cur_token_location_)
         if not isinstance(mc, self.ast.MarkClass):
-            raise FeatureLibError(
-                "@%s is not a markClass" % name, self.cur_token_location_
-            )
+            raise FeatureLibError("@%s is not a markClass" % name,
+                                  self.cur_token_location_)
         return mc
 
     def expect_tag_(self):
@@ -2005,9 +1518,8 @@
         if self.cur_token_type_ is not Lexer.NAME:
             raise FeatureLibError("Expected a tag", self.cur_token_location_)
         if len(self.cur_token_) > 4:
-            raise FeatureLibError(
-                "Tags cannot be longer than 4 characters", self.cur_token_location_
-            )
+            raise FeatureLibError("Tags can not be longer than 4 characters",
+                                  self.cur_token_location_)
         return (self.cur_token_ + "    ")[:4]
 
     def expect_script_tag_(self):
@@ -2015,8 +1527,7 @@
         if tag == "dflt":
             raise FeatureLibError(
                 '"dflt" is not a valid script tag; use "DFLT" instead',
-                self.cur_token_location_,
-            )
+                self.cur_token_location_)
         return tag
 
     def expect_language_tag_(self):
@@ -2024,21 +1535,22 @@
         if tag == "DFLT":
             raise FeatureLibError(
                 '"DFLT" is not a valid language tag; use "dflt" instead',
-                self.cur_token_location_,
-            )
+                self.cur_token_location_)
         return tag
 
     def expect_symbol_(self, symbol):
         self.advance_lexer_()
         if self.cur_token_type_ is Lexer.SYMBOL and self.cur_token_ == symbol:
             return symbol
-        raise FeatureLibError("Expected '%s'" % symbol, self.cur_token_location_)
+        raise FeatureLibError("Expected '%s'" % symbol,
+                              self.cur_token_location_)
 
     def expect_keyword_(self, keyword):
         self.advance_lexer_()
         if self.cur_token_type_ is Lexer.NAME and self.cur_token_ == keyword:
             return self.cur_token_
-        raise FeatureLibError('Expected "%s"' % keyword, self.cur_token_location_)
+        raise FeatureLibError("Expected \"%s\"" % keyword,
+                              self.cur_token_location_)
 
     def expect_name_(self):
         self.advance_lexer_()
@@ -2046,63 +1558,41 @@
             return self.cur_token_
         raise FeatureLibError("Expected a name", self.cur_token_location_)
 
+    # TODO: Don't allow this method to accept hexadecimal values
     def expect_number_(self):
         self.advance_lexer_()
         if self.cur_token_type_ is Lexer.NUMBER:
             return self.cur_token_
         raise FeatureLibError("Expected a number", self.cur_token_location_)
 
-    def expect_any_number_(self):
-        self.advance_lexer_()
-        if self.cur_token_type_ in Lexer.NUMBERS:
-            return self.cur_token_
-        raise FeatureLibError(
-            "Expected a decimal, hexadecimal or octal number", self.cur_token_location_
-        )
-
     def expect_float_(self):
         self.advance_lexer_()
         if self.cur_token_type_ is Lexer.FLOAT:
             return self.cur_token_
-        raise FeatureLibError(
-            "Expected a floating-point number", self.cur_token_location_
-        )
+        raise FeatureLibError("Expected a floating-point number",
+                              self.cur_token_location_)
 
+    # TODO: Don't allow this method to accept hexadecimal values
     def expect_decipoint_(self):
         if self.next_token_type_ == Lexer.FLOAT:
             return self.expect_float_()
         elif self.next_token_type_ is Lexer.NUMBER:
             return self.expect_number_() / 10
         else:
-            raise FeatureLibError(
-                "Expected an integer or floating-point number", self.cur_token_location_
-            )
+            raise FeatureLibError("Expected an integer or floating-point number",
+                                  self.cur_token_location_)
 
-    def expect_stat_flags(self):
-        value = 0
-        flags = {
-            "OlderSiblingFontAttribute": 1,
-            "ElidableAxisValueName": 2,
-        }
-        while self.next_token_ != ";":
-            if self.next_token_ in flags:
-                name = self.expect_name_()
-                value = value | flags[name]
-            else:
-                raise FeatureLibError(
-                    f"Unexpected STAT flag {self.cur_token_}", self.cur_token_location_
-                )
-        return value
-
-    def expect_stat_values_(self):
-        if self.next_token_type_ == Lexer.FLOAT:
-            return self.expect_float_()
-        elif self.next_token_type_ is Lexer.NUMBER:
-            return self.expect_number_()
-        else:
-            raise FeatureLibError(
-                "Expected an integer or floating-point number", self.cur_token_location_
-            )
+    def expect_decimal_or_hexadecimal_(self):
+        # the lexer returns the same token type 'NUMBER' for either decimal or
+        # hexadecimal integers, and casts them both to a `int` type, so it's
+        # impossible to distinguish the two here. This method is implemented
+        # the same as `expect_number_`, only it gives a more informative
+        # error message
+        self.advance_lexer_()
+        if self.cur_token_type_ is Lexer.NUMBER:
+            return self.cur_token_
+        raise FeatureLibError("Expected a decimal or hexadecimal number",
+                              self.cur_token_location_)
 
     def expect_string_(self):
         self.advance_lexer_()
@@ -2117,17 +1607,11 @@
             return
         else:
             self.cur_token_type_, self.cur_token_, self.cur_token_location_ = (
-                self.next_token_type_,
-                self.next_token_,
-                self.next_token_location_,
-            )
+                self.next_token_type_, self.next_token_, self.next_token_location_)
         while True:
             try:
-                (
-                    self.next_token_type_,
-                    self.next_token_,
-                    self.next_token_location_,
-                ) = next(self.lexer_)
+                (self.next_token_type_, self.next_token_,
+                 self.next_token_location_) = next(self.lexer_)
             except StopIteration:
                 self.next_token_type_, self.next_token_ = (None, None)
             if self.next_token_type_ != Lexer.COMMENT:
@@ -2137,15 +1621,14 @@
     @staticmethod
     def reverse_string_(s):
         """'abc' --> 'cba'"""
-        return "".join(reversed(list(s)))
+        return ''.join(reversed(list(s)))
 
     def make_cid_range_(self, location, start, limit):
         """(location, 999, 1001) --> ["cid00999", "cid01000", "cid01001"]"""
         result = list()
         if start > limit:
             raise FeatureLibError(
-                "Bad range: start should be less than limit", location
-            )
+                "Bad range: start should be less than limit", location)
         for cid in range(start, limit + 1):
             result.append("cid%05d" % cid)
         return result
@@ -2155,45 +1638,45 @@
         result = list()
         if len(start) != len(limit):
             raise FeatureLibError(
-                'Bad range: "%s" and "%s" should have the same length' % (start, limit),
-                location,
-            )
+                "Bad range: \"%s\" and \"%s\" should have the same length" %
+                (start, limit), location)
 
         rev = self.reverse_string_
         prefix = os.path.commonprefix([start, limit])
         suffix = rev(os.path.commonprefix([rev(start), rev(limit)]))
         if len(suffix) > 0:
-            start_range = start[len(prefix) : -len(suffix)]
-            limit_range = limit[len(prefix) : -len(suffix)]
+            start_range = start[len(prefix):-len(suffix)]
+            limit_range = limit[len(prefix):-len(suffix)]
         else:
-            start_range = start[len(prefix) :]
-            limit_range = limit[len(prefix) :]
+            start_range = start[len(prefix):]
+            limit_range = limit[len(prefix):]
 
         if start_range >= limit_range:
             raise FeatureLibError(
-                "Start of range must be smaller than its end", location
-            )
+                "Start of range must be smaller than its end",
+                location)
 
-        uppercase = re.compile(r"^[A-Z]$")
+        uppercase = re.compile(r'^[A-Z]$')
         if uppercase.match(start_range) and uppercase.match(limit_range):
             for c in range(ord(start_range), ord(limit_range) + 1):
                 result.append("%s%c%s" % (prefix, c, suffix))
             return result
 
-        lowercase = re.compile(r"^[a-z]$")
+        lowercase = re.compile(r'^[a-z]$')
         if lowercase.match(start_range) and lowercase.match(limit_range):
             for c in range(ord(start_range), ord(limit_range) + 1):
                 result.append("%s%c%s" % (prefix, c, suffix))
             return result
 
-        digits = re.compile(r"^[0-9]{1,3}$")
+        digits = re.compile(r'^[0-9]{1,3}$')
         if digits.match(start_range) and digits.match(limit_range):
             for i in range(int(start_range, 10), int(limit_range, 10) + 1):
-                number = ("000" + str(i))[-len(start_range) :]
+                number = ("000" + str(i))[-len(start_range):]
                 result.append("%s%s%s" % (prefix, number, suffix))
             return result
 
-        raise FeatureLibError('Bad range: "%s-%s"' % (start, limit), location)
+        raise FeatureLibError("Bad range: \"%s-%s\"" % (start, limit),
+                              location)
 
 
 class SymbolTable(object):
diff --git a/Lib/fontTools/fontBuilder.py b/Lib/fontTools/fontBuilder.py
index e282408..c6811f0 100644
--- a/Lib/fontTools/fontBuilder.py
+++ b/Lib/fontTools/fontBuilder.py
@@ -1,3 +1,6 @@
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
+
 __all__ = ["FontBuilder"]
 
 """
@@ -129,196 +132,198 @@
 ```
 """
 
+from .misc.py23 import *
 from .ttLib import TTFont, newTable
 from .ttLib.tables._c_m_a_p import cmap_classes
+from .ttLib.tables._n_a_m_e import NameRecord, makeName
 from .misc.timeTools import timestampNow
 import struct
-from collections import OrderedDict
 
 
 _headDefaults = dict(
-    tableVersion=1.0,
-    fontRevision=1.0,
-    checkSumAdjustment=0,
-    magicNumber=0x5F0F3CF5,
-    flags=0x0003,
-    unitsPerEm=1000,
-    created=0,
-    modified=0,
-    xMin=0,
-    yMin=0,
-    xMax=0,
-    yMax=0,
-    macStyle=0,
-    lowestRecPPEM=3,
-    fontDirectionHint=2,
-    indexToLocFormat=0,
-    glyphDataFormat=0,
+    tableVersion = 1.0,
+    fontRevision = 1.0,
+    checkSumAdjustment = 0,
+    magicNumber = 0x5F0F3CF5,
+    flags = 0x0003,
+    unitsPerEm = 1000,
+    created = 0,
+    modified = 0,
+    xMin = 0,
+    yMin = 0,
+    xMax = 0,
+    yMax = 0,
+    macStyle = 0,
+    lowestRecPPEM = 3,
+    fontDirectionHint = 2,
+    indexToLocFormat = 0,
+    glyphDataFormat = 0,
 )
 
 _maxpDefaultsTTF = dict(
-    tableVersion=0x00010000,
-    numGlyphs=0,
-    maxPoints=0,
-    maxContours=0,
-    maxCompositePoints=0,
-    maxCompositeContours=0,
-    maxZones=2,
-    maxTwilightPoints=0,
-    maxStorage=0,
-    maxFunctionDefs=0,
-    maxInstructionDefs=0,
-    maxStackElements=0,
-    maxSizeOfInstructions=0,
-    maxComponentElements=0,
-    maxComponentDepth=0,
+    tableVersion = 0x00010000,
+    numGlyphs = 0,
+    maxPoints = 0,
+    maxContours = 0,
+    maxCompositePoints = 0,
+    maxCompositeContours = 0,
+    maxZones = 2,
+    maxTwilightPoints = 0,
+    maxStorage = 0,
+    maxFunctionDefs = 0,
+    maxInstructionDefs = 0,
+    maxStackElements = 0,
+    maxSizeOfInstructions = 0,
+    maxComponentElements = 0,
+    maxComponentDepth = 0,
 )
 _maxpDefaultsOTF = dict(
-    tableVersion=0x00005000,
-    numGlyphs=0,
+    tableVersion = 0x00005000,
+    numGlyphs = 0,
 )
 
 _postDefaults = dict(
-    formatType=3.0,
-    italicAngle=0,
-    underlinePosition=0,
-    underlineThickness=0,
-    isFixedPitch=0,
-    minMemType42=0,
-    maxMemType42=0,
-    minMemType1=0,
-    maxMemType1=0,
+    formatType = 3.0,
+    italicAngle = 0,
+    underlinePosition = 0,
+    underlineThickness = 0,
+    isFixedPitch = 0,
+    minMemType42 = 0,
+    maxMemType42 = 0,
+    minMemType1 = 0,
+    maxMemType1 = 0,
 )
 
 _hheaDefaults = dict(
-    tableVersion=0x00010000,
-    ascent=0,
-    descent=0,
-    lineGap=0,
-    advanceWidthMax=0,
-    minLeftSideBearing=0,
-    minRightSideBearing=0,
-    xMaxExtent=0,
-    caretSlopeRise=1,
-    caretSlopeRun=0,
-    caretOffset=0,
-    reserved0=0,
-    reserved1=0,
-    reserved2=0,
-    reserved3=0,
-    metricDataFormat=0,
-    numberOfHMetrics=0,
+    tableVersion = 0x00010000,
+    ascent = 0,
+    descent = 0,
+    lineGap = 0,
+    advanceWidthMax = 0,
+    minLeftSideBearing = 0,
+    minRightSideBearing = 0,
+    xMaxExtent = 0,
+    caretSlopeRise = 1,
+    caretSlopeRun = 0,
+    caretOffset = 0,
+    reserved0 = 0,
+    reserved1 = 0,
+    reserved2 = 0,
+    reserved3 = 0,
+    metricDataFormat = 0,
+    numberOfHMetrics = 0,
 )
 
 _vheaDefaults = dict(
-    tableVersion=0x00010000,
-    ascent=0,
-    descent=0,
-    lineGap=0,
-    advanceHeightMax=0,
-    minTopSideBearing=0,
-    minBottomSideBearing=0,
-    yMaxExtent=0,
-    caretSlopeRise=0,
-    caretSlopeRun=0,
-    reserved0=0,
-    reserved1=0,
-    reserved2=0,
-    reserved3=0,
-    reserved4=0,
-    metricDataFormat=0,
-    numberOfVMetrics=0,
+    tableVersion = 0x00010000,
+    ascent = 0,
+    descent = 0,
+    lineGap = 0,
+    advanceHeightMax = 0,
+    minTopSideBearing = 0,
+    minBottomSideBearing = 0,
+    yMaxExtent = 0,
+    caretSlopeRise = 0,
+    caretSlopeRun = 0,
+    reserved0 = 0,
+    reserved1 = 0,
+    reserved2 = 0,
+    reserved3 = 0,
+    reserved4 = 0,
+    metricDataFormat = 0,
+    numberOfVMetrics = 0,
 )
 
 _nameIDs = dict(
-    copyright=0,
-    familyName=1,
-    styleName=2,
-    uniqueFontIdentifier=3,
-    fullName=4,
-    version=5,
-    psName=6,
-    trademark=7,
-    manufacturer=8,
-    designer=9,
-    description=10,
-    vendorURL=11,
-    designerURL=12,
-    licenseDescription=13,
-    licenseInfoURL=14,
-    # reserved = 15,
-    typographicFamily=16,
-    typographicSubfamily=17,
-    compatibleFullName=18,
-    sampleText=19,
-    postScriptCIDFindfontName=20,
-    wwsFamilyName=21,
-    wwsSubfamilyName=22,
-    lightBackgroundPalette=23,
-    darkBackgroundPalette=24,
-    variationsPostScriptNamePrefix=25,
+                         copyright = 0,
+                        familyName = 1,
+                         styleName = 2,
+              uniqueFontIdentifier = 3,
+                          fullName = 4,
+                           version = 5,
+                            psName = 6,
+                         trademark = 7,
+                      manufacturer = 8,
+                          designer = 9,
+                       description = 10,
+                         vendorURL = 11,
+                       designerURL = 12,
+                licenseDescription = 13,
+                    licenseInfoURL = 14,
+                        # reserved = 15,
+                 typographicFamily = 16,
+              typographicSubfamily = 17,
+                compatibleFullName = 18,
+                        sampleText = 19,
+         postScriptCIDFindfontName = 20,
+                     wwsFamilyName = 21,
+                  wwsSubfamilyName = 22,
+            lightBackgroundPalette = 23,
+             darkBackgroundPalette = 24,
+    variationsPostScriptNamePrefix = 25,
 )
 
 # to insert in setupNameTable doc string:
 # print("\n".join(("%s (nameID %s)" % (k, v)) for k, v in sorted(_nameIDs.items(), key=lambda x: x[1])))
 
 _panoseDefaults = dict(
-    bFamilyType=0,
-    bSerifStyle=0,
-    bWeight=0,
-    bProportion=0,
-    bContrast=0,
-    bStrokeVariation=0,
-    bArmStyle=0,
-    bLetterForm=0,
-    bMidline=0,
-    bXHeight=0,
+    bFamilyType = 0,
+    bSerifStyle = 0,
+    bWeight = 0,
+    bProportion = 0,
+    bContrast = 0,
+    bStrokeVariation = 0,
+    bArmStyle = 0,
+    bLetterForm = 0,
+    bMidline = 0,
+    bXHeight = 0,
 )
 
 _OS2Defaults = dict(
-    version=3,
-    xAvgCharWidth=0,
-    usWeightClass=400,
-    usWidthClass=5,
-    fsType=0x0004,  # default: Preview & Print embedding
-    ySubscriptXSize=0,
-    ySubscriptYSize=0,
-    ySubscriptXOffset=0,
-    ySubscriptYOffset=0,
-    ySuperscriptXSize=0,
-    ySuperscriptYSize=0,
-    ySuperscriptXOffset=0,
-    ySuperscriptYOffset=0,
-    yStrikeoutSize=0,
-    yStrikeoutPosition=0,
-    sFamilyClass=0,
-    panose=_panoseDefaults,
-    ulUnicodeRange1=0,
-    ulUnicodeRange2=0,
-    ulUnicodeRange3=0,
-    ulUnicodeRange4=0,
-    achVendID="????",
-    fsSelection=0,
-    usFirstCharIndex=0,
-    usLastCharIndex=0,
-    sTypoAscender=0,
-    sTypoDescender=0,
-    sTypoLineGap=0,
-    usWinAscent=0,
-    usWinDescent=0,
-    ulCodePageRange1=0,
-    ulCodePageRange2=0,
-    sxHeight=0,
-    sCapHeight=0,
-    usDefaultChar=0,  # .notdef
-    usBreakChar=32,  # space
-    usMaxContext=0,
-    usLowerOpticalPointSize=0,
-    usUpperOpticalPointSize=0,
+    version = 3,
+    xAvgCharWidth = 0,
+    usWeightClass = 400,
+    usWidthClass = 5,
+    fsType = 0x0004,  # default: Preview & Print embedding
+    ySubscriptXSize = 0,
+    ySubscriptYSize = 0,
+    ySubscriptXOffset = 0,
+    ySubscriptYOffset = 0,
+    ySuperscriptXSize = 0,
+    ySuperscriptYSize = 0,
+    ySuperscriptXOffset = 0,
+    ySuperscriptYOffset = 0,
+    yStrikeoutSize = 0,
+    yStrikeoutPosition = 0,
+    sFamilyClass = 0,
+    panose = _panoseDefaults,
+    ulUnicodeRange1 = 0,
+    ulUnicodeRange2 = 0,
+    ulUnicodeRange3 = 0,
+    ulUnicodeRange4 = 0,
+    achVendID = "????",
+    fsSelection = 0,
+    usFirstCharIndex = 0,
+    usLastCharIndex = 0,
+    sTypoAscender = 0,
+    sTypoDescender = 0,
+    sTypoLineGap = 0,
+    usWinAscent = 0,
+    usWinDescent = 0,
+    ulCodePageRange1 = 0,
+    ulCodePageRange2 = 0,
+    sxHeight = 0,
+    sCapHeight = 0,
+    usDefaultChar = 0,  # .notdef
+    usBreakChar = 32,   # space
+    usMaxContext = 0,
+    usLowerOpticalPointSize = 0,
+    usUpperOpticalPointSize = 0,
 )
 
 
 class FontBuilder(object):
+
     def __init__(self, unitsPerEm=None, font=None, isTTF=True):
         """Initialize a FontBuilder instance.
 
@@ -392,7 +397,7 @@
         """
         subTables = []
         highestUnicode = max(cmapping)
-        if highestUnicode > 0xFFFF:
+        if highestUnicode > 0xffff:
             cmapping_3_1 = dict((k, v) for k, v in cmapping.items() if k < 0x10000)
             subTable_3_10 = buildCmapSubTable(cmapping, 12, 3, 10)
             subTables.append(subTable_3_10)
@@ -405,9 +410,7 @@
         except struct.error:
             # format 4 overflowed, fall back to format 12
             if not allowFallback:
-                raise ValueError(
-                    "cmap format 4 subtable overflowed; sort glyph order by unicode to fix."
-                )
+                raise ValueError("cmap format 4 subtable overflowed; sort glyph order by unicode to fix.")
             format = 12
             subTable_3_1 = buildCmapSubTable(cmapping_3_1, format, 3, 1)
         subTables.append(subTable_3_1)
@@ -476,7 +479,7 @@
                 nameID = nameName
             else:
                 nameID = _nameIDs[nameName]
-            if isinstance(nameValue, str):
+            if isinstance(nameValue, basestring):
                 nameValue = dict(en=nameValue)
             nameTable.addMultilingualName(
                 nameValue, ttFont=self.font, nameID=nameID, windows=windows, mac=mac
@@ -488,40 +491,23 @@
         """
         if "xAvgCharWidth" not in values:
             gs = self.font.getGlyphSet()
-            widths = [
-                gs[glyphName].width
-                for glyphName in gs.keys()
-                if gs[glyphName].width > 0
-            ]
+            widths = [gs[glyphName].width for glyphName in gs.keys() if gs[glyphName].width > 0]
             values["xAvgCharWidth"] = int(round(sum(widths) / float(len(widths))))
         self._initTableWithValues("OS/2", _OS2Defaults, values)
-        if not (
-            "ulUnicodeRange1" in values
-            or "ulUnicodeRange2" in values
-            or "ulUnicodeRange3" in values
-            or "ulUnicodeRange3" in values
-        ):
-            assert (
-                "cmap" in self.font
-            ), "the 'cmap' table must be setup before the 'OS/2' table"
+        if not ("ulUnicodeRange1" in values or "ulUnicodeRange2" in values or
+                "ulUnicodeRange3" in values or "ulUnicodeRange3" in values):
+            assert "cmap" in self.font, "the 'cmap' table must be setup before the 'OS/2' table"
             self.font["OS/2"].recalcUnicodeRanges(self.font)
 
     def setupCFF(self, psName, fontInfo, charStringsDict, privateDict):
-        from .cffLib import (
-            CFFFontSet,
-            TopDictIndex,
-            TopDict,
-            CharStrings,
-            GlobalSubrsIndex,
-            PrivateDict,
-        )
+        from .cffLib import CFFFontSet, TopDictIndex, TopDict, CharStrings, \
+                GlobalSubrsIndex, PrivateDict
 
         assert not self.isTTF
         self.font.sfntVersion = "OTTO"
         fontSet = CFFFontSet()
         fontSet.major = 1
         fontSet.minor = 0
-        fontSet.otFont = self.font
         fontSet.fontNames = [psName]
         fontSet.topDictIndex = TopDictIndex()
 
@@ -536,16 +522,13 @@
         topDict = TopDict()
         topDict.charset = self.font.getGlyphOrder()
         topDict.Private = private
-        topDict.GlobalSubrs = fontSet.GlobalSubrs
         for key, value in fontInfo.items():
             setattr(topDict, key, value)
         if "FontMatrix" not in fontInfo:
             scale = 1 / self.font["head"].unitsPerEm
             topDict.FontMatrix = [scale, 0, 0, scale, 0, 0]
 
-        charStrings = CharStrings(
-            None, topDict.charset, globalSubrs, private, fdSelect, fdArray
-        )
+        charStrings = CharStrings(None, topDict.charset, globalSubrs, private, fdSelect, fdArray)
         for glyphName, charString in charStringsDict.items():
             charString.private = private
             charString.globalSubrs = globalSubrs
@@ -558,16 +541,8 @@
         self.font["CFF "].cff = fontSet
 
     def setupCFF2(self, charStringsDict, fdArrayList=None, regions=None):
-        from .cffLib import (
-            CFFFontSet,
-            TopDictIndex,
-            TopDict,
-            CharStrings,
-            GlobalSubrsIndex,
-            PrivateDict,
-            FDArrayIndex,
-            FontDict,
-        )
+        from .cffLib import CFFFontSet, TopDictIndex, TopDict, CharStrings, \
+                GlobalSubrsIndex, PrivateDict, FDArrayIndex, FontDict
 
         assert not self.isTTF
         self.font.sfntVersion = "OTTO"
@@ -629,10 +604,7 @@
         varData = buildVarData(list(range(len(regions))), None, optimize=False)
         varStore = buildVarStore(varRegionList, [varData])
         vstore = VarStoreData(otVarStore=varStore)
-        topDict = self.font["CFF2"].cff.topDictIndex[0]
-        topDict.VarStore = vstore
-        for fontDict in topDict.FDArray:
-            fontDict.Private.vstore = vstore
+        self.font["CFF2"].cff.topDictIndex[0].VarStore = vstore
 
     def setupGlyf(self, glyphs, calcGlyphBounds=True):
         """Create the `glyf` table from a dict, that maps glyph names
@@ -653,40 +625,10 @@
             self.calcGlyphBounds()
 
     def setupFvar(self, axes, instances):
-        """Adds an font variations table to the font.
-
-        Args:
-            axes (list): See below.
-            instances (list): See below.
-
-        ``axes`` should be a list of axes, with each axis either supplied as
-        a py:class:`.designspaceLib.AxisDescriptor` object, or a tuple in the
-        format ```tupletag, minValue, defaultValue, maxValue, name``.
-        The ``name`` is either a string, or a dict, mapping language codes
-        to strings, to allow localized name table entries.
-
-        ```instances`` should be a list of instances, with each instance either
-        supplied as a py:class:`.designspaceLib.InstanceDescriptor` object, or a
-        dict with keys ``location`` (mapping of axis tags to float values),
-        ``stylename`` and (optionally) ``postscriptfontname``.
-        The ``stylename`` is either a string, or a dict, mapping language codes
-        to strings, to allow localized name table entries.
-        """
-
         addFvar(self.font, axes, instances)
 
-    def setupAvar(self, axes):
-        """Adds an axis variations table to the font.
-
-        Args:
-            axes (list): A list of py:class:`.designspaceLib.AxisDescriptor` objects.
-        """
-        from .varLib import _add_avar
-
-        _add_avar(self.font, OrderedDict(enumerate(axes)))  # Only values are used
-
     def setupGvar(self, variations):
-        gvar = self.font["gvar"] = newTable("gvar")
+        gvar = self.font["gvar"] = newTable('gvar')
         gvar.version = 1
         gvar.reserved = 0
         gvar.variations = variations
@@ -705,7 +647,7 @@
         The `metrics` argument must be a dict, mapping glyph names to
         `(width, leftSidebearing)` tuples.
         """
-        self.setupMetrics("hmtx", metrics)
+        self.setupMetrics('hmtx', metrics)
 
     def setupVerticalMetrics(self, metrics):
         """Create a new `vmtx` table, for horizontal metrics.
@@ -713,7 +655,7 @@
         The `metrics` argument must be a dict, mapping glyph names to
         `(height, topSidebearing)` tuples.
         """
-        self.setupMetrics("vmtx", metrics)
+        self.setupMetrics('vmtx', metrics)
 
     def setupMetrics(self, tableTag, metrics):
         """See `setupHorizontalMetrics()` and `setupVerticalMetrics()`."""
@@ -754,14 +696,8 @@
                     bag[vorg] = 1
                 else:
                     bag[vorg] += 1
-            defaultVerticalOrigin = sorted(
-                bag, key=lambda vorg: bag[vorg], reverse=True
-            )[0]
-        self._initTableWithValues(
-            "VORG",
-            {},
-            dict(VOriginRecords={}, defaultVertOriginY=defaultVerticalOrigin),
-        )
+            defaultVerticalOrigin = sorted(bag, key=lambda vorg: bag[vorg], reverse=True)[0]
+        self._initTableWithValues("VORG", {}, dict(VOriginRecords={}, defaultVertOriginY=defaultVerticalOrigin))
         vorgTable = self.font["VORG"]
         vorgTable.majorVersion = 1
         vorgTable.minorVersion = 0
@@ -772,7 +708,7 @@
         """Create a new `post` table and initialize it with default values,
         which can be overridden by keyword arguments.
         """
-        isCFF2 = "CFF2" in self.font
+        isCFF2 = 'CFF2' in self.font
         postTable = self._initTableWithValues("post", _postDefaults, values)
         if (self.isTTF or isCFF2) and keepGlyphNames:
             postTable.formatType = 2.0
@@ -796,10 +732,10 @@
         happy. This does not properly sign the font.
         """
         values = dict(
-            ulVersion=1,
-            usFlag=0,
-            usNumSigs=0,
-            signatureRecords=[],
+            ulVersion = 1,
+            usFlag = 0,
+            usNumSigs = 0,
+            signatureRecords = [],
         )
         self._initTableWithValues("DSIG", {}, values)
 
@@ -815,70 +751,7 @@
         `fontTools.feaLib` for details.
         """
         from .feaLib.builder import addOpenTypeFeaturesFromString
-
-        addOpenTypeFeaturesFromString(
-            self.font, features, filename=filename, tables=tables
-        )
-
-    def addFeatureVariations(self, conditionalSubstitutions, featureTag="rvrn"):
-        """Add conditional substitutions to a Variable Font.
-
-        See `fontTools.varLib.featureVars.addFeatureVariations`.
-        """
-        from .varLib import featureVars
-
-        if "fvar" not in self.font:
-            raise KeyError("'fvar' table is missing; can't add FeatureVariations.")
-
-        featureVars.addFeatureVariations(
-            self.font, conditionalSubstitutions, featureTag=featureTag
-        )
-
-    def setupCOLR(self, colorLayers, version=None, varStore=None):
-        """Build new COLR table using color layers dictionary.
-
-        Cf. `fontTools.colorLib.builder.buildCOLR`.
-        """
-        from fontTools.colorLib.builder import buildCOLR
-
-        glyphMap = self.font.getReverseGlyphMap()
-        self.font["COLR"] = buildCOLR(
-            colorLayers, version=version, glyphMap=glyphMap, varStore=varStore
-        )
-
-    def setupCPAL(
-        self,
-        palettes,
-        paletteTypes=None,
-        paletteLabels=None,
-        paletteEntryLabels=None,
-    ):
-        """Build new CPAL table using list of palettes.
-
-        Optionally build CPAL v1 table using paletteTypes, paletteLabels and
-        paletteEntryLabels.
-
-        Cf. `fontTools.colorLib.builder.buildCPAL`.
-        """
-        from fontTools.colorLib.builder import buildCPAL
-
-        self.font["CPAL"] = buildCPAL(
-            palettes,
-            paletteTypes=paletteTypes,
-            paletteLabels=paletteLabels,
-            paletteEntryLabels=paletteEntryLabels,
-            nameTable=self.font.get("name"),
-        )
-
-    def setupStat(self, axes, locations=None, elidedFallbackName=2):
-        """Build a new 'STAT' table.
-
-        See `fontTools.otlLib.builder.buildStatTable` for details about
-        the arguments.
-        """
-        from .otlLib.builder import buildStatTable
-
-        buildStatTable(self.font, axes, locations, elidedFallbackName)
+        addOpenTypeFeaturesFromString(self.font, features, filename=filename, tables=tables)
 
 
 def buildCmapSubTable(cmapping, format, platformID, platEncID):
@@ -891,57 +764,32 @@
 
 
 def addFvar(font, axes, instances):
+    from .misc.py23 import Tag, tounicode
     from .ttLib.tables._f_v_a_r import Axis, NamedInstance
 
     assert axes
 
-    fvar = newTable("fvar")
-    nameTable = font["name"]
+    fvar = newTable('fvar')
+    nameTable = font['name']
 
-    for axis_def in axes:
+    for tag, minValue, defaultValue, maxValue, name in axes:
         axis = Axis()
-
-        if isinstance(axis_def, tuple):
-            (
-                axis.axisTag,
-                axis.minValue,
-                axis.defaultValue,
-                axis.maxValue,
-                name,
-            ) = axis_def
-        else:
-            (axis.axisTag, axis.minValue, axis.defaultValue, axis.maxValue, name) = (
-                axis_def.tag,
-                axis_def.minimum,
-                axis_def.default,
-                axis_def.maximum,
-                axis_def.name,
-            )
-
-        if isinstance(name, str):
-            name = dict(en=name)
-
-        axis.axisNameID = nameTable.addMultilingualName(name, ttFont=font)
+        axis.axisTag = Tag(tag)
+        axis.minValue, axis.defaultValue, axis.maxValue = minValue, defaultValue, maxValue
+        axis.axisNameID = nameTable.addName(tounicode(name))
         fvar.axes.append(axis)
 
     for instance in instances:
-        if isinstance(instance, dict):
-            coordinates = instance["location"]
-            name = instance["stylename"]
-            psname = instance.get("postscriptfontname")
-        else:
-            coordinates = instance.location
-            name = instance.localisedStyleName or instance.styleName
-            psname = instance.postScriptFontName
-
-        if isinstance(name, str):
-            name = dict(en=name)
+        coordinates = instance['location']
+        name = tounicode(instance['stylename'])
+        psname = instance.get('postscriptfontname')
 
         inst = NamedInstance()
-        inst.subfamilyNameID = nameTable.addMultilingualName(name, ttFont=font)
+        inst.subfamilyNameID = nameTable.addName(name)
         if psname is not None:
+            psname = tounicode(psname)
             inst.postscriptNameID = nameTable.addName(psname)
         inst.coordinates = coordinates
         fvar.instances.append(inst)
 
-    font["fvar"] = fvar
+    font['fvar'] = fvar
diff --git a/Lib/fontTools/help.py b/Lib/fontTools/help.py
deleted file mode 100644
index ff8048d..0000000
--- a/Lib/fontTools/help.py
+++ /dev/null
@@ -1,34 +0,0 @@
-import pkgutil
-import sys
-import fontTools
-import importlib
-import os
-from pathlib import Path
-
-
-def main():
-    """Show this help"""
-    path = fontTools.__path__
-    descriptions = {}
-    for pkg in sorted(
-        mod.name
-        for mod in pkgutil.walk_packages([fontTools.__path__[0]], prefix="fontTools.")
-    ):
-        try:
-            imports = __import__(pkg, globals(), locals(), ["main"])
-        except ImportError as e:
-            continue
-        try:
-            description = imports.main.__doc__
-            if description:
-                pkg = pkg.replace("fontTools.", "").replace(".__main__", "")
-                descriptions[pkg] = description
-        except AttributeError as e:
-            pass
-    for pkg, description in descriptions.items():
-        print("fonttools %-12s %s" % (pkg, description), file=sys.stderr)
-
-
-if __name__ == "__main__":
-    print("fonttools v%s\n" % fontTools.__version__, file=sys.stderr)
-    main()
diff --git a/Lib/fontTools/merge.py b/Lib/fontTools/merge.py
index 2df22a8..36ac756 100644
--- a/Lib/fontTools/merge.py
+++ b/Lib/fontTools/merge.py
@@ -2,6 +2,11 @@
 #
 # Google Author(s): Behdad Esfahbod, Roozbeh Pournader
 
+"""Font merger.
+"""
+
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.timeTools import timestampNow
 from fontTools import ttLib, cffLib
 from fontTools.ttLib.tables import otTables, _h_e_a_d
@@ -290,18 +295,11 @@
 	'sTypoLineGap': max,
 	'usWinAscent': max,
 	'usWinDescent': max,
-	# Version 1
+	# Version 2,3,4
 	'ulCodePageRange1': onlyExisting(bitwise_or),
 	'ulCodePageRange2': onlyExisting(bitwise_or),
-	# Version 2, 3, 4
-	'sxHeight': onlyExisting(max),
-	'sCapHeight': onlyExisting(max),
-	'usDefaultChar': onlyExisting(first),
-	'usBreakChar': onlyExisting(first),
-	'usMaxContext': onlyExisting(max),
-	# version 5
-	'usLowerOpticalPointSize': onlyExisting(min),
-	'usUpperOpticalPointSize': onlyExisting(max),
+	'usMaxContex': onlyExisting(max),
+	# TODO version 5
 }
 
 @_add_method(ttLib.getTableClass('OS/2'))
@@ -741,12 +739,12 @@
 
 	if self.Format not in [1, 2, 3]:
 		return None  # Don't shoot the messenger; let it go
-	if not hasattr(self.__class__, "_merge__ContextHelpers"):
-		self.__class__._merge__ContextHelpers = {}
-	if self.Format not in self.__class__._merge__ContextHelpers:
+	if not hasattr(self.__class__, "__ContextHelpers"):
+		self.__class__.__ContextHelpers = {}
+	if self.Format not in self.__class__.__ContextHelpers:
 		helper = ContextHelper(self.__class__, self.Format)
-		self.__class__._merge__ContextHelpers[self.Format] = helper
-	return self.__class__._merge__ContextHelpers[self.Format]
+		self.__class__.__ContextHelpers[self.Format] = helper
+	return self.__class__.__ContextHelpers[self.Format]
 
 
 @_add_method(otTables.ContextSubst,
@@ -947,34 +945,6 @@
 		del self.d[id(k)]
 
 class Merger(object):
-	"""Font merger.
-
-	This class merges multiple files into a single OpenType font, taking into
-	account complexities such as OpenType layout (``GSUB``/``GPOS``) tables and
-	cross-font metrics (e.g. ``hhea.ascent`` is set to the maximum value across
-	all the fonts).
-
-	If multiple glyphs map to the same Unicode value, and the glyphs are considered
-	sufficiently different (that is, they differ in any of paths, widths, or
-	height), then subsequent glyphs are renamed and a lookup in the ``locl``
-	feature will be created to disambiguate them. For example, if the arguments
-	are an Arabic font and a Latin font and both contain a set of parentheses,
-	the Latin glyphs will be renamed to ``parenleft#1`` and ``parenright#1``,
-	and a lookup will be inserted into the to ``locl`` feature (creating it if
-	necessary) under the ``latn`` script to substitute ``parenleft`` with
-	``parenleft#1`` etc.
-
-	Restrictions:
-
-	- All fonts must currently have TrueType outlines (``glyf`` table).
-		Merging fonts with CFF outlines is not supported.
-	- All fonts must have the same units per em.
-	- If duplicate glyph disambiguation takes place as described above then the
-		fonts must have a ``GSUB`` table.
-
-	Attributes:
-		options: Currently unused.
-	"""
 
 	def __init__(self, options=None):
 
@@ -984,15 +954,7 @@
 		self.options = options
 
 	def merge(self, fontfiles):
-		"""Merges fonts together.
 
-		Args:
-			fontfiles: A list of file names to be merged
-
-		Returns:
-			A :class:`fontTools.ttLib.TTFont` object. Call the ``save`` method on
-			this to write it out to an OTF file.
-		"""
 		mega = ttLib.TTFont()
 
 		#
@@ -1013,7 +975,7 @@
 			self._preMerge(font)
 
 		self.fonts = fonts
-		self.duplicateGlyphsPerFont = [{} for _ in fonts]
+		self.duplicateGlyphsPerFont = [{} for f in fonts]
 
 		allTags = reduce(set.union, (list(font.keys()) for font in fonts), set())
 		allTags.remove('GlyphOrder')
@@ -1051,18 +1013,16 @@
 	def _mergeGlyphOrders(self, glyphOrders):
 		"""Modifies passed-in glyphOrders to reflect new glyph names.
 		Returns glyphOrder for the merged font."""
-		mega = {}
-		for glyphOrder in glyphOrders:
+		# Simply append font index to the glyph name for now.
+		# TODO Even this simplistic numbering can result in conflicts.
+		# But then again, we have to improve this soon anyway.
+		mega = []
+		for n,glyphOrder in enumerate(glyphOrders):
 			for i,glyphName in enumerate(glyphOrder):
-				if glyphName in mega:
-					n = mega[glyphName]
-					while (glyphName + "#" + repr(n)) in mega:
-						n += 1
-					mega[glyphName] = n
-					glyphName += "#" + repr(n)
-					glyphOrder[i] = glyphName
-				mega[glyphName] = 1
-		return list(mega.keys())
+				glyphName += "#" + repr(n)
+				glyphOrder[i] = glyphName
+				mega.append(glyphName)
+		return mega
 
 	def mergeObjects(self, returnTable, logic, tables):
 		# Right now we don't use self at all.  Will use in the future
@@ -1175,7 +1135,6 @@
 
 @timer("make one with everything (TOTAL TIME)")
 def main(args=None):
-	"""Merge multiple fonts into one"""
 	from fontTools import configLogger
 
 	if args is None:
diff --git a/Lib/fontTools/misc/__init__.py b/Lib/fontTools/misc/__init__.py
index 156cb23..3f9abc9 100644
--- a/Lib/fontTools/misc/__init__.py
+++ b/Lib/fontTools/misc/__init__.py
@@ -1 +1,4 @@
 """Empty __init__.py file to signal Python this directory is a package."""
+
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
diff --git a/Lib/fontTools/misc/arrayTools.py b/Lib/fontTools/misc/arrayTools.py
index c20a9ed..ed20230 100644
--- a/Lib/fontTools/misc/arrayTools.py
+++ b/Lib/fontTools/misc/arrayTools.py
@@ -1,21 +1,19 @@
-"""Routines for calculating bounding boxes, point in rectangle calculations and
-so on.
-"""
+#
+# Various array and rectangle tools, but mostly rectangles, hence the
+# name of this module (not).
+#
 
-from fontTools.misc.roundTools import otRound
-from fontTools.misc.vector import Vector as _Vector
+
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools.misc.fixedTools import otRound
+from numbers import Number
 import math
-import warnings
-
+import operator
 
 def calcBounds(array):
-    """Calculate the bounding rectangle of a 2D points array.
-
-    Args:
-        array: A sequence of 2D tuples.
-
-    Returns:
-        A four-item tuple representing the bounding rectangle ``(xMin, yMin, xMax, yMax)``.
+    """Return the bounding rectangle of a 2D points array as a tuple:
+    (xMin, yMin, xMax, yMax)
     """
     if len(array) == 0:
         return 0, 0, 0, 0
@@ -24,64 +22,29 @@
     return min(xs), min(ys), max(xs), max(ys)
 
 def calcIntBounds(array, round=otRound):
-    """Calculate the integer bounding rectangle of a 2D points array.
-
-    Values are rounded to closest integer towards ``+Infinity`` using the
-    :func:`fontTools.misc.fixedTools.otRound` function by default, unless
-    an optional ``round`` function is passed.
-
-    Args:
-        array: A sequence of 2D tuples.
-        round: A rounding function of type ``f(x: float) -> int``.
-
-    Returns:
-        A four-item tuple of integers representing the bounding rectangle:
-        ``(xMin, yMin, xMax, yMax)``.
+    """Return the integer bounding rectangle of a 2D points array as a
+    tuple: (xMin, yMin, xMax, yMax)
+    Values are rounded to closest integer towards +Infinity using otRound
+    function by default, unless an optional 'round' function is passed.
     """
     return tuple(round(v) for v in calcBounds(array))
 
 
 def updateBounds(bounds, p, min=min, max=max):
-    """Add a point to a bounding rectangle.
-
-    Args:
-        bounds: A bounding rectangle expressed as a tuple
-            ``(xMin, yMin, xMax, yMax)``.
-        p: A 2D tuple representing a point.
-        min,max: functions to compute the minimum and maximum.
-
-    Returns:
-        The updated bounding rectangle ``(xMin, yMin, xMax, yMax)``.
-    """
+    """Return the bounding recangle of rectangle bounds and point (x, y)."""
     (x, y) = p
     xMin, yMin, xMax, yMax = bounds
     return min(xMin, x), min(yMin, y), max(xMax, x), max(yMax, y)
 
 def pointInRect(p, rect):
-    """Test if a point is inside a bounding rectangle.
-
-    Args:
-        p: A 2D tuple representing a point.
-        rect: A bounding rectangle expressed as a tuple
-            ``(xMin, yMin, xMax, yMax)``.
-
-    Returns:
-        ``True`` if the point is inside the rectangle, ``False`` otherwise.
-    """
+    """Return True when point (x, y) is inside rect."""
     (x, y) = p
     xMin, yMin, xMax, yMax = rect
     return (xMin <= x <= xMax) and (yMin <= y <= yMax)
 
 def pointsInRect(array, rect):
-    """Determine which points are inside a bounding rectangle.
-
-    Args:
-        array: A sequence of 2D tuples.
-        rect: A bounding rectangle expressed as a tuple
-            ``(xMin, yMin, xMax, yMax)``.
-
-    Returns:
-        A list containing the points inside the rectangle.
+    """Find out which points or array are inside rect.
+    Returns an array with a boolean for each point.
     """
     if len(array) < 1:
         return []
@@ -89,105 +52,41 @@
     return [(xMin <= x <= xMax) and (yMin <= y <= yMax) for x, y in array]
 
 def vectorLength(vector):
-    """Calculate the length of the given vector.
-
-    Args:
-        vector: A 2D tuple.
-
-    Returns:
-        The Euclidean length of the vector.
-    """
+    """Return the length of the given vector."""
     x, y = vector
     return math.sqrt(x**2 + y**2)
 
 def asInt16(array):
-    """Round a list of floats to 16-bit signed integers.
-
-    Args:
-        array: List of float values.
-
-    Returns:
-        A list of rounded integers.
-    """
+    """Round and cast to 16 bit integer."""
     return [int(math.floor(i+0.5)) for i in array]
 
 
 def normRect(rect):
-    """Normalize a bounding box rectangle.
-
-    This function "turns the rectangle the right way up", so that the following
-    holds::
-
+    """Normalize the rectangle so that the following holds:
         xMin <= xMax and yMin <= yMax
-
-    Args:
-        rect: A bounding rectangle expressed as a tuple
-            ``(xMin, yMin, xMax, yMax)``.
-
-    Returns:
-        A normalized bounding rectangle.
     """
     (xMin, yMin, xMax, yMax) = rect
     return min(xMin, xMax), min(yMin, yMax), max(xMin, xMax), max(yMin, yMax)
 
 def scaleRect(rect, x, y):
-    """Scale a bounding box rectangle.
-
-    Args:
-        rect: A bounding rectangle expressed as a tuple
-            ``(xMin, yMin, xMax, yMax)``.
-        x: Factor to scale the rectangle along the X axis.
-        Y: Factor to scale the rectangle along the Y axis.
-
-    Returns:
-        A scaled bounding rectangle.
-    """
+    """Scale the rectangle by x, y."""
     (xMin, yMin, xMax, yMax) = rect
     return xMin * x, yMin * y, xMax * x, yMax * y
 
 def offsetRect(rect, dx, dy):
-    """Offset a bounding box rectangle.
-
-    Args:
-        rect: A bounding rectangle expressed as a tuple
-            ``(xMin, yMin, xMax, yMax)``.
-        dx: Amount to offset the rectangle along the X axis.
-        dY: Amount to offset the rectangle along the Y axis.
-
-    Returns:
-        An offset bounding rectangle.
-    """
+    """Offset the rectangle by dx, dy."""
     (xMin, yMin, xMax, yMax) = rect
     return xMin+dx, yMin+dy, xMax+dx, yMax+dy
 
 def insetRect(rect, dx, dy):
-    """Inset a bounding box rectangle on all sides.
-
-    Args:
-        rect: A bounding rectangle expressed as a tuple
-            ``(xMin, yMin, xMax, yMax)``.
-        dx: Amount to inset the rectangle along the X axis.
-        dY: Amount to inset the rectangle along the Y axis.
-
-    Returns:
-        An inset bounding rectangle.
-    """
+    """Inset the rectangle by dx, dy on all sides."""
     (xMin, yMin, xMax, yMax) = rect
     return xMin+dx, yMin+dy, xMax-dx, yMax-dy
 
 def sectRect(rect1, rect2):
-    """Test for rectangle-rectangle intersection.
-
-    Args:
-        rect1: First bounding rectangle, expressed as tuples
-            ``(xMin, yMin, xMax, yMax)``.
-        rect2: Second bounding rectangle.
-
-    Returns:
-        A boolean and a rectangle.
-        If the input rectangles intersect, returns ``True`` and the intersecting
-        rectangle. Returns ``False`` and ``(0, 0, 0, 0)`` if the input
-        rectangles don't intersect.
+    """Return a boolean and a rectangle. If the input rectangles intersect, return
+    True and the intersecting rectangle. Return False and (0, 0, 0, 0) if the input
+    rectangles don't intersect.
     """
     (xMin1, yMin1, xMax1, yMax1) = rect1
     (xMin2, yMin2, xMax2, yMax2) = rect2
@@ -198,16 +97,9 @@
     return True, (xMin, yMin, xMax, yMax)
 
 def unionRect(rect1, rect2):
-    """Determine union of bounding rectangles.
-
-    Args:
-        rect1: First bounding rectangle, expressed as tuples
-            ``(xMin, yMin, xMax, yMax)``.
-        rect2: Second bounding rectangle.
-
-    Returns:
-        The smallest rectangle in which both input rectangles are fully
-        enclosed.
+    """Return the smallest rectangle in which both input rectangles are fully
+    enclosed. In other words, return the total bounding rectangle of both input
+    rectangles.
     """
     (xMin1, yMin1, xMax1, yMax1) = rect1
     (xMin2, yMin2, xMax2, yMax2) = rect2
@@ -215,45 +107,16 @@
                               max(xMax1, xMax2), max(yMax1, yMax2))
     return (xMin, yMin, xMax, yMax)
 
-def rectCenter(rect):
-    """Determine rectangle center.
-
-    Args:
-        rect: Bounding rectangle, expressed as tuples
-            ``(xMin, yMin, xMax, yMax)``.
-
-    Returns:
-        A 2D tuple representing the point at the center of the rectangle.
-    """
-    (xMin, yMin, xMax, yMax) = rect
+def rectCenter(rect0):
+    """Return the center of the rectangle as an (x, y) coordinate."""
+    (xMin, yMin, xMax, yMax) = rect0
     return (xMin+xMax)/2, (yMin+yMax)/2
 
-def rectArea(rect):
-    """Determine rectangle area.
-
-    Args:
-        rect: Bounding rectangle, expressed as tuples
-            ``(xMin, yMin, xMax, yMax)``.
-
-    Returns:
-        The area of the rectangle.
+def intRect(rect1):
+    """Return the rectangle, rounded off to integer values, but guaranteeing that
+    the resulting rectangle is NOT smaller than the original.
     """
-    (xMin, yMin, xMax, yMax) = rect
-    return (yMax - yMin) * (xMax - xMin)
-
-def intRect(rect):
-    """Round a rectangle to integer values.
-
-    Guarantees that the resulting rectangle is NOT smaller than the original.
-
-    Args:
-        rect: Bounding rectangle, expressed as tuples
-            ``(xMin, yMin, xMax, yMax)``.
-
-    Returns:
-        A rounded bounding rectangle.
-    """
-    (xMin, yMin, xMax, yMax) = rect
+    (xMin, yMin, xMax, yMax) = rect1
     xMin = int(math.floor(xMin))
     yMin = int(math.floor(yMin))
     xMax = int(math.ceil(xMax))
@@ -261,48 +124,121 @@
     return (xMin, yMin, xMax, yMax)
 
 
-class Vector(_Vector):
+class Vector(object):
+    """A math-like vector."""
 
-    def __init__(self, *args, **kwargs):
-        warnings.warn(
-            "fontTools.misc.arrayTools.Vector has been deprecated, please use "
-            "fontTools.misc.vector.Vector instead.",
-            DeprecationWarning,
-        )
+    def __init__(self, values, keep=False):
+        self.values = values if keep else list(values)
+
+    def __getitem__(self, index):
+        return self.values[index]
+
+    def __len__(self):
+        return len(self.values)
+
+    def __repr__(self):
+        return "Vector(%s)" % self.values
+
+    def _vectorOp(self, other, op):
+        if isinstance(other, Vector):
+            assert len(self.values) == len(other.values)
+            a = self.values
+            b = other.values
+            return [op(a[i], b[i]) for i in range(len(self.values))]
+        if isinstance(other, Number):
+            return [op(v, other) for v in self.values]
+        raise NotImplementedError
+
+    def _scalarOp(self, other, op):
+        if isinstance(other, Number):
+            return [op(v, other) for v in self.values]
+        raise NotImplementedError
+
+    def _unaryOp(self, op):
+        return [op(v) for v in self.values]
+
+    def __add__(self, other):
+        return Vector(self._vectorOp(other, operator.add), keep=True)
+    def __iadd__(self, other):
+        self.values = self._vectorOp(other, operator.add)
+        return self
+    __radd__ = __add__
+
+    def __sub__(self, other):
+        return Vector(self._vectorOp(other, operator.sub), keep=True)
+    def __isub__(self, other):
+        self.values = self._vectorOp(other, operator.sub)
+        return self
+    def __rsub__(self, other):
+        return other + (-self)
+
+    def __mul__(self, other):
+        return Vector(self._scalarOp(other, operator.mul), keep=True)
+    def __imul__(self, other):
+        self.values = self._scalarOp(other, operator.mul)
+        return self
+    __rmul__ = __mul__
+
+    def __truediv__(self, other):
+        return Vector(self._scalarOp(other, operator.div), keep=True)
+    def __itruediv__(self, other):
+        self.values = self._scalarOp(other, operator.div)
+        return self
+
+    def __pos__(self):
+        return Vector(self._unaryOp(operator.pos), keep=True)
+    def __neg__(self):
+        return Vector(self._unaryOp(operator.neg), keep=True)
+    def __round__(self):
+        return Vector(self._unaryOp(round), keep=True)
+    def toInt(self):
+        return self.__round__()
+
+    def __eq__(self, other):
+        if type(other) == Vector:
+            return self.values == other.values
+        else:
+            return self.values == other
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def __bool__(self):
+        return any(self.values)
+    __nonzero__ = __bool__
+
+    def __abs__(self):
+        return math.sqrt(sum([x*x for x in self.values]))
+    def dot(self, other):
+        a = self.values
+        b = other.values if type(other) == Vector else b
+        assert len(a) == len(b)
+        return sum([a[i] * b[i] for i in range(len(a))])
 
 
 def pairwise(iterable, reverse=False):
-    """Iterate over current and next items in iterable.
+    """Iterate over current and next items in iterable, optionally in
+    reverse order.
 
-    Args:
-        iterable: An iterable
-        reverse: If true, iterate in reverse order.
-
-    Returns:
-        A iterable yielding two elements per iteration.
-
-    Example:
-
-        >>> tuple(pairwise([]))
-        ()
-        >>> tuple(pairwise([], reverse=True))
-        ()
-        >>> tuple(pairwise([0]))
-        ((0, 0),)
-        >>> tuple(pairwise([0], reverse=True))
-        ((0, 0),)
-        >>> tuple(pairwise([0, 1]))
-        ((0, 1), (1, 0))
-        >>> tuple(pairwise([0, 1], reverse=True))
-        ((1, 0), (0, 1))
-        >>> tuple(pairwise([0, 1, 2]))
-        ((0, 1), (1, 2), (2, 0))
-        >>> tuple(pairwise([0, 1, 2], reverse=True))
-        ((2, 1), (1, 0), (0, 2))
-        >>> tuple(pairwise(['a', 'b', 'c', 'd']))
-        (('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'a'))
-        >>> tuple(pairwise(['a', 'b', 'c', 'd'], reverse=True))
-        (('d', 'c'), ('c', 'b'), ('b', 'a'), ('a', 'd'))
+    >>> tuple(pairwise([]))
+    ()
+    >>> tuple(pairwise([], reverse=True))
+    ()
+    >>> tuple(pairwise([0]))
+    ((0, 0),)
+    >>> tuple(pairwise([0], reverse=True))
+    ((0, 0),)
+    >>> tuple(pairwise([0, 1]))
+    ((0, 1), (1, 0))
+    >>> tuple(pairwise([0, 1], reverse=True))
+    ((1, 0), (0, 1))
+    >>> tuple(pairwise([0, 1, 2]))
+    ((0, 1), (1, 2), (2, 0))
+    >>> tuple(pairwise([0, 1, 2], reverse=True))
+    ((2, 1), (1, 0), (0, 2))
+    >>> tuple(pairwise(['a', 'b', 'c', 'd']))
+    (('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'a'))
+    >>> tuple(pairwise(['a', 'b', 'c', 'd'], reverse=True))
+    (('d', 'c'), ('c', 'b'), ('b', 'a'), ('a', 'd'))
     """
     if not iterable:
         return
diff --git a/Lib/fontTools/misc/bezierTools.py b/Lib/fontTools/misc/bezierTools.py
index 2cf2640..7305305 100644
--- a/Lib/fontTools/misc/bezierTools.py
+++ b/Lib/fontTools/misc/bezierTools.py
@@ -1,13 +1,11 @@
 # -*- coding: utf-8 -*-
-"""fontTools.misc.bezierTools.py -- tools for working with Bezier path segments.
+"""fontTools.misc.bezierTools.py -- tools for working with bezier path segments.
 """
 
-from fontTools.misc.arrayTools import calcBounds, sectRect, rectArea
-from fontTools.misc.transform import Identity
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.arrayTools import calcBounds
+from fontTools.misc.py23 import *
 import math
-from collections import namedtuple
-
-Intersection = namedtuple("Intersection", ["pt", "t1", "t2"])
 
 
 __all__ = [
@@ -28,68 +26,32 @@
     "splitCubicAtT",
     "solveQuadratic",
     "solveCubic",
-    "quadraticPointAtT",
-    "cubicPointAtT",
-    "linePointAtT",
-    "segmentPointAtT",
-    "lineLineIntersections",
-    "curveLineIntersections",
-    "curveCurveIntersections",
-    "segmentSegmentIntersections",
 ]
 
 
 def calcCubicArcLength(pt1, pt2, pt3, pt4, tolerance=0.005):
-    """Calculates the arc length for a cubic Bezier segment.
-
-    Whereas :func:`approximateCubicArcLength` approximates the length, this
-    function calculates it by "measuring", recursively dividing the curve
-    until the divided segments are shorter than ``tolerance``.
-
-    Args:
-        pt1,pt2,pt3,pt4: Control points of the Bezier as 2D tuples.
-        tolerance: Controls the precision of the calcuation.
-
-    Returns:
-        Arc length value.
-    """
-    return calcCubicArcLengthC(
-        complex(*pt1), complex(*pt2), complex(*pt3), complex(*pt4), tolerance
-    )
+    """Return the arc length for a cubic bezier segment."""
+    return calcCubicArcLengthC(complex(*pt1), complex(*pt2), complex(*pt3), complex(*pt4), tolerance)
 
 
 def _split_cubic_into_two(p0, p1, p2, p3):
-    mid = (p0 + 3 * (p1 + p2) + p3) * 0.125
-    deriv3 = (p3 + p2 - p1 - p0) * 0.125
-    return (
-        (p0, (p0 + p1) * 0.5, mid - deriv3, mid),
-        (mid, mid + deriv3, (p2 + p3) * 0.5, p3),
-    )
-
+    mid = (p0 + 3 * (p1 + p2) + p3) * .125
+    deriv3 = (p3 + p2 - p1 - p0) * .125
+    return ((p0, (p0 + p1) * .5, mid - deriv3, mid),
+            (mid, mid + deriv3, (p2 + p3) * .5, p3))
 
 def _calcCubicArcLengthCRecurse(mult, p0, p1, p2, p3):
-    arch = abs(p0 - p3)
-    box = abs(p0 - p1) + abs(p1 - p2) + abs(p2 - p3)
-    if arch * mult >= box:
-        return (arch + box) * 0.5
-    else:
-        one, two = _split_cubic_into_two(p0, p1, p2, p3)
-        return _calcCubicArcLengthCRecurse(mult, *one) + _calcCubicArcLengthCRecurse(
-            mult, *two
-        )
-
+	arch = abs(p0-p3)
+	box = abs(p0-p1) + abs(p1-p2) + abs(p2-p3)
+	if arch * mult >= box:
+		return (arch + box) * .5
+	else:
+		one,two = _split_cubic_into_two(p0,p1,p2,p3)
+		return _calcCubicArcLengthCRecurse(mult, *one) + _calcCubicArcLengthCRecurse(mult, *two)
 
 def calcCubicArcLengthC(pt1, pt2, pt3, pt4, tolerance=0.005):
-    """Calculates the arc length for a cubic Bezier segment.
-
-    Args:
-        pt1,pt2,pt3,pt4: Control points of the Bezier as complex numbers.
-        tolerance: Controls the precision of the calcuation.
-
-    Returns:
-        Arc length value.
-    """
-    mult = 1.0 + 1.5 * tolerance  # The 1.5 is a empirical hack; no math
+    """Return the arc length for a cubic bezier segment using complex points."""
+    mult = 1. + 1.5 * tolerance # The 1.5 is a empirical hack; no math
     return _calcCubicArcLengthCRecurse(mult, pt1, pt2, pt3, pt4)
 
 
@@ -104,21 +66,12 @@
 def _intSecAtan(x):
     # In : sympy.integrate(sp.sec(sp.atan(x)))
     # Out: x*sqrt(x**2 + 1)/2 + asinh(x)/2
-    return x * math.sqrt(x ** 2 + 1) / 2 + math.asinh(x) / 2
+    return x * math.sqrt(x**2 + 1)/2 + math.asinh(x)/2
 
 
 def calcQuadraticArcLength(pt1, pt2, pt3):
-    """Calculates the arc length for a quadratic Bezier segment.
-
-    Args:
-        pt1: Start point of the Bezier as 2D tuple.
-        pt2: Handle point of the Bezier as 2D tuple.
-        pt3: End point of the Bezier as 2D tuple.
-
-    Returns:
-        Arc length value.
-
-    Example::
+    """Return the arc length for a qudratic bezier segment.
+    pt1 and pt3 are the "anchor" points, pt2 is the "handle".
 
         >>> calcQuadraticArcLength((0, 0), (0, 0), (0, 0)) # empty segment
         0.0
@@ -143,16 +96,9 @@
 
 
 def calcQuadraticArcLengthC(pt1, pt2, pt3):
-    """Calculates the arc length for a quadratic Bezier segment.
+    """Return the arc length for a qudratic bezier segment using complex points.
+    pt1 and pt3 are the "anchor" points, pt2 is the "handle"."""
 
-    Args:
-        pt1: Start point of the Bezier as a complex number.
-        pt2: Handle point of the Bezier as a complex number.
-        pt3: End point of the Bezier as a complex number.
-
-    Returns:
-        Arc length value.
-    """
     # Analytical solution to the length of a quadratic bezier.
     # I'll explain how I arrived at this later.
     d0 = pt2 - pt1
@@ -160,82 +106,48 @@
     d = d1 - d0
     n = d * 1j
     scale = abs(n)
-    if scale == 0.0:
-        return abs(pt3 - pt1)
-    origDist = _dot(n, d0)
+    if scale == 0.:
+        return abs(pt3-pt1)
+    origDist = _dot(n,d0)
     if abs(origDist) < epsilon:
-        if _dot(d0, d1) >= 0:
-            return abs(pt3 - pt1)
+        if _dot(d0,d1) >= 0:
+            return abs(pt3-pt1)
         a, b = abs(d0), abs(d1)
-        return (a * a + b * b) / (a + b)
-    x0 = _dot(d, d0) / origDist
-    x1 = _dot(d, d1) / origDist
+        return (a*a + b*b) / (a+b)
+    x0 = _dot(d,d0) / origDist
+    x1 = _dot(d,d1) / origDist
     Len = abs(2 * (_intSecAtan(x1) - _intSecAtan(x0)) * origDist / (scale * (x1 - x0)))
     return Len
 
 
 def approximateQuadraticArcLength(pt1, pt2, pt3):
-    """Calculates the arc length for a quadratic Bezier segment.
-
-    Uses Gauss-Legendre quadrature for a branch-free approximation.
-    See :func:`calcQuadraticArcLength` for a slower but more accurate result.
-
-    Args:
-        pt1: Start point of the Bezier as 2D tuple.
-        pt2: Handle point of the Bezier as 2D tuple.
-        pt3: End point of the Bezier as 2D tuple.
-
-    Returns:
-        Approximate arc length value.
-    """
+    # Approximate length of quadratic Bezier curve using Gauss-Legendre quadrature
+    # with n=3 points.
     return approximateQuadraticArcLengthC(complex(*pt1), complex(*pt2), complex(*pt3))
 
 
 def approximateQuadraticArcLengthC(pt1, pt2, pt3):
-    """Calculates the arc length for a quadratic Bezier segment.
-
-    Uses Gauss-Legendre quadrature for a branch-free approximation.
-    See :func:`calcQuadraticArcLength` for a slower but more accurate result.
-
-    Args:
-        pt1: Start point of the Bezier as a complex number.
-        pt2: Handle point of the Bezier as a complex number.
-        pt3: End point of the Bezier as a complex number.
-
-    Returns:
-        Approximate arc length value.
-    """
+    # Approximate length of quadratic Bezier curve using Gauss-Legendre quadrature
+    # with n=3 points for complex points.
+    #
     # This, essentially, approximates the length-of-derivative function
     # to be integrated with the best-matching fifth-degree polynomial
     # approximation of it.
     #
-    # https://en.wikipedia.org/wiki/Gaussian_quadrature#Gauss.E2.80.93Legendre_quadrature
+    #https://en.wikipedia.org/wiki/Gaussian_quadrature#Gauss.E2.80.93Legendre_quadrature
 
     # abs(BezierCurveC[2].diff(t).subs({t:T})) for T in sorted(.5, .5±sqrt(3/5)/2),
     # weighted 5/18, 8/18, 5/18 respectively.
-    v0 = abs(
-        -0.492943519233745 * pt1 + 0.430331482911935 * pt2 + 0.0626120363218102 * pt3
-    )
-    v1 = abs(pt3 - pt1) * 0.4444444444444444
-    v2 = abs(
-        -0.0626120363218102 * pt1 - 0.430331482911935 * pt2 + 0.492943519233745 * pt3
-    )
+    v0 = abs(-0.492943519233745*pt1 + 0.430331482911935*pt2 + 0.0626120363218102*pt3)
+    v1 = abs(pt3-pt1)*0.4444444444444444
+    v2 = abs(-0.0626120363218102*pt1 - 0.430331482911935*pt2 + 0.492943519233745*pt3)
 
     return v0 + v1 + v2
 
 
 def calcQuadraticBounds(pt1, pt2, pt3):
-    """Calculates the bounding rectangle for a quadratic Bezier segment.
-
-    Args:
-        pt1: Start point of the Bezier as a 2D tuple.
-        pt2: Handle point of the Bezier as a 2D tuple.
-        pt3: End point of the Bezier as a 2D tuple.
-
-    Returns:
-        A four-item tuple representing the bounding rectangle ``(xMin, yMin, xMax, yMax)``.
-
-    Example::
+    """Return the bounding rectangle for a qudratic bezier segment.
+    pt1 and pt3 are the "anchor" points, pt2 is the "handle".
 
         >>> calcQuadraticBounds((0, 0), (50, 100), (100, 0))
         (0, 0, 100, 50.0)
@@ -243,34 +155,20 @@
         (0.0, 0.0, 100, 100)
     """
     (ax, ay), (bx, by), (cx, cy) = calcQuadraticParameters(pt1, pt2, pt3)
-    ax2 = ax * 2.0
-    ay2 = ay * 2.0
+    ax2 = ax*2.0
+    ay2 = ay*2.0
     roots = []
     if ax2 != 0:
-        roots.append(-bx / ax2)
+        roots.append(-bx/ax2)
     if ay2 != 0:
-        roots.append(-by / ay2)
-    points = [
-        (ax * t * t + bx * t + cx, ay * t * t + by * t + cy)
-        for t in roots
-        if 0 <= t < 1
-    ] + [pt1, pt3]
+        roots.append(-by/ay2)
+    points = [(ax*t*t + bx*t + cx, ay*t*t + by*t + cy) for t in roots if 0 <= t < 1] + [pt1, pt3]
     return calcBounds(points)
 
 
 def approximateCubicArcLength(pt1, pt2, pt3, pt4):
-    """Approximates the arc length for a cubic Bezier segment.
-
-    Uses Gauss-Lobatto quadrature with n=5 points to approximate arc length.
-    See :func:`calcCubicArcLength` for a slower but more accurate result.
-
-    Args:
-        pt1,pt2,pt3,pt4: Control points of the Bezier as 2D tuples.
-
-    Returns:
-        Arc length value.
-
-    Example::
+    """Return the approximate arc length for a cubic bezier segment.
+    pt1 and pt4 are the "anchor" points, pt2 and pt3 are the "handles".
 
         >>> approximateCubicArcLength((0, 0), (25, 100), (75, 100), (100, 0))
         190.04332968932817
@@ -283,20 +181,18 @@
         >>> approximateCubicArcLength((0, 0), (50, 0), (100, -50), (-50, 0)) # cusp
         154.80848416537057
     """
-    return approximateCubicArcLengthC(
-        complex(*pt1), complex(*pt2), complex(*pt3), complex(*pt4)
-    )
+    # Approximate length of cubic Bezier curve using Gauss-Lobatto quadrature
+    # with n=5 points.
+    return approximateCubicArcLengthC(complex(*pt1), complex(*pt2), complex(*pt3), complex(*pt4))
 
 
 def approximateCubicArcLengthC(pt1, pt2, pt3, pt4):
-    """Approximates the arc length for a cubic Bezier segment.
+    """Return the approximate arc length for a cubic bezier segment of complex points.
+    pt1 and pt4 are the "anchor" points, pt2 and pt3 are the "handles"."""
 
-    Args:
-        pt1,pt2,pt3,pt4: Control points of the Bezier as complex numbers.
-
-    Returns:
-        Arc length value.
-    """
+    # Approximate length of cubic Bezier curve using Gauss-Lobatto quadrature
+    # with n=5 points for complex points.
+    #
     # This, essentially, approximates the length-of-derivative function
     # to be integrated with the best-matching seventh-degree polynomial
     # approximation of it.
@@ -305,35 +201,18 @@
 
     # abs(BezierCurveC[3].diff(t).subs({t:T})) for T in sorted(0, .5±(3/7)**.5/2, .5, 1),
     # weighted 1/20, 49/180, 32/90, 49/180, 1/20 respectively.
-    v0 = abs(pt2 - pt1) * 0.15
-    v1 = abs(
-        -0.558983582205757 * pt1
-        + 0.325650248872424 * pt2
-        + 0.208983582205757 * pt3
-        + 0.024349751127576 * pt4
-    )
-    v2 = abs(pt4 - pt1 + pt3 - pt2) * 0.26666666666666666
-    v3 = abs(
-        -0.024349751127576 * pt1
-        - 0.208983582205757 * pt2
-        - 0.325650248872424 * pt3
-        + 0.558983582205757 * pt4
-    )
-    v4 = abs(pt4 - pt3) * 0.15
+    v0 = abs(pt2-pt1)*.15
+    v1 = abs(-0.558983582205757*pt1 + 0.325650248872424*pt2 + 0.208983582205757*pt3 + 0.024349751127576*pt4)
+    v2 = abs(pt4-pt1+pt3-pt2)*0.26666666666666666
+    v3 = abs(-0.024349751127576*pt1 - 0.208983582205757*pt2 - 0.325650248872424*pt3 + 0.558983582205757*pt4)
+    v4 = abs(pt4-pt3)*.15
 
     return v0 + v1 + v2 + v3 + v4
 
 
 def calcCubicBounds(pt1, pt2, pt3, pt4):
-    """Calculates the bounding rectangle for a quadratic Bezier segment.
-
-    Args:
-        pt1,pt2,pt3,pt4: Control points of the Bezier as 2D tuples.
-
-    Returns:
-        A four-item tuple representing the bounding rectangle ``(xMin, yMin, xMax, yMax)``.
-
-    Example::
+    """Return the bounding rectangle for a cubic bezier segment.
+    pt1 and pt4 are the "anchor" points, pt2 and pt3 are the "handles".
 
         >>> calcCubicBounds((0, 0), (25, 100), (75, 100), (100, 0))
         (0, 0, 100, 75.0)
@@ -352,33 +231,16 @@
     yRoots = [t for t in solveQuadratic(ay3, by2, cy) if 0 <= t < 1]
     roots = xRoots + yRoots
 
-    points = [
-        (
-            ax * t * t * t + bx * t * t + cx * t + dx,
-            ay * t * t * t + by * t * t + cy * t + dy,
-        )
-        for t in roots
-    ] + [pt1, pt4]
+    points = [(ax*t*t*t + bx*t*t + cx * t + dx, ay*t*t*t + by*t*t + cy * t + dy) for t in roots] + [pt1, pt4]
     return calcBounds(points)
 
 
 def splitLine(pt1, pt2, where, isHorizontal):
-    """Split a line at a given coordinate.
-
-    Args:
-        pt1: Start point of line as 2D tuple.
-        pt2: End point of line as 2D tuple.
-        where: Position at which to split the line.
-        isHorizontal: Direction of the ray splitting the line. If true,
-            ``where`` is interpreted as a Y coordinate; if false, then
-            ``where`` is interpreted as an X coordinate.
-
-    Returns:
-        A list of two line segments (each line segment being two 2D tuples)
-        if the line was successfully split, or a list containing the original
-        line.
-
-    Example::
+    """Split the line between pt1 and pt2 at position 'where', which
+    is an x coordinate if isHorizontal is False, a y coordinate if
+    isHorizontal is True. Return a list of two line segments if the
+    line was successfully split, or a list containing the original
+    line.
 
         >>> printSegments(splitLine((0, 0), (100, 100), 50, True))
         ((0, 0), (50, 50))
@@ -401,8 +263,8 @@
     pt1x, pt1y = pt1
     pt2x, pt2y = pt2
 
-    ax = pt2x - pt1x
-    ay = pt2y - pt1y
+    ax = (pt2x - pt1x)
+    ay = (pt2y - pt1y)
 
     bx = pt1x
     by = pt1y
@@ -420,21 +282,9 @@
 
 
 def splitQuadratic(pt1, pt2, pt3, where, isHorizontal):
-    """Split a quadratic Bezier curve at a given coordinate.
-
-    Args:
-        pt1,pt2,pt3: Control points of the Bezier as 2D tuples.
-        where: Position at which to split the curve.
-        isHorizontal: Direction of the ray splitting the curve. If true,
-            ``where`` is interpreted as a Y coordinate; if false, then
-            ``where`` is interpreted as an X coordinate.
-
-    Returns:
-        A list of two curve segments (each curve segment being three 2D tuples)
-        if the curve was successfully split, or a list containing the original
-        curve.
-
-    Example::
+    """Split the quadratic curve between pt1, pt2 and pt3 at position 'where',
+    which is an x coordinate if isHorizontal is False, a y coordinate if
+    isHorizontal is True. Return a list of curve segments.
 
         >>> printSegments(splitQuadratic((0, 0), (50, 100), (100, 0), 150, False))
         ((0, 0), (50, 100), (100, 0))
@@ -455,31 +305,18 @@
         ((50, 50), (75, 50), (100, 0))
     """
     a, b, c = calcQuadraticParameters(pt1, pt2, pt3)
-    solutions = solveQuadratic(
-        a[isHorizontal], b[isHorizontal], c[isHorizontal] - where
-    )
-    solutions = sorted(t for t in solutions if 0 <= t < 1)
+    solutions = solveQuadratic(a[isHorizontal], b[isHorizontal],
+        c[isHorizontal] - where)
+    solutions = sorted([t for t in solutions if 0 <= t < 1])
     if not solutions:
         return [(pt1, pt2, pt3)]
     return _splitQuadraticAtT(a, b, c, *solutions)
 
 
 def splitCubic(pt1, pt2, pt3, pt4, where, isHorizontal):
-    """Split a cubic Bezier curve at a given coordinate.
-
-    Args:
-        pt1,pt2,pt3,pt4: Control points of the Bezier as 2D tuples.
-        where: Position at which to split the curve.
-        isHorizontal: Direction of the ray splitting the curve. If true,
-            ``where`` is interpreted as a Y coordinate; if false, then
-            ``where`` is interpreted as an X coordinate.
-
-    Returns:
-        A list of two curve segments (each curve segment being four 2D tuples)
-        if the curve was successfully split, or a list containing the original
-        curve.
-
-    Example::
+    """Split the cubic curve between pt1, pt2, pt3 and pt4 at position 'where',
+    which is an x coordinate if isHorizontal is False, a y coordinate if
+    isHorizontal is True. Return a list of curve segments.
 
         >>> printSegments(splitCubic((0, 0), (25, 100), (75, 100), (100, 0), 150, False))
         ((0, 0), (25, 100), (75, 100), (100, 0))
@@ -492,26 +329,17 @@
         ((92.5259, 25), (95.202, 17.5085), (97.7062, 9.17517), (100, 1.77636e-15))
     """
     a, b, c, d = calcCubicParameters(pt1, pt2, pt3, pt4)
-    solutions = solveCubic(
-        a[isHorizontal], b[isHorizontal], c[isHorizontal], d[isHorizontal] - where
-    )
-    solutions = sorted(t for t in solutions if 0 <= t < 1)
+    solutions = solveCubic(a[isHorizontal], b[isHorizontal], c[isHorizontal],
+        d[isHorizontal] - where)
+    solutions = sorted([t for t in solutions if 0 <= t < 1])
     if not solutions:
         return [(pt1, pt2, pt3, pt4)]
     return _splitCubicAtT(a, b, c, d, *solutions)
 
 
 def splitQuadraticAtT(pt1, pt2, pt3, *ts):
-    """Split a quadratic Bezier curve at one or more values of t.
-
-    Args:
-        pt1,pt2,pt3: Control points of the Bezier as 2D tuples.
-        *ts: Positions at which to split the curve.
-
-    Returns:
-        A list of curve segments (each curve segment being three 2D tuples).
-
-    Examples::
+    """Split the quadratic curve between pt1, pt2 and pt3 at one or more
+    values of t. Return a list of curve segments.
 
         >>> printSegments(splitQuadraticAtT((0, 0), (50, 100), (100, 0), 0.5))
         ((0, 0), (25, 50), (50, 50))
@@ -526,16 +354,8 @@
 
 
 def splitCubicAtT(pt1, pt2, pt3, pt4, *ts):
-    """Split a cubic Bezier curve at one or more values of t.
-
-    Args:
-        pt1,pt2,pt3,pt4: Control points of the Bezier as 2D tuples.
-        *ts: Positions at which to split the curve.
-
-    Returns:
-        A list of curve segments (each curve segment being four 2D tuples).
-
-    Examples::
+    """Split the cubic curve between pt1, pt2, pt3 and pt4 at one or more
+    values of t. Return a list of curve segments.
 
         >>> printSegments(splitCubicAtT((0, 0), (25, 100), (75, 100), (100, 0), 0.5))
         ((0, 0), (12.5, 50), (31.25, 75), (50, 75))
@@ -559,17 +379,17 @@
     cx, cy = c
     for i in range(len(ts) - 1):
         t1 = ts[i]
-        t2 = ts[i + 1]
-        delta = t2 - t1
+        t2 = ts[i+1]
+        delta = (t2 - t1)
         # calc new a, b and c
-        delta_2 = delta * delta
+        delta_2 = delta*delta
         a1x = ax * delta_2
         a1y = ay * delta_2
-        b1x = (2 * ax * t1 + bx) * delta
-        b1y = (2 * ay * t1 + by) * delta
-        t1_2 = t1 * t1
-        c1x = ax * t1_2 + bx * t1 + cx
-        c1y = ay * t1_2 + by * t1 + cy
+        b1x = (2*ax*t1 + bx) * delta
+        b1y = (2*ay*t1 + by) * delta
+        t1_2 = t1*t1
+        c1x = ax*t1_2 + bx*t1 + cx
+        c1y = ay*t1_2 + by*t1 + cy
 
         pt1, pt2, pt3 = calcQuadraticPoints((a1x, a1y), (b1x, b1y), (c1x, c1y))
         segments.append((pt1, pt2, pt3))
@@ -587,26 +407,24 @@
     dx, dy = d
     for i in range(len(ts) - 1):
         t1 = ts[i]
-        t2 = ts[i + 1]
-        delta = t2 - t1
+        t2 = ts[i+1]
+        delta = (t2 - t1)
 
-        delta_2 = delta * delta
-        delta_3 = delta * delta_2
-        t1_2 = t1 * t1
-        t1_3 = t1 * t1_2
+        delta_2 = delta*delta
+        delta_3 = delta*delta_2
+        t1_2 = t1*t1
+        t1_3 = t1*t1_2
 
         # calc new a, b, c and d
         a1x = ax * delta_3
         a1y = ay * delta_3
-        b1x = (3 * ax * t1 + bx) * delta_2
-        b1y = (3 * ay * t1 + by) * delta_2
-        c1x = (2 * bx * t1 + cx + 3 * ax * t1_2) * delta
-        c1y = (2 * by * t1 + cy + 3 * ay * t1_2) * delta
-        d1x = ax * t1_3 + bx * t1_2 + cx * t1 + dx
-        d1y = ay * t1_3 + by * t1_2 + cy * t1 + dy
-        pt1, pt2, pt3, pt4 = calcCubicPoints(
-            (a1x, a1y), (b1x, b1y), (c1x, c1y), (d1x, d1y)
-        )
+        b1x = (3*ax*t1 + bx) * delta_2
+        b1y = (3*ay*t1 + by) * delta_2
+        c1x = (2*bx*t1 + cx + 3*ax*t1_2) * delta
+        c1y = (2*by*t1 + cy + 3*ay*t1_2) * delta
+        d1x = ax*t1_3 + bx*t1_2 + cx*t1 + dx
+        d1y = ay*t1_3 + by*t1_2 + cy*t1 + dy
+        pt1, pt2, pt3, pt4 = calcCubicPoints((a1x, a1y), (b1x, b1y), (c1x, c1y), (d1x, d1y))
         segments.append((pt1, pt2, pt3, pt4))
     return segments
 
@@ -618,19 +436,12 @@
 from math import sqrt, acos, cos, pi
 
 
-def solveQuadratic(a, b, c, sqrt=sqrt):
-    """Solve a quadratic equation.
-
-    Solves *a*x*x + b*x + c = 0* where a, b and c are real.
-
-    Args:
-        a: coefficient of *x²*
-        b: coefficient of *x*
-        c: constant term
-
-    Returns:
-        A list of roots. Note that the returned list is neither guaranteed to
-        be sorted nor to contain unique values!
+def solveQuadratic(a, b, c,
+        sqrt=sqrt):
+    """Solve a quadratic equation where a, b and c are real.
+        a*x*x + b*x + c = 0
+    This function returns a list of roots. Note that the returned list
+    is neither guaranteed to be sorted nor to contain unique values!
     """
     if abs(a) < epsilon:
         if abs(b) < epsilon:
@@ -638,13 +449,13 @@
             roots = []
         else:
             # We have a linear equation with 1 root.
-            roots = [-c / b]
+            roots = [-c/b]
     else:
         # We have a true quadratic equation.  Apply the quadratic formula to find two roots.
-        DD = b * b - 4.0 * a * c
+        DD = b*b - 4.0*a*c
         if DD >= 0.0:
             rDD = sqrt(DD)
-            roots = [(-b + rDD) / 2.0 / a, (-b - rDD) / 2.0 / a]
+            roots = [(-b+rDD)/2.0/a, (-b-rDD)/2.0/a]
         else:
             # complex roots, ignore
             roots = []
@@ -652,36 +463,25 @@
 
 
 def solveCubic(a, b, c, d):
-    """Solve a cubic equation.
+    """Solve a cubic equation where a, b, c and d are real.
+        a*x*x*x + b*x*x + c*x + d = 0
+    This function returns a list of roots. Note that the returned list
+    is neither guaranteed to be sorted nor to contain unique values!
 
-    Solves *a*x*x*x + b*x*x + c*x + d = 0* where a, b, c and d are real.
-
-    Args:
-        a: coefficient of *x³*
-        b: coefficient of *x²*
-        c: coefficient of *x*
-        d: constant term
-
-    Returns:
-        A list of roots. Note that the returned list is neither guaranteed to
-        be sorted nor to contain unique values!
-
-    Examples::
-
-        >>> solveCubic(1, 1, -6, 0)
-        [-3.0, -0.0, 2.0]
-        >>> solveCubic(-10.0, -9.0, 48.0, -29.0)
-        [-2.9, 1.0, 1.0]
-        >>> solveCubic(-9.875, -9.0, 47.625, -28.75)
-        [-2.911392, 1.0, 1.0]
-        >>> solveCubic(1.0, -4.5, 6.75, -3.375)
-        [1.5, 1.5, 1.5]
-        >>> solveCubic(-12.0, 18.0, -9.0, 1.50023651123)
-        [0.5, 0.5, 0.5]
-        >>> solveCubic(
-        ...     9.0, 0.0, 0.0, -7.62939453125e-05
-        ... ) == [-0.0, -0.0, -0.0]
-        True
+    >>> solveCubic(1, 1, -6, 0)
+    [-3.0, -0.0, 2.0]
+    >>> solveCubic(-10.0, -9.0, 48.0, -29.0)
+    [-2.9, 1.0, 1.0]
+    >>> solveCubic(-9.875, -9.0, 47.625, -28.75)
+    [-2.911392, 1.0, 1.0]
+    >>> solveCubic(1.0, -4.5, 6.75, -3.375)
+    [1.5, 1.5, 1.5]
+    >>> solveCubic(-12.0, 18.0, -9.0, 1.50023651123)
+    [0.5, 0.5, 0.5]
+    >>> solveCubic(
+    ...     9.0, 0.0, 0.0, -7.62939453125e-05
+    ... ) == [-0.0, -0.0, -0.0]
+    True
     """
     #
     # adapted from:
@@ -694,52 +494,52 @@
         # returns unreliable results, so we fall back to quad.
         return solveQuadratic(b, c, d)
     a = float(a)
-    a1 = b / a
-    a2 = c / a
-    a3 = d / a
+    a1 = b/a
+    a2 = c/a
+    a3 = d/a
 
-    Q = (a1 * a1 - 3.0 * a2) / 9.0
-    R = (2.0 * a1 * a1 * a1 - 9.0 * a1 * a2 + 27.0 * a3) / 54.0
+    Q = (a1*a1 - 3.0*a2)/9.0
+    R = (2.0*a1*a1*a1 - 9.0*a1*a2 + 27.0*a3)/54.0
 
-    R2 = R * R
-    Q3 = Q * Q * Q
+    R2 = R*R
+    Q3 = Q*Q*Q
     R2 = 0 if R2 < epsilon else R2
     Q3 = 0 if abs(Q3) < epsilon else Q3
 
     R2_Q3 = R2 - Q3
 
-    if R2 == 0.0 and Q3 == 0.0:
-        x = round(-a1 / 3.0, epsilonDigits)
+    if R2 == 0. and Q3 == 0.:
+        x = round(-a1/3.0, epsilonDigits)
         return [x, x, x]
-    elif R2_Q3 <= epsilon * 0.5:
+    elif R2_Q3 <= epsilon * .5:
         # The epsilon * .5 above ensures that Q3 is not zero.
-        theta = acos(max(min(R / sqrt(Q3), 1.0), -1.0))
-        rQ2 = -2.0 * sqrt(Q)
-        a1_3 = a1 / 3.0
-        x0 = rQ2 * cos(theta / 3.0) - a1_3
-        x1 = rQ2 * cos((theta + 2.0 * pi) / 3.0) - a1_3
-        x2 = rQ2 * cos((theta + 4.0 * pi) / 3.0) - a1_3
+        theta = acos(max(min(R/sqrt(Q3), 1.0), -1.0))
+        rQ2 = -2.0*sqrt(Q)
+        a1_3 = a1/3.0
+        x0 = rQ2*cos(theta/3.0) - a1_3
+        x1 = rQ2*cos((theta+2.0*pi)/3.0) - a1_3
+        x2 = rQ2*cos((theta+4.0*pi)/3.0) - a1_3
         x0, x1, x2 = sorted([x0, x1, x2])
         # Merge roots that are close-enough
         if x1 - x0 < epsilon and x2 - x1 < epsilon:
-            x0 = x1 = x2 = round((x0 + x1 + x2) / 3.0, epsilonDigits)
+            x0 = x1 = x2 = round((x0 + x1 + x2) / 3., epsilonDigits)
         elif x1 - x0 < epsilon:
-            x0 = x1 = round((x0 + x1) / 2.0, epsilonDigits)
+            x0 = x1 = round((x0 + x1) / 2., epsilonDigits)
             x2 = round(x2, epsilonDigits)
         elif x2 - x1 < epsilon:
             x0 = round(x0, epsilonDigits)
-            x1 = x2 = round((x1 + x2) / 2.0, epsilonDigits)
+            x1 = x2 = round((x1 + x2) / 2., epsilonDigits)
         else:
             x0 = round(x0, epsilonDigits)
             x1 = round(x1, epsilonDigits)
             x2 = round(x2, epsilonDigits)
         return [x0, x1, x2]
     else:
-        x = pow(sqrt(R2_Q3) + abs(R), 1 / 3.0)
-        x = x + Q / x
+        x = pow(sqrt(R2_Q3)+abs(R), 1/3.0)
+        x = x + Q/x
         if R >= 0.0:
             x = -x
-        x = round(x - a1 / 3.0, epsilonDigits)
+        x = round(x - a1/3.0, epsilonDigits)
         return [x]
 
 
@@ -747,7 +547,6 @@
 # Conversion routines for points to parameters and vice versa
 #
 
-
 def calcQuadraticParameters(pt1, pt2, pt3):
     x2, y2 = pt2
     x3, y3 = pt3
@@ -764,8 +563,8 @@
     x3, y3 = pt3
     x4, y4 = pt4
     dx, dy = pt1
-    cx = (x2 - dx) * 3.0
-    cy = (y2 - dy) * 3.0
+    cx = (x2 -dx) * 3.0
+    cy = (y2 -dy) * 3.0
     bx = (x3 - x2) * 3.0 - cx
     by = (y3 - y2) * 3.0 - cy
     ax = x4 - dx - cx - bx
@@ -802,406 +601,17 @@
     return (x1, y1), (x2, y2), (x3, y3), (x4, y4)
 
 
-#
-# Point at time
-#
-
-
-def linePointAtT(pt1, pt2, t):
-    """Finds the point at time `t` on a line.
-
-    Args:
-        pt1, pt2: Coordinates of the line as 2D tuples.
-        t: The time along the line.
-
-    Returns:
-        A 2D tuple with the coordinates of the point.
-    """
-    return ((pt1[0] * (1 - t) + pt2[0] * t), (pt1[1] * (1 - t) + pt2[1] * t))
-
-
-def quadraticPointAtT(pt1, pt2, pt3, t):
-    """Finds the point at time `t` on a quadratic curve.
-
-    Args:
-        pt1, pt2, pt3: Coordinates of the curve as 2D tuples.
-        t: The time along the curve.
-
-    Returns:
-        A 2D tuple with the coordinates of the point.
-    """
-    x = (1 - t) * (1 - t) * pt1[0] + 2 * (1 - t) * t * pt2[0] + t * t * pt3[0]
-    y = (1 - t) * (1 - t) * pt1[1] + 2 * (1 - t) * t * pt2[1] + t * t * pt3[1]
-    return (x, y)
-
-
-def cubicPointAtT(pt1, pt2, pt3, pt4, t):
-    """Finds the point at time `t` on a cubic curve.
-
-    Args:
-        pt1, pt2, pt3, pt4: Coordinates of the curve as 2D tuples.
-        t: The time along the curve.
-
-    Returns:
-        A 2D tuple with the coordinates of the point.
-    """
-    x = (
-        (1 - t) * (1 - t) * (1 - t) * pt1[0]
-        + 3 * (1 - t) * (1 - t) * t * pt2[0]
-        + 3 * (1 - t) * t * t * pt3[0]
-        + t * t * t * pt4[0]
-    )
-    y = (
-        (1 - t) * (1 - t) * (1 - t) * pt1[1]
-        + 3 * (1 - t) * (1 - t) * t * pt2[1]
-        + 3 * (1 - t) * t * t * pt3[1]
-        + t * t * t * pt4[1]
-    )
-    return (x, y)
-
-
-def segmentPointAtT(seg, t):
-    if len(seg) == 2:
-        return linePointAtT(*seg, t)
-    elif len(seg) == 3:
-        return quadraticPointAtT(*seg, t)
-    elif len(seg) == 4:
-        return cubicPointAtT(*seg, t)
-    raise ValueError("Unknown curve degree")
-
-
-#
-# Intersection finders
-#
-
-
-def _line_t_of_pt(s, e, pt):
-    sx, sy = s
-    ex, ey = e
-    px, py = pt
-    if not math.isclose(sx, ex):
-        return (px - sx) / (ex - sx)
-    if not math.isclose(sy, ey):
-        return (py - sy) / (ey - sy)
-    # Line is a point!
-    return -1
-
-
-def _both_points_are_on_same_side_of_origin(a, b, origin):
-    xDiff = (a[0] - origin[0]) * (b[0] - origin[0])
-    yDiff = (a[1] - origin[1]) * (b[1] - origin[1])
-    return not (xDiff <= 0.0 and yDiff <= 0.0)
-
-
-def lineLineIntersections(s1, e1, s2, e2):
-    """Finds intersections between two line segments.
-
-    Args:
-        s1, e1: Coordinates of the first line as 2D tuples.
-        s2, e2: Coordinates of the second line as 2D tuples.
-
-    Returns:
-        A list of ``Intersection`` objects, each object having ``pt``, ``t1``
-        and ``t2`` attributes containing the intersection point, time on first
-        segment and time on second segment respectively.
-
-    Examples::
-
-        >>> a = lineLineIntersections( (310,389), (453, 222), (289, 251), (447, 367))
-        >>> len(a)
-        1
-        >>> intersection = a[0]
-        >>> intersection.pt
-        (374.44882952482897, 313.73458370177315)
-        >>> (intersection.t1, intersection.t2)
-        (0.45069111555824454, 0.5408153767394238)
-    """
-    s1x, s1y = s1
-    e1x, e1y = e1
-    s2x, s2y = s2
-    e2x, e2y = e2
-    if (
-        math.isclose(s2x, e2x) and math.isclose(s1x, e1x) and not math.isclose(s1x, s2x)
-    ):  # Parallel vertical
-        return []
-    if (
-        math.isclose(s2y, e2y) and math.isclose(s1y, e1y) and not math.isclose(s1y, s2y)
-    ):  # Parallel horizontal
-        return []
-    if math.isclose(s2x, e2x) and math.isclose(s2y, e2y):  # Line segment is tiny
-        return []
-    if math.isclose(s1x, e1x) and math.isclose(s1y, e1y):  # Line segment is tiny
-        return []
-    if math.isclose(e1x, s1x):
-        x = s1x
-        slope34 = (e2y - s2y) / (e2x - s2x)
-        y = slope34 * (x - s2x) + s2y
-        pt = (x, y)
-        return [
-            Intersection(
-                pt=pt, t1=_line_t_of_pt(s1, e1, pt), t2=_line_t_of_pt(s2, e2, pt)
-            )
-        ]
-    if math.isclose(s2x, e2x):
-        x = s2x
-        slope12 = (e1y - s1y) / (e1x - s1x)
-        y = slope12 * (x - s1x) + s1y
-        pt = (x, y)
-        return [
-            Intersection(
-                pt=pt, t1=_line_t_of_pt(s1, e1, pt), t2=_line_t_of_pt(s2, e2, pt)
-            )
-        ]
-
-    slope12 = (e1y - s1y) / (e1x - s1x)
-    slope34 = (e2y - s2y) / (e2x - s2x)
-    if math.isclose(slope12, slope34):
-        return []
-    x = (slope12 * s1x - s1y - slope34 * s2x + s2y) / (slope12 - slope34)
-    y = slope12 * (x - s1x) + s1y
-    pt = (x, y)
-    if _both_points_are_on_same_side_of_origin(
-        pt, e1, s1
-    ) and _both_points_are_on_same_side_of_origin(pt, s2, e2):
-        return [
-            Intersection(
-                pt=pt, t1=_line_t_of_pt(s1, e1, pt), t2=_line_t_of_pt(s2, e2, pt)
-            )
-        ]
-    return []
-
-
-def _alignment_transformation(segment):
-    # Returns a transformation which aligns a segment horizontally at the
-    # origin. Apply this transformation to curves and root-find to find
-    # intersections with the segment.
-    start = segment[0]
-    end = segment[-1]
-    angle = math.atan2(end[1] - start[1], end[0] - start[0])
-    return Identity.rotate(-angle).translate(-start[0], -start[1])
-
-
-def _curve_line_intersections_t(curve, line):
-    aligned_curve = _alignment_transformation(line).transformPoints(curve)
-    if len(curve) == 3:
-        a, b, c = calcQuadraticParameters(*aligned_curve)
-        intersections = solveQuadratic(a[1], b[1], c[1])
-    elif len(curve) == 4:
-        a, b, c, d = calcCubicParameters(*aligned_curve)
-        intersections = solveCubic(a[1], b[1], c[1], d[1])
-    else:
-        raise ValueError("Unknown curve degree")
-    return sorted(i for i in intersections if 0.0 <= i <= 1)
-
-
-def curveLineIntersections(curve, line):
-    """Finds intersections between a curve and a line.
-
-    Args:
-        curve: List of coordinates of the curve segment as 2D tuples.
-        line: List of coordinates of the line segment as 2D tuples.
-
-    Returns:
-        A list of ``Intersection`` objects, each object having ``pt``, ``t1``
-        and ``t2`` attributes containing the intersection point, time on first
-        segment and time on second segment respectively.
-
-    Examples::
-        >>> curve = [ (100, 240), (30, 60), (210, 230), (160, 30) ]
-        >>> line  = [ (25, 260), (230, 20) ]
-        >>> intersections = curveLineIntersections(curve, line)
-        >>> len(intersections)
-        3
-        >>> intersections[0].pt
-        (84.90010344084885, 189.87306176459828)
-    """
-    if len(curve) == 3:
-        pointFinder = quadraticPointAtT
-    elif len(curve) == 4:
-        pointFinder = cubicPointAtT
-    else:
-        raise ValueError("Unknown curve degree")
-    intersections = []
-    for t in _curve_line_intersections_t(curve, line):
-        pt = pointFinder(*curve, t)
-        intersections.append(Intersection(pt=pt, t1=t, t2=_line_t_of_pt(*line, pt)))
-    return intersections
-
-
-def _curve_bounds(c):
-    if len(c) == 3:
-        return calcQuadraticBounds(*c)
-    elif len(c) == 4:
-        return calcCubicBounds(*c)
-    raise ValueError("Unknown curve degree")
-
-
-def _split_segment_at_t(c, t):
-    if len(c) == 2:
-        s, e = c
-        midpoint = linePointAtT(s, e, t)
-        return [(s, midpoint), (midpoint, e)]
-    if len(c) == 3:
-        return splitQuadraticAtT(*c, t)
-    elif len(c) == 4:
-        return splitCubicAtT(*c, t)
-    raise ValueError("Unknown curve degree")
-
-
-def _curve_curve_intersections_t(
-    curve1, curve2, precision=1e-3, range1=None, range2=None
-):
-    bounds1 = _curve_bounds(curve1)
-    bounds2 = _curve_bounds(curve2)
-
-    if not range1:
-        range1 = (0.0, 1.0)
-    if not range2:
-        range2 = (0.0, 1.0)
-
-    # If bounds don't intersect, go home
-    intersects, _ = sectRect(bounds1, bounds2)
-    if not intersects:
-        return []
-
-    def midpoint(r):
-        return 0.5 * (r[0] + r[1])
-
-    # If they do overlap but they're tiny, approximate
-    if rectArea(bounds1) < precision and rectArea(bounds2) < precision:
-        return [(midpoint(range1), midpoint(range2))]
-
-    c11, c12 = _split_segment_at_t(curve1, 0.5)
-    c11_range = (range1[0], midpoint(range1))
-    c12_range = (midpoint(range1), range1[1])
-
-    c21, c22 = _split_segment_at_t(curve2, 0.5)
-    c21_range = (range2[0], midpoint(range2))
-    c22_range = (midpoint(range2), range2[1])
-
-    found = []
-    found.extend(
-        _curve_curve_intersections_t(
-            c11, c21, precision, range1=c11_range, range2=c21_range
-        )
-    )
-    found.extend(
-        _curve_curve_intersections_t(
-            c12, c21, precision, range1=c12_range, range2=c21_range
-        )
-    )
-    found.extend(
-        _curve_curve_intersections_t(
-            c11, c22, precision, range1=c11_range, range2=c22_range
-        )
-    )
-    found.extend(
-        _curve_curve_intersections_t(
-            c12, c22, precision, range1=c12_range, range2=c22_range
-        )
-    )
-
-    unique_key = lambda ts: (int(ts[0] / precision), int(ts[1] / precision))
-    seen = set()
-    unique_values = []
-
-    for ts in found:
-        key = unique_key(ts)
-        if key in seen:
-            continue
-        seen.add(key)
-        unique_values.append(ts)
-
-    return unique_values
-
-
-def curveCurveIntersections(curve1, curve2):
-    """Finds intersections between a curve and a curve.
-
-    Args:
-        curve1: List of coordinates of the first curve segment as 2D tuples.
-        curve2: List of coordinates of the second curve segment as 2D tuples.
-
-    Returns:
-        A list of ``Intersection`` objects, each object having ``pt``, ``t1``
-        and ``t2`` attributes containing the intersection point, time on first
-        segment and time on second segment respectively.
-
-    Examples::
-        >>> curve1 = [ (10,100), (90,30), (40,140), (220,220) ]
-        >>> curve2 = [ (5,150), (180,20), (80,250), (210,190) ]
-        >>> intersections = curveCurveIntersections(curve1, curve2)
-        >>> len(intersections)
-        3
-        >>> intersections[0].pt
-        (81.7831487395506, 109.88904552375288)
-    """
-    intersection_ts = _curve_curve_intersections_t(curve1, curve2)
-    return [
-        Intersection(pt=segmentPointAtT(curve1, ts[0]), t1=ts[0], t2=ts[1])
-        for ts in intersection_ts
-    ]
-
-
-def segmentSegmentIntersections(seg1, seg2):
-    """Finds intersections between two segments.
-
-    Args:
-        seg1: List of coordinates of the first segment as 2D tuples.
-        seg2: List of coordinates of the second segment as 2D tuples.
-
-    Returns:
-        A list of ``Intersection`` objects, each object having ``pt``, ``t1``
-        and ``t2`` attributes containing the intersection point, time on first
-        segment and time on second segment respectively.
-
-    Examples::
-        >>> curve1 = [ (10,100), (90,30), (40,140), (220,220) ]
-        >>> curve2 = [ (5,150), (180,20), (80,250), (210,190) ]
-        >>> intersections = segmentSegmentIntersections(curve1, curve2)
-        >>> len(intersections)
-        3
-        >>> intersections[0].pt
-        (81.7831487395506, 109.88904552375288)
-        >>> curve3 = [ (100, 240), (30, 60), (210, 230), (160, 30) ]
-        >>> line  = [ (25, 260), (230, 20) ]
-        >>> intersections = segmentSegmentIntersections(curve3, line)
-        >>> len(intersections)
-        3
-        >>> intersections[0].pt
-        (84.90010344084885, 189.87306176459828)
-
-    """
-    # Arrange by degree
-    swapped = False
-    if len(seg2) > len(seg1):
-        seg2, seg1 = seg1, seg2
-        swapped = True
-    if len(seg1) > 2:
-        if len(seg2) > 2:
-            intersections = curveCurveIntersections(seg1, seg2)
-        else:
-            intersections = curveLineIntersections(seg1, seg2)
-    elif len(seg1) == 2 and len(seg2) == 2:
-        intersections = lineLineIntersections(*seg1, *seg2)
-    else:
-        raise ValueError("Couldn't work out which intersection function to use")
-    if not swapped:
-        return intersections
-    return [Intersection(pt=i.pt, t1=i.t2, t2=i.t1) for i in intersections]
-
-
 def _segmentrepr(obj):
     """
-    >>> _segmentrepr([1, [2, 3], [], [[2, [3, 4], [0.1, 2.2]]]])
-    '(1, (2, 3), (), ((2, (3, 4), (0.1, 2.2))))'
+        >>> _segmentrepr([1, [2, 3], [], [[2, [3, 4], [0.1, 2.2]]]])
+        '(1, (2, 3), (), ((2, (3, 4), (0.1, 2.2))))'
     """
     try:
         it = iter(obj)
     except TypeError:
         return "%g" % obj
     else:
-        return "(%s)" % ", ".join(_segmentrepr(x) for x in it)
+        return "(%s)" % ", ".join([_segmentrepr(x) for x in it])
 
 
 def printSegments(segments):
@@ -1211,9 +621,7 @@
     for segment in segments:
         print(_segmentrepr(segment))
 
-
 if __name__ == "__main__":
     import sys
     import doctest
-
     sys.exit(doctest.testmod().failed)
diff --git a/Lib/fontTools/misc/classifyTools.py b/Lib/fontTools/misc/classifyTools.py
index ae88a8f..64bcdc8 100644
--- a/Lib/fontTools/misc/classifyTools.py
+++ b/Lib/fontTools/misc/classifyTools.py
@@ -1,6 +1,8 @@
 """ fontTools.misc.classifyTools.py -- tools for classifying things.
 """
 
+from __future__ import print_function, absolute_import
+from fontTools.misc.py23 import *
 
 class Classifier(object):
 
diff --git a/Lib/fontTools/misc/cliTools.py b/Lib/fontTools/misc/cliTools.py
index e8c1767..8420e3e 100644
--- a/Lib/fontTools/misc/cliTools.py
+++ b/Lib/fontTools/misc/cliTools.py
@@ -1,4 +1,6 @@
 """Collection of utilities for command-line interfaces and console scripts."""
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 import os
 import re
 
@@ -7,28 +9,6 @@
 
 
 def makeOutputFileName(input, outputDir=None, extension=None, overWrite=False):
-    """Generates a suitable file name for writing output.
-
-    Often tools will want to take a file, do some kind of transformation to it,
-    and write it out again. This function determines an appropriate name for the
-    output file, through one or more of the following steps:
-
-    - changing the output directory
-    - replacing the file extension
-    - suffixing the filename with a number (``#1``, ``#2``, etc.) to avoid
-      overwriting an existing file.
-
-    Args:
-        input: Name of input file.
-        outputDir: Optionally, a new directory to write the file into.
-        extension: Optionally, a replacement for the current file extension.
-        overWrite: Overwriting an existing file is permitted if true; if false
-            and the proposed filename exists, a new name will be generated by
-            adding an appropriate number suffix.
-
-    Returns:
-        str: Suitable output filename
-    """
     dirName, fileName = os.path.split(input)
     fileName, ext = os.path.splitext(fileName)
     if outputDir:
diff --git a/Lib/fontTools/misc/cython.py b/Lib/fontTools/misc/cython.py
deleted file mode 100644
index 0ba659f..0000000
--- a/Lib/fontTools/misc/cython.py
+++ /dev/null
@@ -1,25 +0,0 @@
-""" Exports a no-op 'cython' namespace similar to
-https://github.com/cython/cython/blob/master/Cython/Shadow.py
-
-This allows to optionally compile @cython decorated functions
-(when cython is available at built time), or run the same code
-as pure-python, without runtime dependency on cython module.
-
-We only define the symbols that we use. E.g. see fontTools.cu2qu
-"""
-
-from types import SimpleNamespace
-
-def _empty_decorator(x):
-    return x
-
-compiled = False
-
-for name in ("double", "complex", "int"):
-    globals()[name] = None
-
-for name in ("cfunc", "inline"):
-    globals()[name] = _empty_decorator
-
-locals = lambda **_: _empty_decorator
-returns = lambda _: _empty_decorator
diff --git a/Lib/fontTools/misc/dictTools.py b/Lib/fontTools/misc/dictTools.py
index ae7932c..db5d658 100644
--- a/Lib/fontTools/misc/dictTools.py
+++ b/Lib/fontTools/misc/dictTools.py
@@ -1,5 +1,7 @@
 """Misc dict tools."""
 
+from __future__ import print_function, absolute_import, division
+from fontTools.misc.py23 import *
 
 __all__ = ['hashdict']
 
diff --git a/Lib/fontTools/misc/eexec.py b/Lib/fontTools/misc/eexec.py
index 71f733c..0efa6f5 100644
--- a/Lib/fontTools/misc/eexec.py
+++ b/Lib/fontTools/misc/eexec.py
@@ -1,19 +1,9 @@
-"""
-PostScript Type 1 fonts make use of two types of encryption: charstring
-encryption and ``eexec`` encryption. Charstring encryption is used for
-the charstrings themselves, while ``eexec`` is used to encrypt larger
-sections of the font program, such as the ``Private`` and ``CharStrings``
-dictionaries. Despite the different names, the algorithm is the same,
-although ``eexec`` encryption uses a fixed initial key R=55665.
-
-The algorithm uses cipher feedback, meaning that the ciphertext is used
-to modify the key. Because of this, the routines in this module return
-the new key at the end of the operation.
-
+"""fontTools.misc.eexec.py -- Module implementing the eexec and
+charstring encryption algorithm as used by PostScript Type 1 fonts.
 """
 
-from fontTools.misc.py23 import bytechr, bytesjoin, byteord
-
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 
 def _decryptChar(cipher, R):
 	cipher = byteord(cipher)
@@ -30,24 +20,12 @@
 
 def decrypt(cipherstring, R):
 	r"""
-	Decrypts a string using the Type 1 encryption algorithm.
-
-	Args:
-		cipherstring: String of ciphertext.
-		R: Initial key.
-
-	Returns:
-		decryptedStr: Plaintext string.
-		R: Output key for subsequent decryptions.
-
-	Examples::
-
-		>>> testStr = b"\0\0asdadads asds\265"
-		>>> decryptedStr, R = decrypt(testStr, 12321)
-		>>> decryptedStr == b'0d\nh\x15\xe8\xc4\xb2\x15\x1d\x108\x1a<6\xa1'
-		True
-		>>> R == 36142
-		True
+	>>> testStr = b"\0\0asdadads asds\265"
+	>>> decryptedStr, R = decrypt(testStr, 12321)
+	>>> decryptedStr == b'0d\nh\x15\xe8\xc4\xb2\x15\x1d\x108\x1a<6\xa1'
+	True
+	>>> R == 36142
+	True
 	"""
 	plainList = []
 	for cipher in cipherstring:
@@ -58,30 +36,6 @@
 
 def encrypt(plainstring, R):
 	r"""
-	Encrypts a string using the Type 1 encryption algorithm.
-
-	Note that the algorithm as described in the Type 1 specification requires the
-	plaintext to be prefixed with a number of random bytes. (For ``eexec`` the
-	number of random bytes is set to 4.) This routine does *not* add the random
-	prefix to its input.
-
-	Args:
-		plainstring: String of plaintext.
-		R: Initial key.
-
-	Returns:
-		cipherstring: Ciphertext string.
-		R: Output key for subsequent encryptions.
-
-	Examples::
-
-		>>> testStr = b"\0\0asdadads asds\265"
-		>>> decryptedStr, R = decrypt(testStr, 12321)
-		>>> decryptedStr == b'0d\nh\x15\xe8\xc4\xb2\x15\x1d\x108\x1a<6\xa1'
-		True
-		>>> R == 36142
-		True
-
 	>>> testStr = b'0d\nh\x15\xe8\xc4\xb2\x15\x1d\x108\x1a<6\xa1'
 	>>> encryptedStr, R = encrypt(testStr, 12321)
 	>>> encryptedStr == b"\0\0asdadads asds\265"
diff --git a/Lib/fontTools/misc/encodingTools.py b/Lib/fontTools/misc/encodingTools.py
index eccf951..454ec9a 100644
--- a/Lib/fontTools/misc/encodingTools.py
+++ b/Lib/fontTools/misc/encodingTools.py
@@ -1,6 +1,8 @@
 """fontTools.misc.encodingTools.py -- tools for working with OpenType encodings.
 """
 
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 import fontTools.encodings.codecs
 
 # Map keyed by platformID, then platEncID, then possibly langID
diff --git a/Lib/fontTools/misc/etree.py b/Lib/fontTools/misc/etree.py
index 6e943e4..08e43f0 100644
--- a/Lib/fontTools/misc/etree.py
+++ b/Lib/fontTools/misc/etree.py
@@ -11,7 +11,8 @@
 only availble in lxml, like OrderedDict for attributes, pretty_print and
 iterwalk.
 """
-from fontTools.misc.py23 import unicode, tostr
+from __future__ import absolute_import, unicode_literals
+from fontTools.misc.py23 import basestring, unicode, tounicode, open
 
 
 XML_DECLARATION = """<?xml version='1.0' encoding='%s'?>"""
@@ -242,7 +243,7 @@
         Reject all bytes input that contains non-ASCII characters.
         """
         try:
-            s = tostr(s, encoding="ascii", errors="strict")
+            s = tounicode(s, encoding="ascii", errors="strict")
         except UnicodeDecodeError:
             raise ValueError(
                 "Bytes strings can only contain ASCII characters. "
@@ -356,7 +357,7 @@
             if isinstance(tag, QName):
                 if tag.text not in qnames:
                     add_qname(tag.text)
-            elif isinstance(tag, str):
+            elif isinstance(tag, basestring):
                 if tag not in qnames:
                     add_qname(tag)
             elif tag is not None and tag is not Comment and tag is not PI:
diff --git a/Lib/fontTools/misc/filenames.py b/Lib/fontTools/misc/filenames.py
index 0f01000..260ace4 100644
--- a/Lib/fontTools/misc/filenames.py
+++ b/Lib/fontTools/misc/filenames.py
@@ -1,21 +1,18 @@
 """
-This module implements the algorithm for converting between a "user name" -
-something that a user can choose arbitrarily inside a font editor - and a file
-name suitable for use in a wide range of operating systems and filesystems.
+User name to file name conversion based on the UFO 3 spec:
+http://unifiedfontobject.org/versions/ufo3/conventions/
 
-The `UFO 3 specification <http://unifiedfontobject.org/versions/ufo3/conventions/>`_
-provides an example of an algorithm for such conversion, which avoids illegal
-characters, reserved file names, ambiguity between upper- and lower-case
-characters, and clashes with existing files.
+The code was copied from:
+https://github.com/unified-font-object/ufoLib/blob/8747da7/Lib/ufoLib/filenames.py
 
-This code was originally copied from
-`ufoLib <https://github.com/unified-font-object/ufoLib/blob/8747da7/Lib/ufoLib/filenames.py>`_
-by Tal Leming and is copyright (c) 2005-2016, The RoboFab Developers:
-
--	Erik van Blokland
--	Tal Leming
--	Just van Rossum
+Author: Tal Leming
+Copyright (c) 2005-2016, The RoboFab Developers:
+	Erik van Blokland
+	Tal Leming
+	Just van Rossum
 """
+from __future__ import unicode_literals
+from fontTools.misc.py23 import basestring, unicode
 
 
 illegalCharacters = r"\" * + / : < > ? [ \ ] | \0".split(" ")
@@ -31,73 +28,58 @@
 
 
 def userNameToFileName(userName, existing=[], prefix="", suffix=""):
-	"""Converts from a user name to a file name.
-
-	Takes care to avoid illegal characters, reserved file names, ambiguity between
-	upper- and lower-case characters, and clashes with existing files.
-
-	Args:
-		userName (str): The input file name.
-		existing: A case-insensitive list of all existing file names.
-		prefix: Prefix to be prepended to the file name.
-		suffix: Suffix to be appended to the file name.
-
-	Returns:
-		A suitable filename.
-
-	Raises:
-		NameTranslationError: If no suitable name could be generated.
-
-	Examples::
-
-		>>> userNameToFileName("a") == "a"
-		True
-		>>> userNameToFileName("A") == "A_"
-		True
-		>>> userNameToFileName("AE") == "A_E_"
-		True
-		>>> userNameToFileName("Ae") == "A_e"
-		True
-		>>> userNameToFileName("ae") == "ae"
-		True
-		>>> userNameToFileName("aE") == "aE_"
-		True
-		>>> userNameToFileName("a.alt") == "a.alt"
-		True
-		>>> userNameToFileName("A.alt") == "A_.alt"
-		True
-		>>> userNameToFileName("A.Alt") == "A_.A_lt"
-		True
-		>>> userNameToFileName("A.aLt") == "A_.aL_t"
-		True
-		>>> userNameToFileName(u"A.alT") == "A_.alT_"
-		True
-		>>> userNameToFileName("T_H") == "T__H_"
-		True
-		>>> userNameToFileName("T_h") == "T__h"
-		True
-		>>> userNameToFileName("t_h") == "t_h"
-		True
-		>>> userNameToFileName("F_F_I") == "F__F__I_"
-		True
-		>>> userNameToFileName("f_f_i") == "f_f_i"
-		True
-		>>> userNameToFileName("Aacute_V.swash") == "A_acute_V_.swash"
-		True
-		>>> userNameToFileName(".notdef") == "_notdef"
-		True
-		>>> userNameToFileName("con") == "_con"
-		True
-		>>> userNameToFileName("CON") == "C_O_N_"
-		True
-		>>> userNameToFileName("con.alt") == "_con.alt"
-		True
-		>>> userNameToFileName("alt.con") == "alt._con"
-		True
 	"""
-	# the incoming name must be a str
-	if not isinstance(userName, str):
-		raise ValueError("The value for userName must be a string.")
+	existing should be a case-insensitive list
+	of all existing file names.
+
+	>>> userNameToFileName("a") == "a"
+	True
+	>>> userNameToFileName("A") == "A_"
+	True
+	>>> userNameToFileName("AE") == "A_E_"
+	True
+	>>> userNameToFileName("Ae") == "A_e"
+	True
+	>>> userNameToFileName("ae") == "ae"
+	True
+	>>> userNameToFileName("aE") == "aE_"
+	True
+	>>> userNameToFileName("a.alt") == "a.alt"
+	True
+	>>> userNameToFileName("A.alt") == "A_.alt"
+	True
+	>>> userNameToFileName("A.Alt") == "A_.A_lt"
+	True
+	>>> userNameToFileName("A.aLt") == "A_.aL_t"
+	True
+	>>> userNameToFileName(u"A.alT") == "A_.alT_"
+	True
+	>>> userNameToFileName("T_H") == "T__H_"
+	True
+	>>> userNameToFileName("T_h") == "T__h"
+	True
+	>>> userNameToFileName("t_h") == "t_h"
+	True
+	>>> userNameToFileName("F_F_I") == "F__F__I_"
+	True
+	>>> userNameToFileName("f_f_i") == "f_f_i"
+	True
+	>>> userNameToFileName("Aacute_V.swash") == "A_acute_V_.swash"
+	True
+	>>> userNameToFileName(".notdef") == "_notdef"
+	True
+	>>> userNameToFileName("con") == "_con"
+	True
+	>>> userNameToFileName("CON") == "C_O_N_"
+	True
+	>>> userNameToFileName("con.alt") == "_con.alt"
+	True
+	>>> userNameToFileName("alt.con") == "alt._con"
+	True
+	"""
+	# the incoming name must be a unicode string
+	if not isinstance(userName, unicode):
+		raise ValueError("The value for userName must be a unicode string.")
 	# establish the prefix and suffix lengths
 	prefixLength = len(prefix)
 	suffixLength = len(suffix)
diff --git a/Lib/fontTools/misc/fixedTools.py b/Lib/fontTools/misc/fixedTools.py
index f0474ab..c5119ab 100644
--- a/Lib/fontTools/misc/fixedTools.py
+++ b/Lib/fontTools/misc/fixedTools.py
@@ -1,139 +1,43 @@
-"""
-The `OpenType specification <https://docs.microsoft.com/en-us/typography/opentype/spec/otff#data-types>`_
-defines two fixed-point data types:
-
-``Fixed``
-	A 32-bit signed fixed-point number with a 16 bit twos-complement
-	magnitude component and 16 fractional bits.
-``F2DOT14``
-	A 16-bit signed fixed-point number with a 2 bit twos-complement
-	magnitude component and 14 fractional bits.
-
-To support reading and writing data with these data types, this module provides
-functions for converting between fixed-point, float and string representations.
-
-.. data:: MAX_F2DOT14
-
-	The maximum value that can still fit in an F2Dot14. (1.99993896484375)
+"""fontTools.misc.fixedTools.py -- tools for working with fixed numbers.
 """
 
-from .roundTools import otRound
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+import math
 import logging
 
 log = logging.getLogger(__name__)
 
 __all__ = [
-	"MAX_F2DOT14",
+	"otRound",
 	"fixedToFloat",
 	"floatToFixed",
-	"floatToFixedToFloat",
-	"floatToFixedToStr",
-	"fixedToStr",
-	"strToFixed",
-	"strToFixedToFloat",
+    "floatToFixedToFloat",
 	"ensureVersionIsLong",
 	"versionToFixed",
 ]
 
 
-MAX_F2DOT14 = 0x7FFF / (1 << 14)
+def otRound(value):
+	"""Round float value to nearest integer towards +Infinity.
+	For fractional values of 0.5 and higher, take the next higher integer;
+	for other fractional values, truncate.
+
+	https://docs.microsoft.com/en-us/typography/opentype/spec/otvaroverview
+	https://github.com/fonttools/fonttools/issues/1248#issuecomment-383198166
+	"""
+	return int(math.floor(value + 0.5))
 
 
 def fixedToFloat(value, precisionBits):
-	"""Converts a fixed-point number to a float given the number of
-	precision bits.
+	"""Converts a fixed-point number to a float, choosing the float
+	that has the shortest decimal reprentation.  Eg. to convert a
+	fixed number in a 2.14 format, use precisionBits=14.  This is
+	pretty slow compared to a simple division.  Use sporadically.
 
-	Args:
-		value (int): Number in fixed-point format.
-		precisionBits (int): Number of precision bits.
-
-	Returns:
-		Floating point value.
-
-	Examples::
-
-		>>> import math
-		>>> f = fixedToFloat(-10139, precisionBits=14)
-		>>> math.isclose(f, -0.61883544921875)
-		True
+	precisionBits is only supported up to 16.
 	"""
-	return value / (1 << precisionBits)
-
-
-def floatToFixed(value, precisionBits):
-	"""Converts a float to a fixed-point number given the number of
-	precision bits.
-
-	Args:
-		value (float): Floating point value.
-		precisionBits (int): Number of precision bits.
-
-	Returns:
-		int: Fixed-point representation.
-
-	Examples::
-
-		>>> floatToFixed(-0.61883544921875, precisionBits=14)
-		-10139
-		>>> floatToFixed(-0.61884, precisionBits=14)
-		-10139
-	"""
-	return otRound(value * (1 << precisionBits))
-
-
-def floatToFixedToFloat(value, precisionBits):
-	"""Converts a float to a fixed-point number and back again.
-
-	By converting the float to fixed, rounding it, and converting it back
-	to float again, this returns a floating point values which is exactly
-	representable in fixed-point format.
-
-	Note: this **is** equivalent to ``fixedToFloat(floatToFixed(value))``.
-
-	Args:
-		value (float): The input floating point value.
-		precisionBits (int): Number of precision bits.
-
-	Returns:
-		float: The transformed and rounded value.
-
-	Examples::
-		>>> import math
-		>>> f1 = -0.61884
-		>>> f2 = floatToFixedToFloat(-0.61884, precisionBits=14)
-		>>> f1 != f2
-		True
-		>>> math.isclose(f2, -0.61883544921875)
-		True
-	"""
-	scale = 1 << precisionBits
-	return otRound(value * scale) / scale
-
-
-def fixedToStr(value, precisionBits):
-	"""Converts a fixed-point number to a string representing a decimal float.
-
-	This chooses the float that has the shortest decimal representation (the least
-	number of fractional decimal digits).
-
-	For example, to convert a fixed-point number in a 2.14 format, use
-	``precisionBits=14``::
-
-		>>> fixedToStr(-10139, precisionBits=14)
-		'-0.61884'
-
-	This is pretty slow compared to the simple division used in ``fixedToFloat``.
-	Use sporadically when you need to serialize or print the fixed-point number in
-	a human-readable form.
-
-	Args:
-		value (int): The fixed-point value to convert.
-		precisionBits (int): Number of precision bits, *up to a maximum of 16*.
-
-	Returns:
-		str: A string representation of the value.
-	"""
-	if not value: return "0.0"
+	if not value: return 0.0
 
 	scale = 1 << precisionBits
 	value /= scale
@@ -142,7 +46,7 @@
 	hi = value + eps
 	# If the range of valid choices spans an integer, return the integer.
 	if int(lo) != int(hi):
-		return str(float(round(value)))
+		return float(round(value))
 	fmt = "%.8f"
 	lo = fmt % lo
 	hi = fmt % hi
@@ -153,99 +57,28 @@
 	period = lo.find('.')
 	assert period < i
 	fmt = "%%.%df" % (i - period)
-	return fmt % value
+	value = fmt % value
+	return float(value)
 
-
-def strToFixed(string, precisionBits):
-	"""Converts a string representing a decimal float to a fixed-point number.
-
-	Args:
-		string (str): A string representing a decimal float.
-		precisionBits (int): Number of precision bits, *up to a maximum of 16*.
-
-	Returns:
-		int: Fixed-point representation.
-
-	Examples::
-
-	>>> ## to convert a float string to a 2.14 fixed-point number:
-	>>> strToFixed('-0.61884', precisionBits=14)
-	-10139
+def floatToFixed(value, precisionBits):
+	"""Converts a float to a fixed-point number given the number of
+	precisionBits.  Ie. round(value * (1<<precisionBits)).
 	"""
-	value = float(string)
-	return otRound(value * (1 << precisionBits))
+	return otRound(value * (1<<precisionBits))
 
-
-def strToFixedToFloat(string, precisionBits):
-	"""Convert a string to a decimal float with fixed-point rounding.
-
-	This first converts string to a float, then turns it into a fixed-point
-	number with ``precisionBits`` fractional binary digits, then back to a
-	float again.
-
-	This is simply a shorthand for fixedToFloat(floatToFixed(float(s))).
-
-	Args:
-		string (str): A string representing a decimal float.
-		precisionBits (int): Number of precision bits.
-
-	Returns:
-		float: The transformed and rounded value.
-
-	Examples::
-
-		>>> import math
-		>>> s = '-0.61884'
-		>>> bits = 14
-		>>> f = strToFixedToFloat(s, precisionBits=bits)
-		>>> math.isclose(f, -0.61883544921875)
-		True
-		>>> f == fixedToFloat(floatToFixed(float(s), precisionBits=bits), precisionBits=bits)
-		True
+def floatToFixedToFloat(value, precisionBits):
+	"""Converts a float to a fixed-point number given the number of
+	precisionBits, round it, then convert it back to float again.
+	Ie. round(value * (1<<precisionBits)) / (1<<precisionBits)
+	Note: this is *not* equivalent to fixedToFloat(floatToFixed(value)),
+	which would return the shortest representation of the rounded value.
 	"""
-	value = float(string)
-	scale = 1 << precisionBits
+	scale = 1<<precisionBits
 	return otRound(value * scale) / scale
 
-
-def floatToFixedToStr(value, precisionBits):
-	"""Convert float to string with fixed-point rounding.
-
-	This uses the shortest decimal representation (ie. the least
-	number of fractional decimal digits) to represent the equivalent
-	fixed-point number with ``precisionBits`` fractional binary digits.
-	It uses fixedToStr under the hood.
-
-	>>> floatToFixedToStr(-0.61883544921875, precisionBits=14)
-	'-0.61884'
-
-	Args:
-		value (float): The float value to convert.
-		precisionBits (int): Number of precision bits, *up to a maximum of 16*.
-
-	Returns:
-		str: A string representation of the value.
-
-	"""
-	fixed = otRound(value * (1 << precisionBits))
-	return fixedToStr(fixed, precisionBits)
-
-
 def ensureVersionIsLong(value):
-	"""Ensure a table version is an unsigned long.
-
-	OpenType table version numbers are expressed as a single unsigned long
-	comprising of an unsigned short major version and unsigned short minor
-	version. This function detects if the value to be used as a version number
-	looks too small (i.e. is less than ``0x10000``), and converts it to
-	fixed-point using :func:`floatToFixed` if so.
-
-	Args:
-		value (Number): a candidate table version number.
-
-	Returns:
-		int: A table version number, possibly corrected to fixed-point.
-	"""
+	"""Ensure a table version is an unsigned long (unsigned short major,
+	unsigned short minor) instead of a float."""
 	if value < 0x10000:
 		newValue = floatToFixed(value, 16)
 		log.warning(
@@ -256,14 +89,7 @@
 
 
 def versionToFixed(value):
-	"""Ensure a table version number is fixed-point.
-
-	Args:
-		value (str): a candidate table version number.
-
-	Returns:
-		int: A table version number, possibly corrected to fixed-point.
-	"""
+	"""Converts a table version to a fixed"""
 	value = int(value, 0) if value.startswith("0") else float(value)
 	value = ensureVersionIsLong(value)
 	return value
diff --git a/Lib/fontTools/misc/intTools.py b/Lib/fontTools/misc/intTools.py
index 448e162..9eb2f0f 100644
--- a/Lib/fontTools/misc/intTools.py
+++ b/Lib/fontTools/misc/intTools.py
@@ -1,23 +1,13 @@
+"""Misc integer tools."""
+
+from __future__ import print_function, absolute_import, division
+from fontTools.misc.py23 import *
+
 __all__ = ['popCount']
 
 
 def popCount(v):
-    """Return number of 1 bits (population count) of an integer.
-
-    If the integer is negative, the number of 1 bits in the
-    twos-complement representation of the integer is returned. i.e.
-    ``popCount(-30) == 28`` because -30 is::
-
-        1111 1111 1111 1111 1111 1111 1110 0010
-
-    Uses the algorithm from `HAKMEM item 169 <https://www.inwap.com/pdp10/hbaker/hakmem/hacks.html#item169>`_.
-
-    Args:
-        v (int): Value to count.
-
-    Returns:
-        Number of 1 bits in the binary representation of ``v``.
-    """
+    """Return number of 1 bits in an integer."""
 
     if v > 0xFFFFFFFF:
         return popCount(v >> 32) + popCount(v & 0xFFFFFFFF)
diff --git a/Lib/fontTools/misc/loggingTools.py b/Lib/fontTools/misc/loggingTools.py
index d1baa83..b4b9a9b 100644
--- a/Lib/fontTools/misc/loggingTools.py
+++ b/Lib/fontTools/misc/loggingTools.py
@@ -1,10 +1,23 @@
+""" fontTools.misc.loggingTools.py -- tools for interfacing with the Python
+logging package.
+"""
+
+from __future__ import print_function, absolute_import
+from fontTools.misc.py23 import *
 import sys
 import logging
 import timeit
 from functools import wraps
-from collections.abc import Mapping, Callable
+try:
+	from collections.abc import Mapping, Callable
+except ImportError:  # python < 3.3
+	from collections import Mapping, Callable
 import warnings
-from logging import PercentStyle
+
+try:
+	from logging import PercentStyle
+except ImportError:
+	PercentStyle = None
 
 
 # default logging level used by Timer class
@@ -20,18 +33,10 @@
 
 
 class LevelFormatter(logging.Formatter):
-	"""Log formatter with level-specific formatting.
-
-	Formatter class which optionally takes a dict of logging levels to
+	""" Formatter class which optionally takes a dict of logging levels to
 	format strings, allowing to customise the log records appearance for
 	specific levels.
-
-
-	Attributes:
-		fmt: A dictionary mapping logging levels to format strings.
-			The ``*`` key identifies the default format string.
-		datefmt: As per py:class:`logging.Formatter`
-		style: As per py:class:`logging.Formatter`
+	The '*' key identifies the default format string.
 
 	>>> import sys
 	>>> handler = logging.StreamHandler(sys.stdout)
@@ -59,7 +64,7 @@
 				"only '%' percent style is supported in both python 2 and 3")
 		if fmt is None:
 			fmt = DEFAULT_FORMATS
-		if isinstance(fmt, str):
+		if isinstance(fmt, basestring):
 			default_format = fmt
 			custom_formats = {}
 		elif isinstance(fmt, Mapping):
@@ -86,48 +91,46 @@
 
 
 def configLogger(**kwargs):
-	"""A more sophisticated logging system configuation manager.
+	""" Do basic configuration for the logging system. This is more or less
+	the same as logging.basicConfig with some additional options and defaults.
 
-	This is more or less the same as :py:func:`logging.basicConfig`,
-	with some additional options and defaults.
-
-	The default behaviour is to create a ``StreamHandler`` which writes to
-	sys.stderr, set a formatter using the ``DEFAULT_FORMATS`` strings, and add
+	The default behaviour is to create a StreamHandler which writes to
+	sys.stderr, set a formatter using the DEFAULT_FORMATS strings, and add
 	the handler to the top-level library logger ("fontTools").
 
 	A number of optional keyword arguments may be specified, which can alter
 	the default behaviour.
 
-	Args:
-
-		logger: Specifies the logger name or a Logger instance to be
-			configured. (Defaults to "fontTools" logger). Unlike ``basicConfig``,
-			this function can be called multiple times to reconfigure a logger.
-			If the logger or any of its children already exists before the call is
-			made, they will be reset before the new configuration is applied.
-		filename: Specifies that a ``FileHandler`` be created, using the
-			specified filename, rather than a ``StreamHandler``.
-		filemode: Specifies the mode to open the file, if filename is
-			specified. (If filemode is unspecified, it defaults to ``a``).
-		format: Use the specified format string for the handler. This
-			argument also accepts a dictionary of format strings keyed by
-			level name, to allow customising the records appearance for
-			specific levels. The special ``'*'`` key is for 'any other' level.
-		datefmt: Use the specified date/time format.
-		level: Set the logger level to the specified level.
-		stream: Use the specified stream to initialize the StreamHandler. Note
-			that this argument is incompatible with ``filename`` - if both
-			are present, ``stream`` is ignored.
-		handlers: If specified, this should be an iterable of already created
-			handlers, which will be added to the logger. Any handler in the
-			list which does not have a formatter assigned will be assigned the
-			formatter created in this function.
-		filters: If specified, this should be an iterable of already created
-			filters. If the ``handlers`` do not already have filters assigned,
-			these filters will be added to them.
-		propagate: All loggers have a ``propagate`` attribute which determines
-			whether to continue searching for handlers up the logging hierarchy.
-			If not provided, the "propagate" attribute will be set to ``False``.
+	logger    Specifies the logger name or a Logger instance to be configured.
+	          (it defaults to "fontTools" logger). Unlike basicConfig, this
+	          function can be called multiple times to reconfigure a logger.
+	          If the logger or any of its children already exists before the
+	          call is made, they will be reset before the new configuration
+	          is applied.
+	filename  Specifies that a FileHandler be created, using the specified
+	          filename, rather than a StreamHandler.
+	filemode  Specifies the mode to open the file, if filename is specified
+	          (if filemode is unspecified, it defaults to 'a').
+	format    Use the specified format string for the handler. This argument
+	          also accepts a dictionary of format strings keyed by level name,
+	          to allow customising the records appearance for specific levels.
+	          The special '*' key is for 'any other' level.
+	datefmt   Use the specified date/time format.
+	level     Set the logger level to the specified level.
+	stream    Use the specified stream to initialize the StreamHandler. Note
+	          that this argument is incompatible with 'filename' - if both
+	          are present, 'stream' is ignored.
+	handlers  If specified, this should be an iterable of already created
+	          handlers, which will be added to the logger. Any handler
+	          in the list which does not have a formatter assigned will be
+	          assigned the formatter created in this function.
+	filters   If specified, this should be an iterable of already created
+	          filters, which will be added to the handler(s), if the latter
+	          do(es) not already have filters assigned.
+	propagate All loggers have a "propagate" attribute initially set to True,
+	          which determines whether to continue searching for handlers up
+	          the logging hierarchy. By default, this arguments sets the
+	          "propagate" attribute to False.
 	"""
 	# using kwargs to enforce keyword-only arguments in py2.
 	handlers = kwargs.pop("handlers", None)
@@ -150,7 +153,7 @@
 		handlers = [h]
 	# By default, the top-level library logger is configured.
 	logger = kwargs.pop("logger", "fontTools")
-	if not logger or isinstance(logger, str):
+	if not logger or isinstance(logger, basestring):
 		# empty "" or None means the 'root' logger
 		logger = logging.getLogger(logger)
 	# before (re)configuring, reset named logger and its children (if exist)
@@ -387,11 +390,9 @@
 
 
 class ChannelsFilter(logging.Filter):
-	"""Provides a hierarchical filter for log entries based on channel names.
-
-	Filters out records emitted from a list of enabled channel names,
-	including their children. It works the same as the ``logging.Filter``
-	class, but allows the user to specify multiple channel names.
+	""" Filter out records emitted from a list of enabled channel names,
+	including their children. It works the same as the logging.Filter class,
+	but allows to specify multiple channel names.
 
 	>>> import sys
 	>>> handler = logging.StreamHandler(sys.stdout)
@@ -416,13 +417,13 @@
 	def __init__(self, *names):
 		self.names = names
 		self.num = len(names)
-		self.lengths = {n: len(n) for n in names}
+		self.lenghts = {n: len(n) for n in names}
 
 	def filter(self, record):
 		if self.num == 0:
 			return True
 		for name in self.names:
-			nlen = self.lengths[name]
+			nlen = self.lenghts[name]
 			if name == record.name:
 				return True
 			elif (record.name.find(name, 0, nlen) == 0
@@ -435,7 +436,7 @@
 	def __init__(self, logger, level):
 		super(CapturingLogHandler, self).__init__(level=level)
 		self.records = []
-		if isinstance(logger, str):
+		if isinstance(logger, basestring):
 			self.logger = logging.getLogger(logger)
 		else:
 			self.logger = logger
@@ -476,12 +477,10 @@
 
 class LogMixin(object):
 	""" Mixin class that adds logging functionality to another class.
-
-	You can define a new class that subclasses from ``LogMixin`` as well as
+	You can define a new class that subclasses from LogMixin as well as
 	other base classes through multiple inheritance.
-	All instances of that class will have a ``log`` property that returns
-	a ``logging.Logger`` named after their respective ``<module>.<class>``.
-
+	All instances of that class will have a 'log' property that returns
+	a logging.Logger named after their respective <module>.<class>.
 	For example:
 
 	>>> class BaseClass(object):
diff --git a/Lib/fontTools/misc/macCreatorType.py b/Lib/fontTools/misc/macCreatorType.py
index fb23720..2b33e89 100644
--- a/Lib/fontTools/misc/macCreatorType.py
+++ b/Lib/fontTools/misc/macCreatorType.py
@@ -1,8 +1,14 @@
-from fontTools.misc.py23 import Tag, bytesjoin, strjoin
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+import sys
 try:
 	import xattr
 except ImportError:
 	xattr = None
+try:
+	import MacOS
+except ImportError:
+	MacOS = None
 
 
 def _reverseString(s):
@@ -12,16 +18,6 @@
 
 
 def getMacCreatorAndType(path):
-	"""Returns file creator and file type codes for a path.
-
-	Args:
-		path (str): A file path.
-
-	Returns:
-		A tuple of two :py:class:`fontTools.py23.Tag` objects, the first
-		representing the file creator and the second representing the
-		file type.
-	"""
 	if xattr is not None:
 		try:
 			finderInfo = xattr.getxattr(path, 'com.apple.FinderInfo')
@@ -31,24 +27,25 @@
 			fileType = Tag(finderInfo[:4])
 			fileCreator = Tag(finderInfo[4:8])
 			return fileCreator, fileType
-	return None, None
+	if MacOS is not None:
+		fileCreator, fileType = MacOS.GetCreatorAndType(path)
+		if sys.version_info[:2] < (2, 7) and sys.byteorder == "little":
+			# work around bug in MacOS.GetCreatorAndType() on intel:
+			# http://bugs.python.org/issue1594
+			# (fixed with Python 2.7)
+			fileCreator = _reverseString(fileCreator)
+			fileType = _reverseString(fileType)
+		return fileCreator, fileType
+	else:
+		return None, None
 
 
 def setMacCreatorAndType(path, fileCreator, fileType):
-	"""Set file creator and file type codes for a path.
-
-	Note that if the ``xattr`` module is not installed, no action is
-	taken but no error is raised.
-
-	Args:
-		path (str): A file path.
-		fileCreator: A four-character file creator tag.
-		fileType: A four-character file type tag.
-
-	"""
 	if xattr is not None:
 		from fontTools.misc.textTools import pad
 		if not all(len(s) == 4 for s in (fileCreator, fileType)):
 			raise TypeError('arg must be string of 4 chars')
 		finderInfo = pad(bytesjoin([fileType, fileCreator]), 32)
 		xattr.setxattr(path, 'com.apple.FinderInfo', finderInfo)
+	if MacOS is not None:
+		MacOS.SetCreatorAndType(path, fileCreator, fileType)
diff --git a/Lib/fontTools/misc/macRes.py b/Lib/fontTools/misc/macRes.py
index 2c15b34..db832ec 100644
--- a/Lib/fontTools/misc/macRes.py
+++ b/Lib/fontTools/misc/macRes.py
@@ -1,9 +1,13 @@
-from fontTools.misc.py23 import bytesjoin, tostr
-from io import BytesIO
+""" Tools for reading Mac resource forks. """
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 import struct
 from fontTools.misc import sstruct
 from collections import OrderedDict
-from collections.abc import MutableMapping
+try:
+	from collections.abc import MutableMapping
+except ImportError:
+	from UserDict import DictMixin as MutableMapping
 
 
 class ResourceError(Exception):
@@ -11,25 +15,8 @@
 
 
 class ResourceReader(MutableMapping):
-	"""Reader for Mac OS resource forks.
 
-	Parses a resource fork and returns resources according to their type.
-	If run on OS X, this will open the resource fork in the filesystem.
-	Otherwise, it will open the file itself and attempt to read it as
-	though it were a resource fork.
-
-	The returned object can be indexed by type and iterated over,
-	returning in each case a list of py:class:`Resource` objects
-	representing all the resources of a certain type.
-
-	"""
 	def __init__(self, fileOrPath):
-		"""Open a file
-
-		Args:
-			fileOrPath: Either an object supporting a ``read`` method, an
-				``os.PathLike`` object, or a string.
-		"""
 		self._resources = OrderedDict()
 		if hasattr(fileOrPath, 'read'):
 			self.file = fileOrPath
@@ -138,7 +125,6 @@
 
 	@property
 	def types(self):
-		"""A list of the types of resources in the resource fork."""
 		return list(self._resources.keys())
 
 	def countResources(self, resType):
@@ -149,7 +135,6 @@
 			return 0
 
 	def getIndices(self, resType):
-		"""Returns a list of indices of resources of a given type."""
 		numRes = self.countResources(resType)
 		if numRes:
 			return list(range(1, numRes+1))
@@ -186,15 +171,6 @@
 
 
 class Resource(object):
-	"""Represents a resource stored within a resource fork.
-
-	Attributes:
-		type: resource type.
-		data: resource data.
-		id: ID.
-		name: resource name.
-		attr: attributes.
-	"""
 
 	def __init__(self, resType=None, resData=None, resID=None, resName=None,
 			     resAttr=None):
diff --git a/Lib/fontTools/misc/plistlib.py b/Lib/fontTools/misc/plistlib.py
new file mode 100644
index 0000000..a0e1003
--- /dev/null
+++ b/Lib/fontTools/misc/plistlib.py
@@ -0,0 +1,545 @@
+from __future__ import absolute_import, unicode_literals
+import sys
+import re
+from io import BytesIO
+from datetime import datetime
+from base64 import b64encode, b64decode
+from numbers import Integral
+
+try:
+    from collections.abc import Mapping # python >= 3.3
+except ImportError:
+    from collections import Mapping
+
+try:
+    from functools import singledispatch
+except ImportError:
+    try:
+        from singledispatch import singledispatch
+    except ImportError:
+        singledispatch = None
+
+from fontTools.misc import etree
+
+from fontTools.misc.py23 import (
+    unicode,
+    basestring,
+    tounicode,
+    tobytes,
+    SimpleNamespace,
+    range,
+)
+
+# On python3, by default we deserialize <data> elements as bytes, whereas on
+# python2 we deserialize <data> elements as plistlib.Data objects, in order
+# to distinguish them from the built-in str type (which is bytes on python2).
+# Similarly, by default on python3 we serialize bytes as <data> elements;
+# however, on python2 we serialize bytes as <string> elements (they must
+# only contain ASCII characters in this case).
+# You can pass use_builtin_types=[True|False] to load/dump etc. functions to
+# enforce the same treatment of bytes across python 2 and 3.
+# NOTE that unicode type always maps to <string> element, and plistlib.Data
+# always maps to <data> element, regardless of use_builtin_types.
+PY3 = sys.version_info[0] > 2
+if PY3:
+    USE_BUILTIN_TYPES = True
+else:
+    USE_BUILTIN_TYPES = False
+
+XML_DECLARATION = b"""<?xml version='1.0' encoding='UTF-8'?>"""
+
+PLIST_DOCTYPE = (
+    b'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" '
+    b'"http://www.apple.com/DTDs/PropertyList-1.0.dtd">'
+)
+
+# Date should conform to a subset of ISO 8601:
+# YYYY '-' MM '-' DD 'T' HH ':' MM ':' SS 'Z'
+_date_parser = re.compile(
+    r"(?P<year>\d\d\d\d)"
+    r"(?:-(?P<month>\d\d)"
+    r"(?:-(?P<day>\d\d)"
+    r"(?:T(?P<hour>\d\d)"
+    r"(?::(?P<minute>\d\d)"
+    r"(?::(?P<second>\d\d))"
+    r"?)?)?)?)?Z",
+    getattr(re, "ASCII", 0),  # py3-only
+)
+
+
+def _date_from_string(s):
+    order = ("year", "month", "day", "hour", "minute", "second")
+    gd = _date_parser.match(s).groupdict()
+    lst = []
+    for key in order:
+        val = gd[key]
+        if val is None:
+            break
+        lst.append(int(val))
+    return datetime(*lst)
+
+
+def _date_to_string(d):
+    return "%04d-%02d-%02dT%02d:%02d:%02dZ" % (
+        d.year,
+        d.month,
+        d.day,
+        d.hour,
+        d.minute,
+        d.second,
+    )
+
+
+def _encode_base64(data, maxlinelength=76, indent_level=1):
+    data = b64encode(data)
+    if data and maxlinelength:
+        # split into multiple lines right-justified to 'maxlinelength' chars
+        indent = b"\n" + b"  " * indent_level
+        max_length = max(16, maxlinelength - len(indent))
+        chunks = []
+        for i in range(0, len(data), max_length):
+            chunks.append(indent)
+            chunks.append(data[i : i + max_length])
+        chunks.append(indent)
+        data = b"".join(chunks)
+    return data
+
+
+class Data:
+    """Wrapper for binary data returned in place of the built-in bytes type
+    when loading property list data with use_builtin_types=False.
+    """
+
+    def __init__(self, data):
+        if not isinstance(data, bytes):
+            raise TypeError("Expected bytes, found %s" % type(data).__name__)
+        self.data = data
+
+    @classmethod
+    def fromBase64(cls, data):
+        return cls(b64decode(data))
+
+    def asBase64(self, maxlinelength=76, indent_level=1):
+        return _encode_base64(
+            self.data, maxlinelength=maxlinelength, indent_level=indent_level
+        )
+
+    def __eq__(self, other):
+        if isinstance(other, self.__class__):
+            return self.data == other.data
+        elif isinstance(other, bytes):
+            return self.data == other
+        else:
+            return NotImplemented
+
+    def __repr__(self):
+        return "%s(%s)" % (self.__class__.__name__, repr(self.data))
+
+
+class PlistTarget(object):
+    """ Event handler using the ElementTree Target API that can be
+    passed to a XMLParser to produce property list objects from XML.
+    It is based on the CPython plistlib module's _PlistParser class,
+    but does not use the expat parser.
+
+    >>> from fontTools.misc import etree
+    >>> parser = etree.XMLParser(target=PlistTarget())
+    >>> result = etree.XML(
+    ...     "<dict>"
+    ...     "    <key>something</key>"
+    ...     "    <string>blah</string>"
+    ...     "</dict>",
+    ...     parser=parser)
+    >>> result == {"something": "blah"}
+    True
+
+    Links:
+    https://github.com/python/cpython/blob/master/Lib/plistlib.py
+    http://lxml.de/parsing.html#the-target-parser-interface
+    """
+
+    def __init__(self, use_builtin_types=None, dict_type=dict):
+        self.stack = []
+        self.current_key = None
+        self.root = None
+        if use_builtin_types is None:
+            self._use_builtin_types = USE_BUILTIN_TYPES
+        else:
+            self._use_builtin_types = use_builtin_types
+        self._dict_type = dict_type
+
+    def start(self, tag, attrib):
+        self._data = []
+        handler = _TARGET_START_HANDLERS.get(tag)
+        if handler is not None:
+            handler(self)
+
+    def end(self, tag):
+        handler = _TARGET_END_HANDLERS.get(tag)
+        if handler is not None:
+            handler(self)
+
+    def data(self, data):
+        self._data.append(data)
+
+    def close(self):
+        return self.root
+
+    # helpers
+
+    def add_object(self, value):
+        if self.current_key is not None:
+            if not isinstance(self.stack[-1], type({})):
+                raise ValueError("unexpected element: %r" % self.stack[-1])
+            self.stack[-1][self.current_key] = value
+            self.current_key = None
+        elif not self.stack:
+            # this is the root object
+            self.root = value
+        else:
+            if not isinstance(self.stack[-1], type([])):
+                raise ValueError("unexpected element: %r" % self.stack[-1])
+            self.stack[-1].append(value)
+
+    def get_data(self):
+        data = "".join(self._data)
+        self._data = []
+        return data
+
+
+# event handlers
+
+
+def start_dict(self):
+    d = self._dict_type()
+    self.add_object(d)
+    self.stack.append(d)
+
+
+def end_dict(self):
+    if self.current_key:
+        raise ValueError("missing value for key '%s'" % self.current_key)
+    self.stack.pop()
+
+
+def end_key(self):
+    if self.current_key or not isinstance(self.stack[-1], type({})):
+        raise ValueError("unexpected key")
+    self.current_key = self.get_data()
+
+
+def start_array(self):
+    a = []
+    self.add_object(a)
+    self.stack.append(a)
+
+
+def end_array(self):
+    self.stack.pop()
+
+
+def end_true(self):
+    self.add_object(True)
+
+
+def end_false(self):
+    self.add_object(False)
+
+
+def end_integer(self):
+    self.add_object(int(self.get_data()))
+
+
+def end_real(self):
+    self.add_object(float(self.get_data()))
+
+
+def end_string(self):
+    self.add_object(self.get_data())
+
+
+def end_data(self):
+    if self._use_builtin_types:
+        self.add_object(b64decode(self.get_data()))
+    else:
+        self.add_object(Data.fromBase64(self.get_data()))
+
+
+def end_date(self):
+    self.add_object(_date_from_string(self.get_data()))
+
+
+_TARGET_START_HANDLERS = {"dict": start_dict, "array": start_array}
+
+_TARGET_END_HANDLERS = {
+    "dict": end_dict,
+    "array": end_array,
+    "key": end_key,
+    "true": end_true,
+    "false": end_false,
+    "integer": end_integer,
+    "real": end_real,
+    "string": end_string,
+    "data": end_data,
+    "date": end_date,
+}
+
+
+# functions to build element tree from plist data
+
+
+def _string_element(value, ctx):
+    el = etree.Element("string")
+    el.text = value
+    return el
+
+
+def _bool_element(value, ctx):
+    if value:
+        return etree.Element("true")
+    else:
+        return etree.Element("false")
+
+
+def _integer_element(value, ctx):
+    if -1 << 63 <= value < 1 << 64:
+        el = etree.Element("integer")
+        el.text = "%d" % value
+        return el
+    else:
+        raise OverflowError(value)
+
+
+def _real_element(value, ctx):
+    el = etree.Element("real")
+    el.text = repr(value)
+    return el
+
+
+def _dict_element(d, ctx):
+    el = etree.Element("dict")
+    items = d.items()
+    if ctx.sort_keys:
+        items = sorted(items)
+    ctx.indent_level += 1
+    for key, value in items:
+        if not isinstance(key, basestring):
+            if ctx.skipkeys:
+                continue
+            raise TypeError("keys must be strings")
+        k = etree.SubElement(el, "key")
+        k.text = tounicode(key, "utf-8")
+        el.append(_make_element(value, ctx))
+    ctx.indent_level -= 1
+    return el
+
+
+def _array_element(array, ctx):
+    el = etree.Element("array")
+    if len(array) == 0:
+        return el
+    ctx.indent_level += 1
+    for value in array:
+        el.append(_make_element(value, ctx))
+    ctx.indent_level -= 1
+    return el
+
+
+def _date_element(date, ctx):
+    el = etree.Element("date")
+    el.text = _date_to_string(date)
+    return el
+
+
+def _data_element(data, ctx):
+    el = etree.Element("data")
+    el.text = _encode_base64(
+        data,
+        maxlinelength=(76 if ctx.pretty_print else None),
+        indent_level=ctx.indent_level,
+    )
+    return el
+
+
+def _string_or_data_element(raw_bytes, ctx):
+    if ctx.use_builtin_types:
+        return _data_element(raw_bytes, ctx)
+    else:
+        try:
+            string = raw_bytes.decode(encoding="ascii", errors="strict")
+        except UnicodeDecodeError:
+            raise ValueError(
+                "invalid non-ASCII bytes; use unicode string instead: %r"
+                % raw_bytes
+            )
+        return _string_element(string, ctx)
+
+
+# if singledispatch is available, we use a generic '_make_element' function
+# and register overloaded implementations that are run based on the type of
+# the first argument
+
+if singledispatch is not None:
+
+    @singledispatch
+    def _make_element(value, ctx):
+        raise TypeError("unsupported type: %s" % type(value))
+
+    _make_element.register(unicode)(_string_element)
+    _make_element.register(bool)(_bool_element)
+    _make_element.register(Integral)(_integer_element)
+    _make_element.register(float)(_real_element)
+    _make_element.register(Mapping)(_dict_element)
+    _make_element.register(list)(_array_element)
+    _make_element.register(tuple)(_array_element)
+    _make_element.register(datetime)(_date_element)
+    _make_element.register(bytes)(_string_or_data_element)
+    _make_element.register(bytearray)(_data_element)
+    _make_element.register(Data)(lambda v, ctx: _data_element(v.data, ctx))
+
+else:
+    # otherwise we use a long switch-like if statement
+
+    def _make_element(value, ctx):
+        if isinstance(value, unicode):
+            return _string_element(value, ctx)
+        elif isinstance(value, bool):
+            return _bool_element(value, ctx)
+        elif isinstance(value, Integral):
+            return _integer_element(value, ctx)
+        elif isinstance(value, float):
+            return _real_element(value, ctx)
+        elif isinstance(value, Mapping):
+            return _dict_element(value, ctx)
+        elif isinstance(value, (list, tuple)):
+            return _array_element(value, ctx)
+        elif isinstance(value, datetime):
+            return _date_element(value, ctx)
+        elif isinstance(value, bytes):
+            return _string_or_data_element(value, ctx)
+        elif isinstance(value, bytearray):
+            return _data_element(value, ctx)
+        elif isinstance(value, Data):
+            return _data_element(value.data, ctx)
+
+
+# Public functions to create element tree from plist-compatible python
+# data structures and viceversa, for use when (de)serializing GLIF xml.
+
+
+def totree(
+    value,
+    sort_keys=True,
+    skipkeys=False,
+    use_builtin_types=None,
+    pretty_print=True,
+    indent_level=1,
+):
+    if use_builtin_types is None:
+        use_builtin_types = USE_BUILTIN_TYPES
+    else:
+        use_builtin_types = use_builtin_types
+    context = SimpleNamespace(
+        sort_keys=sort_keys,
+        skipkeys=skipkeys,
+        use_builtin_types=use_builtin_types,
+        pretty_print=pretty_print,
+        indent_level=indent_level,
+    )
+    return _make_element(value, context)
+
+
+def fromtree(tree, use_builtin_types=None, dict_type=dict):
+    target = PlistTarget(
+        use_builtin_types=use_builtin_types, dict_type=dict_type
+    )
+    for action, element in etree.iterwalk(tree, events=("start", "end")):
+        if action == "start":
+            target.start(element.tag, element.attrib)
+        elif action == "end":
+            # if there are no children, parse the leaf's data
+            if not len(element):
+                # always pass str, not None
+                target.data(element.text or "")
+            target.end(element.tag)
+    return target.close()
+
+
+# python3 plistlib API
+
+
+def load(fp, use_builtin_types=None, dict_type=dict):
+    if not hasattr(fp, "read"):
+        raise AttributeError(
+            "'%s' object has no attribute 'read'" % type(fp).__name__
+        )
+    target = PlistTarget(
+        use_builtin_types=use_builtin_types, dict_type=dict_type
+    )
+    parser = etree.XMLParser(target=target)
+    result = etree.parse(fp, parser=parser)
+    # lxml returns the target object directly, while ElementTree wraps
+    # it as the root of an ElementTree object
+    try:
+        return result.getroot()
+    except AttributeError:
+        return result
+
+
+def loads(value, use_builtin_types=None, dict_type=dict):
+    fp = BytesIO(value)
+    return load(fp, use_builtin_types=use_builtin_types, dict_type=dict_type)
+
+
+def dump(
+    value,
+    fp,
+    sort_keys=True,
+    skipkeys=False,
+    use_builtin_types=None,
+    pretty_print=True,
+):
+    if not hasattr(fp, "write"):
+        raise AttributeError(
+            "'%s' object has no attribute 'write'" % type(fp).__name__
+        )
+    root = etree.Element("plist", version="1.0")
+    el = totree(
+        value,
+        sort_keys=sort_keys,
+        skipkeys=skipkeys,
+        use_builtin_types=use_builtin_types,
+        pretty_print=pretty_print,
+    )
+    root.append(el)
+    tree = etree.ElementTree(root)
+    # we write the doctype ourselves instead of using the 'doctype' argument
+    # of 'write' method, becuse lxml will force adding a '\n' even when
+    # pretty_print is False.
+    if pretty_print:
+        header = b"\n".join((XML_DECLARATION, PLIST_DOCTYPE, b""))
+    else:
+        header = XML_DECLARATION + PLIST_DOCTYPE
+    fp.write(header)
+    tree.write(
+        fp, encoding="utf-8", pretty_print=pretty_print, xml_declaration=False
+    )
+
+
+def dumps(
+    value,
+    sort_keys=True,
+    skipkeys=False,
+    use_builtin_types=None,
+    pretty_print=True,
+):
+    fp = BytesIO()
+    dump(
+        value,
+        fp,
+        sort_keys=sort_keys,
+        skipkeys=skipkeys,
+        use_builtin_types=use_builtin_types,
+        pretty_print=pretty_print,
+    )
+    return fp.getvalue()
diff --git a/Lib/fontTools/misc/plistlib/__init__.py b/Lib/fontTools/misc/plistlib/__init__.py
deleted file mode 100644
index 84dc418..0000000
--- a/Lib/fontTools/misc/plistlib/__init__.py
+++ /dev/null
@@ -1,677 +0,0 @@
-import collections.abc
-import re
-from typing import (
-    Any,
-    Callable,
-    Dict,
-    List,
-    Mapping,
-    MutableMapping,
-    Optional,
-    Sequence,
-    Type,
-    Union,
-    IO,
-)
-import warnings
-from io import BytesIO
-from datetime import datetime
-from base64 import b64encode, b64decode
-from numbers import Integral
-from types import SimpleNamespace
-from functools import singledispatch
-
-from fontTools.misc import etree
-
-from fontTools.misc.py23 import tostr
-
-
-# By default, we
-#  - deserialize <data> elements as bytes and
-#  - serialize bytes as <data> elements.
-# Before, on Python 2, we
-#  - deserialized <data> elements as plistlib.Data objects, in order to
-#    distinguish them from the built-in str type (which is bytes on python2)
-#  - serialized bytes as <string> elements (they must have only contained
-#    ASCII characters in this case)
-# You can pass use_builtin_types=[True|False] to the load/dump etc. functions
-# to enforce a specific treatment.
-# NOTE that unicode type always maps to <string> element, and plistlib.Data
-# always maps to <data> element, regardless of use_builtin_types.
-USE_BUILTIN_TYPES = True
-
-XML_DECLARATION = b"""<?xml version='1.0' encoding='UTF-8'?>"""
-
-PLIST_DOCTYPE = (
-    b'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" '
-    b'"http://www.apple.com/DTDs/PropertyList-1.0.dtd">'
-)
-
-
-# Date should conform to a subset of ISO 8601:
-# YYYY '-' MM '-' DD 'T' HH ':' MM ':' SS 'Z'
-_date_parser = re.compile(
-    r"(?P<year>\d\d\d\d)"
-    r"(?:-(?P<month>\d\d)"
-    r"(?:-(?P<day>\d\d)"
-    r"(?:T(?P<hour>\d\d)"
-    r"(?::(?P<minute>\d\d)"
-    r"(?::(?P<second>\d\d))"
-    r"?)?)?)?)?Z",
-    re.ASCII,
-)
-
-
-def _date_from_string(s: str) -> datetime:
-    order = ("year", "month", "day", "hour", "minute", "second")
-    m = _date_parser.match(s)
-    if m is None:
-        raise ValueError(f"Expected ISO 8601 date string, but got '{s:r}'.")
-    gd = m.groupdict()
-    lst = []
-    for key in order:
-        val = gd[key]
-        if val is None:
-            break
-        lst.append(int(val))
-    # NOTE: mypy doesn't know that lst is 6 elements long.
-    return datetime(*lst)  # type:ignore
-
-
-def _date_to_string(d: datetime) -> str:
-    return "%04d-%02d-%02dT%02d:%02d:%02dZ" % (
-        d.year,
-        d.month,
-        d.day,
-        d.hour,
-        d.minute,
-        d.second,
-    )
-
-
-class Data:
-    """Represents binary data when ``use_builtin_types=False.``
-
-    This class wraps binary data loaded from a plist file when the
-    ``use_builtin_types`` argument to the loading function (:py:func:`fromtree`,
-    :py:func:`load`, :py:func:`loads`) is false.
-
-    The actual binary data is retrieved using the ``data`` attribute.
-    """
-
-    def __init__(self, data: bytes) -> None:
-        if not isinstance(data, bytes):
-            raise TypeError("Expected bytes, found %s" % type(data).__name__)
-        self.data = data
-
-    @classmethod
-    def fromBase64(cls, data: Union[bytes, str]) -> "Data":
-        return cls(b64decode(data))
-
-    def asBase64(self, maxlinelength: int = 76, indent_level: int = 1) -> bytes:
-        return _encode_base64(
-            self.data, maxlinelength=maxlinelength, indent_level=indent_level
-        )
-
-    def __eq__(self, other: Any) -> bool:
-        if isinstance(other, self.__class__):
-            return self.data == other.data
-        elif isinstance(other, bytes):
-            return self.data == other
-        else:
-            return NotImplemented
-
-    def __repr__(self) -> str:
-        return "%s(%s)" % (self.__class__.__name__, repr(self.data))
-
-
-def _encode_base64(
-    data: bytes, maxlinelength: Optional[int] = 76, indent_level: int = 1
-) -> bytes:
-    data = b64encode(data)
-    if data and maxlinelength:
-        # split into multiple lines right-justified to 'maxlinelength' chars
-        indent = b"\n" + b"  " * indent_level
-        max_length = max(16, maxlinelength - len(indent))
-        chunks = []
-        for i in range(0, len(data), max_length):
-            chunks.append(indent)
-            chunks.append(data[i : i + max_length])
-        chunks.append(indent)
-        data = b"".join(chunks)
-    return data
-
-
-# Mypy does not support recursive type aliases as of 0.782, Pylance does.
-# https://github.com/python/mypy/issues/731
-# https://devblogs.microsoft.com/python/pylance-introduces-five-new-features-that-enable-type-magic-for-python-developers/#1-support-for-recursive-type-aliases
-PlistEncodable = Union[
-    bool,
-    bytes,
-    Data,
-    datetime,
-    float,
-    int,
-    Mapping[str, Any],
-    Sequence[Any],
-    str,
-]
-
-
-class PlistTarget:
-    """Event handler using the ElementTree Target API that can be
-    passed to a XMLParser to produce property list objects from XML.
-    It is based on the CPython plistlib module's _PlistParser class,
-    but does not use the expat parser.
-
-    >>> from fontTools.misc import etree
-    >>> parser = etree.XMLParser(target=PlistTarget())
-    >>> result = etree.XML(
-    ...     "<dict>"
-    ...     "    <key>something</key>"
-    ...     "    <string>blah</string>"
-    ...     "</dict>",
-    ...     parser=parser)
-    >>> result == {"something": "blah"}
-    True
-
-    Links:
-    https://github.com/python/cpython/blob/master/Lib/plistlib.py
-    http://lxml.de/parsing.html#the-target-parser-interface
-    """
-
-    def __init__(
-        self,
-        use_builtin_types: Optional[bool] = None,
-        dict_type: Type[MutableMapping[str, Any]] = dict,
-    ) -> None:
-        self.stack: List[PlistEncodable] = []
-        self.current_key: Optional[str] = None
-        self.root: Optional[PlistEncodable] = None
-        if use_builtin_types is None:
-            self._use_builtin_types = USE_BUILTIN_TYPES
-        else:
-            if use_builtin_types is False:
-                warnings.warn(
-                    "Setting use_builtin_types to False is deprecated and will be "
-                    "removed soon.",
-                    DeprecationWarning,
-                )
-            self._use_builtin_types = use_builtin_types
-        self._dict_type = dict_type
-
-    def start(self, tag: str, attrib: Mapping[str, str]) -> None:
-        self._data: List[str] = []
-        handler = _TARGET_START_HANDLERS.get(tag)
-        if handler is not None:
-            handler(self)
-
-    def end(self, tag: str) -> None:
-        handler = _TARGET_END_HANDLERS.get(tag)
-        if handler is not None:
-            handler(self)
-
-    def data(self, data: str) -> None:
-        self._data.append(data)
-
-    def close(self) -> PlistEncodable:
-        if self.root is None:
-            raise ValueError("No root set.")
-        return self.root
-
-    # helpers
-
-    def add_object(self, value: PlistEncodable) -> None:
-        if self.current_key is not None:
-            stack_top = self.stack[-1]
-            if not isinstance(stack_top, collections.abc.MutableMapping):
-                raise ValueError("unexpected element: %r" % stack_top)
-            stack_top[self.current_key] = value
-            self.current_key = None
-        elif not self.stack:
-            # this is the root object
-            self.root = value
-        else:
-            stack_top = self.stack[-1]
-            if not isinstance(stack_top, list):
-                raise ValueError("unexpected element: %r" % stack_top)
-            stack_top.append(value)
-
-    def get_data(self) -> str:
-        data = "".join(self._data)
-        self._data = []
-        return data
-
-
-# event handlers
-
-
-def start_dict(self: PlistTarget) -> None:
-    d = self._dict_type()
-    self.add_object(d)
-    self.stack.append(d)
-
-
-def end_dict(self: PlistTarget) -> None:
-    if self.current_key:
-        raise ValueError("missing value for key '%s'" % self.current_key)
-    self.stack.pop()
-
-
-def end_key(self: PlistTarget) -> None:
-    if self.current_key or not isinstance(self.stack[-1], collections.abc.Mapping):
-        raise ValueError("unexpected key")
-    self.current_key = self.get_data()
-
-
-def start_array(self: PlistTarget) -> None:
-    a: List[PlistEncodable] = []
-    self.add_object(a)
-    self.stack.append(a)
-
-
-def end_array(self: PlistTarget) -> None:
-    self.stack.pop()
-
-
-def end_true(self: PlistTarget) -> None:
-    self.add_object(True)
-
-
-def end_false(self: PlistTarget) -> None:
-    self.add_object(False)
-
-
-def end_integer(self: PlistTarget) -> None:
-    self.add_object(int(self.get_data()))
-
-
-def end_real(self: PlistTarget) -> None:
-    self.add_object(float(self.get_data()))
-
-
-def end_string(self: PlistTarget) -> None:
-    self.add_object(self.get_data())
-
-
-def end_data(self: PlistTarget) -> None:
-    if self._use_builtin_types:
-        self.add_object(b64decode(self.get_data()))
-    else:
-        self.add_object(Data.fromBase64(self.get_data()))
-
-
-def end_date(self: PlistTarget) -> None:
-    self.add_object(_date_from_string(self.get_data()))
-
-
-_TARGET_START_HANDLERS: Dict[str, Callable[[PlistTarget], None]] = {
-    "dict": start_dict,
-    "array": start_array,
-}
-
-_TARGET_END_HANDLERS: Dict[str, Callable[[PlistTarget], None]] = {
-    "dict": end_dict,
-    "array": end_array,
-    "key": end_key,
-    "true": end_true,
-    "false": end_false,
-    "integer": end_integer,
-    "real": end_real,
-    "string": end_string,
-    "data": end_data,
-    "date": end_date,
-}
-
-
-# functions to build element tree from plist data
-
-
-def _string_element(value: str, ctx: SimpleNamespace) -> etree.Element:
-    el = etree.Element("string")
-    el.text = value
-    return el
-
-
-def _bool_element(value: bool, ctx: SimpleNamespace) -> etree.Element:
-    if value:
-        return etree.Element("true")
-    return etree.Element("false")
-
-
-def _integer_element(value: int, ctx: SimpleNamespace) -> etree.Element:
-    if -1 << 63 <= value < 1 << 64:
-        el = etree.Element("integer")
-        el.text = "%d" % value
-        return el
-    raise OverflowError(value)
-
-
-def _real_element(value: float, ctx: SimpleNamespace) -> etree.Element:
-    el = etree.Element("real")
-    el.text = repr(value)
-    return el
-
-
-def _dict_element(d: Mapping[str, PlistEncodable], ctx: SimpleNamespace) -> etree.Element:
-    el = etree.Element("dict")
-    items = d.items()
-    if ctx.sort_keys:
-        items = sorted(items)  # type: ignore
-    ctx.indent_level += 1
-    for key, value in items:
-        if not isinstance(key, str):
-            if ctx.skipkeys:
-                continue
-            raise TypeError("keys must be strings")
-        k = etree.SubElement(el, "key")
-        k.text = tostr(key, "utf-8")
-        el.append(_make_element(value, ctx))
-    ctx.indent_level -= 1
-    return el
-
-
-def _array_element(array: Sequence[PlistEncodable], ctx: SimpleNamespace) -> etree.Element:
-    el = etree.Element("array")
-    if len(array) == 0:
-        return el
-    ctx.indent_level += 1
-    for value in array:
-        el.append(_make_element(value, ctx))
-    ctx.indent_level -= 1
-    return el
-
-
-def _date_element(date: datetime, ctx: SimpleNamespace) -> etree.Element:
-    el = etree.Element("date")
-    el.text = _date_to_string(date)
-    return el
-
-
-def _data_element(data: bytes, ctx: SimpleNamespace) -> etree.Element:
-    el = etree.Element("data")
-    # NOTE: mypy is confused about whether el.text should be str or bytes.
-    el.text = _encode_base64(  # type: ignore
-        data,
-        maxlinelength=(76 if ctx.pretty_print else None),
-        indent_level=ctx.indent_level,
-    )
-    return el
-
-
-def _string_or_data_element(raw_bytes: bytes, ctx: SimpleNamespace) -> etree.Element:
-    if ctx.use_builtin_types:
-        return _data_element(raw_bytes, ctx)
-    else:
-        try:
-            string = raw_bytes.decode(encoding="ascii", errors="strict")
-        except UnicodeDecodeError:
-            raise ValueError(
-                "invalid non-ASCII bytes; use unicode string instead: %r" % raw_bytes
-            )
-        return _string_element(string, ctx)
-
-
-# The following is probably not entirely correct. The signature should take `Any`
-# and return `NoReturn`. At the time of this writing, neither mypy nor Pyright
-# can deal with singledispatch properly and will apply the signature of the base
-# function to all others. Being slightly dishonest makes it type-check and return
-# usable typing information for the optimistic case.
-@singledispatch
-def _make_element(value: PlistEncodable, ctx: SimpleNamespace) -> etree.Element:
-    raise TypeError("unsupported type: %s" % type(value))
-
-
-_make_element.register(str)(_string_element)
-_make_element.register(bool)(_bool_element)
-_make_element.register(Integral)(_integer_element)
-_make_element.register(float)(_real_element)
-_make_element.register(collections.abc.Mapping)(_dict_element)
-_make_element.register(list)(_array_element)
-_make_element.register(tuple)(_array_element)
-_make_element.register(datetime)(_date_element)
-_make_element.register(bytes)(_string_or_data_element)
-_make_element.register(bytearray)(_data_element)
-_make_element.register(Data)(lambda v, ctx: _data_element(v.data, ctx))
-
-
-# Public functions to create element tree from plist-compatible python
-# data structures and viceversa, for use when (de)serializing GLIF xml.
-
-
-def totree(
-    value: PlistEncodable,
-    sort_keys: bool = True,
-    skipkeys: bool = False,
-    use_builtin_types: Optional[bool] = None,
-    pretty_print: bool = True,
-    indent_level: int = 1,
-) -> etree.Element:
-    """Convert a value derived from a plist into an XML tree.
-
-    Args:
-        value: Any kind of value to be serialized to XML.
-        sort_keys: Whether keys of dictionaries should be sorted.
-        skipkeys (bool): Whether to silently skip non-string dictionary
-            keys.
-        use_builtin_types (bool): If true, byte strings will be
-            encoded in Base-64 and wrapped in a ``data`` tag; if
-            false, they will be either stored as ASCII strings or an
-            exception raised if they cannot be decoded as such. Defaults
-            to ``True`` if not present. Deprecated.
-        pretty_print (bool): Whether to indent the output.
-        indent_level (int): Level of indentation when serializing.
-
-    Returns: an ``etree`` ``Element`` object.
-
-    Raises:
-        ``TypeError``
-            if non-string dictionary keys are serialized
-            and ``skipkeys`` is false.
-        ``ValueError``
-            if non-ASCII binary data is present
-            and `use_builtin_types` is false.
-    """
-    if use_builtin_types is None:
-        use_builtin_types = USE_BUILTIN_TYPES
-    else:
-        use_builtin_types = use_builtin_types
-    context = SimpleNamespace(
-        sort_keys=sort_keys,
-        skipkeys=skipkeys,
-        use_builtin_types=use_builtin_types,
-        pretty_print=pretty_print,
-        indent_level=indent_level,
-    )
-    return _make_element(value, context)
-
-
-def fromtree(
-    tree: etree.Element,
-    use_builtin_types: Optional[bool] = None,
-    dict_type: Type[MutableMapping[str, Any]] = dict,
-) -> Any:
-    """Convert an XML tree to a plist structure.
-
-    Args:
-        tree: An ``etree`` ``Element``.
-        use_builtin_types: If True, binary data is deserialized to
-            bytes strings. If False, it is wrapped in :py:class:`Data`
-            objects. Defaults to True if not provided. Deprecated.
-        dict_type: What type to use for dictionaries.
-
-    Returns: An object (usually a dictionary).
-    """
-    target = PlistTarget(use_builtin_types=use_builtin_types, dict_type=dict_type)
-    for action, element in etree.iterwalk(tree, events=("start", "end")):
-        if action == "start":
-            target.start(element.tag, element.attrib)
-        elif action == "end":
-            # if there are no children, parse the leaf's data
-            if not len(element):
-                # always pass str, not None
-                target.data(element.text or "")
-            target.end(element.tag)
-    return target.close()
-
-
-# python3 plistlib API
-
-
-def load(
-    fp: IO[bytes],
-    use_builtin_types: Optional[bool] = None,
-    dict_type: Type[MutableMapping[str, Any]] = dict,
-) -> Any:
-    """Load a plist file into an object.
-
-    Args:
-        fp: An opened file.
-        use_builtin_types: If True, binary data is deserialized to
-            bytes strings. If False, it is wrapped in :py:class:`Data`
-            objects. Defaults to True if not provided. Deprecated.
-        dict_type: What type to use for dictionaries.
-
-    Returns:
-        An object (usually a dictionary) representing the top level of
-        the plist file.
-    """
-
-    if not hasattr(fp, "read"):
-        raise AttributeError("'%s' object has no attribute 'read'" % type(fp).__name__)
-    target = PlistTarget(use_builtin_types=use_builtin_types, dict_type=dict_type)
-    parser = etree.XMLParser(target=target)
-    result = etree.parse(fp, parser=parser)
-    # lxml returns the target object directly, while ElementTree wraps
-    # it as the root of an ElementTree object
-    try:
-        return result.getroot()
-    except AttributeError:
-        return result
-
-
-def loads(
-    value: bytes,
-    use_builtin_types: Optional[bool] = None,
-    dict_type: Type[MutableMapping[str, Any]] = dict,
-) -> Any:
-    """Load a plist file from a string into an object.
-
-    Args:
-        value: A bytes string containing a plist.
-        use_builtin_types: If True, binary data is deserialized to
-            bytes strings. If False, it is wrapped in :py:class:`Data`
-            objects. Defaults to True if not provided. Deprecated.
-        dict_type: What type to use for dictionaries.
-
-    Returns:
-        An object (usually a dictionary) representing the top level of
-        the plist file.
-    """
-
-    fp = BytesIO(value)
-    return load(fp, use_builtin_types=use_builtin_types, dict_type=dict_type)
-
-
-def dump(
-    value: PlistEncodable,
-    fp: IO[bytes],
-    sort_keys: bool = True,
-    skipkeys: bool = False,
-    use_builtin_types: Optional[bool] = None,
-    pretty_print: bool = True,
-) -> None:
-    """Write a Python object to a plist file.
-
-    Args:
-        value: An object to write.
-        fp: A file opened for writing.
-        sort_keys (bool): Whether keys of dictionaries should be sorted.
-        skipkeys (bool): Whether to silently skip non-string dictionary
-            keys.
-        use_builtin_types (bool): If true, byte strings will be
-            encoded in Base-64 and wrapped in a ``data`` tag; if
-            false, they will be either stored as ASCII strings or an
-            exception raised if they cannot be represented. Defaults
-        pretty_print (bool): Whether to indent the output.
-        indent_level (int): Level of indentation when serializing.
-
-    Raises:
-        ``TypeError``
-            if non-string dictionary keys are serialized
-            and ``skipkeys`` is false.
-        ``ValueError``
-            if non-representable binary data is present
-            and `use_builtin_types` is false.
-    """
-
-    if not hasattr(fp, "write"):
-        raise AttributeError("'%s' object has no attribute 'write'" % type(fp).__name__)
-    root = etree.Element("plist", version="1.0")
-    el = totree(
-        value,
-        sort_keys=sort_keys,
-        skipkeys=skipkeys,
-        use_builtin_types=use_builtin_types,
-        pretty_print=pretty_print,
-    )
-    root.append(el)
-    tree = etree.ElementTree(root)
-    # we write the doctype ourselves instead of using the 'doctype' argument
-    # of 'write' method, becuse lxml will force adding a '\n' even when
-    # pretty_print is False.
-    if pretty_print:
-        header = b"\n".join((XML_DECLARATION, PLIST_DOCTYPE, b""))
-    else:
-        header = XML_DECLARATION + PLIST_DOCTYPE
-    fp.write(header)
-    tree.write(  # type: ignore
-        fp,
-        encoding="utf-8",
-        pretty_print=pretty_print,
-        xml_declaration=False,
-    )
-
-
-def dumps(
-    value: PlistEncodable,
-    sort_keys: bool = True,
-    skipkeys: bool = False,
-    use_builtin_types: Optional[bool] = None,
-    pretty_print: bool = True,
-) -> bytes:
-    """Write a Python object to a string in plist format.
-
-    Args:
-        value: An object to write.
-        sort_keys (bool): Whether keys of dictionaries should be sorted.
-        skipkeys (bool): Whether to silently skip non-string dictionary
-            keys.
-        use_builtin_types (bool): If true, byte strings will be
-            encoded in Base-64 and wrapped in a ``data`` tag; if
-            false, they will be either stored as strings or an
-            exception raised if they cannot be represented. Defaults
-        pretty_print (bool): Whether to indent the output.
-        indent_level (int): Level of indentation when serializing.
-
-    Returns:
-        string: A plist representation of the Python object.
-
-    Raises:
-        ``TypeError``
-            if non-string dictionary keys are serialized
-            and ``skipkeys`` is false.
-        ``ValueError``
-            if non-representable binary data is present
-            and `use_builtin_types` is false.
-    """
-    fp = BytesIO()
-    dump(
-        value,
-        fp,
-        sort_keys=sort_keys,
-        skipkeys=skipkeys,
-        use_builtin_types=use_builtin_types,
-        pretty_print=pretty_print,
-    )
-    return fp.getvalue()
diff --git a/Lib/fontTools/misc/plistlib/py.typed b/Lib/fontTools/misc/plistlib/py.typed
deleted file mode 100644
index e69de29..0000000
--- a/Lib/fontTools/misc/plistlib/py.typed
+++ /dev/null
diff --git a/Lib/fontTools/misc/psCharStrings.py b/Lib/fontTools/misc/psCharStrings.py
index cb67505..a97ec96 100644
--- a/Lib/fontTools/misc/psCharStrings.py
+++ b/Lib/fontTools/misc/psCharStrings.py
@@ -2,10 +2,9 @@
 CFF dictionary data and Type1/Type2 CharStrings.
 """
 
-from fontTools.misc.py23 import bytechr, byteord, bytesjoin, strjoin
-from fontTools.misc.fixedTools import (
-	fixedToFloat, floatToFixed, floatToFixedToStr, strToFixedToFloat,
-)
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools.misc.fixedTools import fixedToFloat, otRound
 from fontTools.pens.boundsPen import BoundsPen
 import struct
 import logging
@@ -217,7 +216,7 @@
 
 def encodeFixed(f, pack=struct.pack):
 	"""For T2 only"""
-	value = floatToFixed(f, precisionBits=16)
+	value = otRound(f * 65536)  # convert the float to fixed point
 	if value & 0xFFFF == 0:  # check if the fractional part is zero
 		return encodeIntT2(value >> 16)  # encode only the integer part
 	else:
@@ -417,6 +416,7 @@
 			self.numRegions = self.private.getNumRegions()
 		numBlends = self.pop()
 		numOps = numBlends * (self.numRegions + 1)
+		blendArgs = self.operandStack[-numOps:]
 		del self.operandStack[-(numOps-numBlends):] # Leave the default operands on the stack.
 
 	def op_vsindex(self, index):
@@ -997,7 +997,7 @@
 			# If present, remove return and endchar operators.
 			if program and program[-1] in ("return", "endchar"):
 				program = program[:-1]
-		elif program and not isinstance(program[-1], str):
+		elif program and not isinstance(program[-1], basestring):
 			raise CharStringCompileError(
 				"T2CharString or Subr has items on the stack after last operator."
 			)
@@ -1010,7 +1010,7 @@
 		while i < end:
 			token = program[i]
 			i = i + 1
-			if isinstance(token, str):
+			if isinstance(token, basestring):
 				try:
 					bytecode.extend(bytechr(b) for b in opcodes[token])
 				except KeyError:
@@ -1043,7 +1043,8 @@
 		self.program = None
 
 	def getToken(self, index,
-			len=len, byteord=byteord, isinstance=isinstance):
+			len=len, byteord=byteord, basestring=basestring,
+			isinstance=isinstance):
 		if self.bytecode is not None:
 			if index >= len(self.bytecode):
 				return None, 0, 0
@@ -1056,7 +1057,7 @@
 				return None, 0, 0
 			token = self.program[index]
 			index = index + 1
-		isOperator = isinstance(token, str)
+		isOperator = isinstance(token, basestring)
 		return token, isOperator, index
 
 	def getBytes(self, index, nBytes):
@@ -1073,7 +1074,7 @@
 	def handle_operator(self, operator):
 		return operator
 
-	def toXML(self, xmlWriter, ttFont=None):
+	def toXML(self, xmlWriter):
 		from fontTools.misc.textTools import num2binary
 		if self.bytecode is not None:
 			xmlWriter.dumphex(self.bytecode)
@@ -1085,6 +1086,7 @@
 				if token is None:
 					break
 				if isOperator:
+					args = [str(arg) for arg in args]
 					if token in ('hintmask', 'cntrmask'):
 						hintMask, isOperator, index = self.getToken(index)
 						bits = []
@@ -1098,15 +1100,12 @@
 					xmlWriter.newline()
 					args = []
 				else:
-					if isinstance(token, float):
-						token = floatToFixedToStr(token, precisionBits=16)
-					else:
-						token = str(token)
 					args.append(token)
 			if args:
 				# NOTE: only CFF2 charstrings/subrs can have numeric arguments on
 				# the stack after the last operator. Compiling this would fail if
 				# this is part of CFF 1.0 table.
+				args = [str(arg) for arg in args]
 				line = ' '.join(args)
 				xmlWriter.write(line)
 
@@ -1127,7 +1126,7 @@
 				token = int(token)
 			except ValueError:
 				try:
-					token = strToFixedToFloat(token, precisionBits=16)
+					token = float(token)
 				except ValueError:
 					program.append(token)
 					if token in ('hintmask', 'cntrmask'):
@@ -1149,7 +1148,10 @@
 	operators, opcodes = buildOperatorDict(t1Operators)
 
 	def __init__(self, bytecode=None, program=None, subrs=None):
-		super().__init__(bytecode, program)
+		if program is None:
+			program = []
+		self.bytecode = bytecode
+		self.program = program
 		self.subrs = subrs
 
 	def getIntEncoder(self):
diff --git a/Lib/fontTools/misc/psLib.py b/Lib/fontTools/misc/psLib.py
index 916755c..e069e7b 100644
--- a/Lib/fontTools/misc/psLib.py
+++ b/Lib/fontTools/misc/psLib.py
@@ -1,23 +1,12 @@
-from fontTools.misc.py23 import bytechr, byteord, bytesjoin, tobytes, tostr
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import eexec
-from .psOperators import (
-	PSOperators,
-	ps_StandardEncoding,
-	ps_array,
-	ps_boolean,
-	ps_dict,
-	ps_integer,
-	ps_literal,
-	ps_mark,
-	ps_name,
-	ps_operator,
-	ps_procedure,
-	ps_procmark,
-	ps_real,
-	ps_string,
-)
+from .psOperators import *
 import re
-from collections.abc import Callable
+try:
+	from collections.abc import Callable
+except ImportError:  # python < 3.3
+	from collections import Callable
 from string import whitespace
 import logging
 
diff --git a/Lib/fontTools/misc/psOperators.py b/Lib/fontTools/misc/psOperators.py
index 3b378f5..4aa0281 100644
--- a/Lib/fontTools/misc/psOperators.py
+++ b/Lib/fontTools/misc/psOperators.py
@@ -1,3 +1,6 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+
 _accessstrings = {0: "", 1: "readonly", 2: "executeonly", 3: "noaccess"}
 
 
diff --git a/Lib/fontTools/misc/py23.py b/Lib/fontTools/misc/py23.py
index 9096e2e..5cddfeb 100644
--- a/Lib/fontTools/misc/py23.py
+++ b/Lib/fontTools/misc/py23.py
@@ -1,148 +1,525 @@
-"""Python 2/3 compat layer leftovers."""
+"""Python 2/3 compat layer."""
 
-import decimal as _decimal
-import math as _math
-import warnings
-from contextlib import redirect_stderr, redirect_stdout
-from io import BytesIO
-from io import StringIO as UnicodeIO
-from types import SimpleNamespace
+from __future__ import print_function, division, absolute_import
+import sys
 
-warnings.warn(
-    "The py23 module has been deprecated and will be removed in a future release. "
-    "Please update your code.",
-    DeprecationWarning,
-)
 
-__all__ = [
-    "basestring",
-    "bytechr",
-    "byteord",
-    "BytesIO",
-    "bytesjoin",
-    "open",
-    "Py23Error",
-    "range",
-    "RecursionError",
-    "round",
-    "SimpleNamespace",
-    "StringIO",
-    "strjoin",
-    "Tag",
-    "tobytes",
-    "tostr",
-    "tounicode",
-    "unichr",
-    "unicode",
-    "UnicodeIO",
-    "xrange",
-    "zip",
-]
+__all__ = ['basestring', 'unicode', 'unichr', 'byteord', 'bytechr', 'BytesIO',
+		'StringIO', 'UnicodeIO', 'strjoin', 'bytesjoin', 'tobytes', 'tostr',
+		'tounicode', 'Tag', 'open', 'range', 'xrange', 'round', 'Py23Error',
+		'SimpleNamespace', 'zip', 'RecursionError']
 
 
 class Py23Error(NotImplementedError):
-    pass
+	pass
 
 
-RecursionError = RecursionError
-StringIO = UnicodeIO
-
-basestring = str
-isclose = _math.isclose
-isfinite = _math.isfinite
-open = open
-range = range
-round = round3 = round
-unichr = chr
-unicode = str
-zip = zip
+PY3 = sys.version_info[0] == 3
+PY2 = sys.version_info[0] == 2
 
 
-def bytechr(n):
-    return bytes([n])
+try:
+	basestring = basestring
+except NameError:
+	basestring = str
+
+try:
+	unicode = unicode
+except NameError:
+	unicode = str
+
+try:
+	unichr = unichr
+
+	if sys.maxunicode < 0x10FFFF:
+		# workarounds for Python 2 "narrow" builds with UCS2-only support.
+
+		_narrow_unichr = unichr
+
+		def unichr(i):
+			"""
+			Return the unicode character whose Unicode code is the integer 'i'.
+			The valid range is 0 to 0x10FFFF inclusive.
+
+			>>> _narrow_unichr(0xFFFF + 1)
+			Traceback (most recent call last):
+			  File "<stdin>", line 1, in ?
+			ValueError: unichr() arg not in range(0x10000) (narrow Python build)
+			>>> unichr(0xFFFF + 1) == u'\U00010000'
+			True
+			>>> unichr(1114111) == u'\U0010FFFF'
+			True
+			>>> unichr(0x10FFFF + 1)
+			Traceback (most recent call last):
+			  File "<stdin>", line 1, in ?
+			ValueError: unichr() arg not in range(0x110000)
+			"""
+			try:
+				return _narrow_unichr(i)
+			except ValueError:
+				try:
+					padded_hex_str = hex(i)[2:].zfill(8)
+					escape_str = "\\U" + padded_hex_str
+					return escape_str.decode("unicode-escape")
+				except UnicodeDecodeError:
+					raise ValueError('unichr() arg not in range(0x110000)')
+
+		import re
+		_unicode_escape_RE = re.compile(r'\\U[A-Fa-f0-9]{8}')
+
+		def byteord(c):
+			"""
+			Given a 8-bit or unicode character, return an integer representing the
+			Unicode code point of the character. If a unicode argument is given, the
+			character's code point must be in the range 0 to 0x10FFFF inclusive.
+
+			>>> ord(u'\U00010000')
+			Traceback (most recent call last):
+			  File "<stdin>", line 1, in ?
+			TypeError: ord() expected a character, but string of length 2 found
+			>>> byteord(u'\U00010000') == 0xFFFF + 1
+			True
+			>>> byteord(u'\U0010FFFF') == 1114111
+			True
+			"""
+			try:
+				return ord(c)
+			except TypeError as e:
+				try:
+					escape_str = c.encode('unicode-escape')
+					if not _unicode_escape_RE.match(escape_str):
+						raise
+					hex_str = escape_str[3:]
+					return int(hex_str, 16)
+				except:
+					raise TypeError(e)
+
+	else:
+		byteord = ord
+	bytechr = chr
+
+except NameError:
+	unichr = chr
+	def bytechr(n):
+		return bytes([n])
+	def byteord(c):
+		return c if isinstance(c, int) else ord(c)
 
 
-def byteord(c):
-    return c if isinstance(c, int) else ord(c)
+# the 'io' module provides the same I/O interface on both 2 and 3.
+# here we define an alias of io.StringIO to disambiguate it eternally...
+from io import BytesIO
+from io import StringIO as UnicodeIO
+try:
+	# in python 2, by 'StringIO' we still mean a stream of *byte* strings
+	from StringIO import StringIO
+except ImportError:
+	# in Python 3, we mean instead a stream of *unicode* strings
+	StringIO = UnicodeIO
 
 
-def strjoin(iterable, joiner=""):
-    return tostr(joiner).join(iterable)
+def strjoin(iterable, joiner=''):
+	return tostr(joiner).join(iterable)
+
+def tobytes(s, encoding='ascii', errors='strict'):
+	if not isinstance(s, bytes):
+		return s.encode(encoding, errors)
+	else:
+		return s
+def tounicode(s, encoding='ascii', errors='strict'):
+	if not isinstance(s, unicode):
+		return s.decode(encoding, errors)
+	else:
+		return s
+
+if str == bytes:
+	class Tag(str):
+		def tobytes(self):
+			if isinstance(self, bytes):
+				return self
+			else:
+				return self.encode('latin1')
+
+	tostr = tobytes
+
+	bytesjoin = strjoin
+else:
+	class Tag(str):
+
+		@staticmethod
+		def transcode(blob):
+			if isinstance(blob, bytes):
+				blob = blob.decode('latin-1')
+			return blob
+
+		def __new__(self, content):
+			return str.__new__(self, self.transcode(content))
+		def __ne__(self, other):
+			return not self.__eq__(other)
+		def __eq__(self, other):
+			return str.__eq__(self, self.transcode(other))
+
+		def __hash__(self):
+			return str.__hash__(self)
+
+		def tobytes(self):
+			return self.encode('latin-1')
+
+	tostr = tounicode
+
+	def bytesjoin(iterable, joiner=b''):
+		return tobytes(joiner).join(tobytes(item) for item in iterable)
 
 
-def tobytes(s, encoding="ascii", errors="strict"):
-    if not isinstance(s, bytes):
-        return s.encode(encoding, errors)
-    else:
-        return s
+import os
+import io as _io
+
+try:
+	from msvcrt import setmode as _setmode
+except ImportError:
+	_setmode = None  # only available on the Windows platform
 
 
-def tounicode(s, encoding="ascii", errors="strict"):
-    if not isinstance(s, unicode):
-        return s.decode(encoding, errors)
-    else:
-        return s
+def open(file, mode='r', buffering=-1, encoding=None, errors=None,
+		 newline=None, closefd=True, opener=None):
+	""" Wrapper around `io.open` that bridges the differences between Python 2
+	and Python 3's built-in `open` functions. In Python 2, `io.open` is a
+	backport of Python 3's `open`, whereas in Python 3, it is an alias of the
+	built-in `open` function.
+
+	One difference is that the 'opener' keyword argument is only supported in
+	Python 3. Here we pass the value of 'opener' only when it is not None.
+	This causes Python 2 to raise TypeError, complaining about the number of
+	expected arguments, so it must be avoided in py2 or py2-3 contexts.
+
+	Another difference between 2 and 3, this time on Windows, has to do with
+	opening files by name or by file descriptor.
+
+	On the Windows C runtime, the 'O_BINARY' flag is defined which disables
+	the newlines translation ('\r\n' <=> '\n') when reading/writing files.
+	On both Python 2 and 3 this flag is always set when opening files by name.
+	This way, the newlines translation at the MSVCRT level doesn't interfere
+	with the Python io module's own newlines translation.
+
+	However, when opening files via fd, on Python 2 the fd is simply copied,
+	regardless of whether it has the 'O_BINARY' flag set or not.
+	This becomes a problem in the case of stdout, stdin, and stderr, because on
+	Windows these are opened in text mode by default (ie. don't have the
+	O_BINARY flag set).
+
+	On Python 3, this issue has been fixed, and all fds are now opened in
+	binary mode on Windows, including standard streams. Similarly here, I use
+	the `_setmode` function to ensure that integer file descriptors are
+	O_BINARY'ed before I pass them on to io.open.
+
+	For more info, see: https://bugs.python.org/issue10841
+	"""
+	if isinstance(file, int):
+		# the 'file' argument is an integer file descriptor
+		fd = file
+		if fd < 0:
+			raise ValueError('negative file descriptor')
+		if _setmode:
+			# `_setmode` function sets the line-end translation and returns the
+			# value of the previous mode. AFAIK there's no `_getmode`, so to
+			# check if the previous mode already had the bit set, I fist need
+			# to duplicate the file descriptor, set the binary flag on the copy
+			# and check the returned value.
+			fdcopy = os.dup(fd)
+			current_mode = _setmode(fdcopy, os.O_BINARY)
+			if not (current_mode & os.O_BINARY):
+				# the binary mode was not set: use the file descriptor's copy
+				file = fdcopy
+				if closefd:
+					# close the original file descriptor
+					os.close(fd)
+				else:
+					# ensure the copy is closed when the file object is closed
+					closefd = True
+			else:
+				# original file descriptor already had binary flag, close copy
+				os.close(fdcopy)
+
+	if opener is not None:
+		# "opener" is not supported on Python 2, use it at your own risk!
+		return _io.open(
+			file, mode, buffering, encoding, errors, newline, closefd,
+			opener=opener)
+	else:
+		return _io.open(
+			file, mode, buffering, encoding, errors, newline, closefd)
 
 
-tostr = tounicode
-
-
-class Tag(str):
-    @staticmethod
-    def transcode(blob):
-        if isinstance(blob, bytes):
-            blob = blob.decode("latin-1")
-        return blob
-
-    def __new__(self, content):
-        return str.__new__(self, self.transcode(content))
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __eq__(self, other):
-        return str.__eq__(self, self.transcode(other))
-
-    def __hash__(self):
-        return str.__hash__(self)
-
-    def tobytes(self):
-        return self.encode("latin-1")
-
-
-def bytesjoin(iterable, joiner=b""):
-    return tobytes(joiner).join(tobytes(item) for item in iterable)
-
+# always use iterator for 'range' and 'zip' on both py 2 and 3
+try:
+	range = xrange
+except NameError:
+	range = range
 
 def xrange(*args, **kwargs):
-    raise Py23Error("'xrange' is not defined. Use 'range' instead.")
+	raise Py23Error("'xrange' is not defined. Use 'range' instead.")
+
+try:
+	from itertools import izip as zip
+except ImportError:
+	zip = zip
 
 
-def round2(number, ndigits=None):
-    """
-    Implementation of Python 2 built-in round() function.
-    Rounds a number to a given precision in decimal digits (default
-    0 digits). The result is a floating point number. Values are rounded
-    to the closest multiple of 10 to the power minus ndigits; if two
-    multiples are equally close, rounding is done away from 0.
-    ndigits may be negative.
-    See Python 2 documentation:
-    https://docs.python.org/2/library/functions.html?highlight=round#round
-    """
-    if ndigits is None:
-        ndigits = 0
+import math as _math
 
-    if ndigits < 0:
-        exponent = 10 ** (-ndigits)
-        quotient, remainder = divmod(number, exponent)
-        if remainder >= exponent // 2 and number >= 0:
-            quotient += 1
-        return float(quotient * exponent)
-    else:
-        exponent = _decimal.Decimal("10") ** (-ndigits)
+try:
+	isclose = _math.isclose
+except AttributeError:
+	# math.isclose() was only added in Python 3.5
 
-        d = _decimal.Decimal.from_float(number).quantize(
-            exponent, rounding=_decimal.ROUND_HALF_UP
-        )
+	_isinf = _math.isinf
+	_fabs = _math.fabs
 
-        return float(d)
+	def isclose(a, b, rel_tol=1e-09, abs_tol=0):
+		"""
+		Python 2 implementation of Python 3.5 math.isclose()
+		https://hg.python.org/cpython/file/v3.5.2/Modules/mathmodule.c#l1993
+		"""
+		# sanity check on the inputs
+		if rel_tol < 0 or abs_tol < 0:
+			raise ValueError("tolerances must be non-negative")
+		# short circuit exact equality -- needed to catch two infinities of
+		# the same sign. And perhaps speeds things up a bit sometimes.
+		if a == b:
+			return True
+		# This catches the case of two infinities of opposite sign, or
+		# one infinity and one finite number. Two infinities of opposite
+		# sign would otherwise have an infinite relative tolerance.
+		# Two infinities of the same sign are caught by the equality check
+		# above.
+		if _isinf(a) or _isinf(b):
+			return False
+		# Cast to float to allow decimal.Decimal arguments
+		if not isinstance(a, float):
+			a = float(a)
+		if not isinstance(b, float):
+			b = float(b)
+		# now do the regular computation
+		# this is essentially the "weak" test from the Boost library
+		diff = _fabs(b - a)
+		result = ((diff <= _fabs(rel_tol * a)) or
+				  (diff <= _fabs(rel_tol * b)) or
+				  (diff <= abs_tol))
+		return result
+
+
+try:
+	_isfinite = _math.isfinite  # Python >= 3.2
+except AttributeError:
+	_isfinite = None
+	_isnan = _math.isnan
+	_isinf = _math.isinf
+
+
+def isfinite(f):
+	"""
+	>>> isfinite(0.0)
+	True
+	>>> isfinite(-0.1)
+	True
+	>>> isfinite(1e10)
+	True
+	>>> isfinite(float("nan"))
+	False
+	>>> isfinite(float("+inf"))
+	False
+	>>> isfinite(float("-inf"))
+	False
+	"""
+	if _isfinite is not None:
+		return _isfinite(f)
+	else:
+		return not (_isnan(f) or _isinf(f))
+
+
+import decimal as _decimal
+
+if PY3:
+	def round2(number, ndigits=None):
+		"""
+		Implementation of Python 2 built-in round() function.
+
+		Rounds a number to a given precision in decimal digits (default
+		0 digits). The result is a floating point number. Values are rounded
+		to the closest multiple of 10 to the power minus ndigits; if two
+		multiples are equally close, rounding is done away from 0.
+
+		ndigits may be negative.
+
+		See Python 2 documentation:
+		https://docs.python.org/2/library/functions.html?highlight=round#round
+		"""
+		if ndigits is None:
+			ndigits = 0
+
+		if ndigits < 0:
+			exponent = 10 ** (-ndigits)
+			quotient, remainder = divmod(number, exponent)
+			if remainder >= exponent//2 and number >= 0:
+				quotient += 1
+			return float(quotient * exponent)
+		else:
+			exponent = _decimal.Decimal('10') ** (-ndigits)
+
+			d = _decimal.Decimal.from_float(number).quantize(
+				exponent, rounding=_decimal.ROUND_HALF_UP)
+
+			return float(d)
+
+	if sys.version_info[:2] >= (3, 6):
+		# in Python 3.6, 'round3' is an alias to the built-in 'round'
+		round = round3 = round
+	else:
+		# in Python3 < 3.6 we need work around the inconsistent behavior of
+		# built-in round(), whereby floats accept a second None argument,
+		# while integers raise TypeError. See https://bugs.python.org/issue27936
+		_round = round
+
+		def round3(number, ndigits=None):
+			return _round(number) if ndigits is None else _round(number, ndigits)
+
+		round = round3
+
+else:
+	# in Python 2, 'round2' is an alias to the built-in 'round' and
+	# 'round' is shadowed by 'round3'
+	round2 = round
+
+	def round3(number, ndigits=None):
+		"""
+		Implementation of Python 3 built-in round() function.
+
+		Rounds a number to a given precision in decimal digits (default
+		0 digits). This returns an int when ndigits is omitted or is None,
+		otherwise the same type as the number.
+
+		Values are rounded to the closest multiple of 10 to the power minus
+		ndigits; if two multiples are equally close, rounding is done toward
+		the even choice (aka "Banker's Rounding"). For example, both round(0.5)
+		and round(-0.5) are 0, and round(1.5) is 2.
+
+		ndigits may be negative.
+
+		See Python 3 documentation:
+		https://docs.python.org/3/library/functions.html?highlight=round#round
+
+		Derived from python-future:
+		https://github.com/PythonCharmers/python-future/blob/master/src/future/builtins/newround.py
+		"""
+		if ndigits is None:
+			ndigits = 0
+			# return an int when called with one argument
+			totype = int
+			# shortcut if already an integer, or a float with no decimal digits
+			inumber = totype(number)
+			if inumber == number:
+				return inumber
+		else:
+			# return the same type as the number, when called with two arguments
+			totype = type(number)
+
+		m = number * (10 ** ndigits)
+		# if number is half-way between two multiples, and the mutliple that is
+		# closer to zero is even, we use the (slow) pure-Python implementation
+		if isclose(m % 1, .5) and int(m) % 2 == 0:
+			if ndigits < 0:
+				exponent = 10 ** (-ndigits)
+				quotient, remainder = divmod(number, exponent)
+				half = exponent//2
+				if remainder > half or (remainder == half and quotient % 2 != 0):
+					quotient += 1
+				d = quotient * exponent
+			else:
+				exponent = _decimal.Decimal('10') ** (-ndigits) if ndigits != 0 else 1
+
+				d = _decimal.Decimal.from_float(number).quantize(
+					exponent, rounding=_decimal.ROUND_HALF_EVEN)
+		else:
+			# else we use the built-in round() as it produces the same results
+			d = round2(number, ndigits)
+
+		return totype(d)
+
+	round = round3
+
+
+try:
+	from types import SimpleNamespace
+except ImportError:
+	class SimpleNamespace(object):
+		"""
+		A backport of Python 3.3's ``types.SimpleNamespace``.
+		"""
+		def __init__(self, **kwargs):
+			self.__dict__.update(kwargs)
+
+		def __repr__(self):
+			keys = sorted(self.__dict__)
+			items = ("{0}={1!r}".format(k, self.__dict__[k]) for k in keys)
+			return "{0}({1})".format(type(self).__name__, ", ".join(items))
+
+		def __eq__(self, other):
+			return self.__dict__ == other.__dict__
+
+
+if sys.version_info[:2] > (3, 4):
+	from contextlib import redirect_stdout, redirect_stderr
+else:
+	# `redirect_stdout` was added with python3.4, while `redirect_stderr`
+	# with python3.5. For simplicity, I redefine both for any versions
+	# less than or equal to 3.4.
+	# The code below is copied from:
+	# https://github.com/python/cpython/blob/57161aa/Lib/contextlib.py
+
+	class _RedirectStream(object):
+
+		_stream = None
+
+		def __init__(self, new_target):
+			self._new_target = new_target
+			# We use a list of old targets to make this CM re-entrant
+			self._old_targets = []
+
+		def __enter__(self):
+			self._old_targets.append(getattr(sys, self._stream))
+			setattr(sys, self._stream, self._new_target)
+			return self._new_target
+
+		def __exit__(self, exctype, excinst, exctb):
+			setattr(sys, self._stream, self._old_targets.pop())
+
+
+	class redirect_stdout(_RedirectStream):
+		"""Context manager for temporarily redirecting stdout to another file.
+			# How to send help() to stderr
+			with redirect_stdout(sys.stderr):
+				help(dir)
+			# How to write help() to a file
+			with open('help.txt', 'w') as f:
+				with redirect_stdout(f):
+					help(pow)
+		"""
+
+		_stream = "stdout"
+
+
+	class redirect_stderr(_RedirectStream):
+		"""Context manager for temporarily redirecting stderr to another file."""
+
+		_stream = "stderr"
+
+
+try:
+	RecursionError = RecursionError
+except NameError:
+	RecursionError = RuntimeError
+
+
+if __name__ == "__main__":
+	import doctest, sys
+	sys.exit(doctest.testmod().failed)
diff --git a/Lib/fontTools/misc/roundTools.py b/Lib/fontTools/misc/roundTools.py
deleted file mode 100644
index c1d546f..0000000
--- a/Lib/fontTools/misc/roundTools.py
+++ /dev/null
@@ -1,58 +0,0 @@
-"""
-Various round-to-integer helpers.
-"""
-
-import math
-import functools
-import logging
-
-log = logging.getLogger(__name__)
-
-__all__ = [
-	"noRound",
-	"otRound",
-	"maybeRound",
-	"roundFunc",
-]
-
-def noRound(value):
-	return value
-
-def otRound(value):
-	"""Round float value to nearest integer towards ``+Infinity``.
-
-	The OpenType spec (in the section on `"normalization" of OpenType Font Variations <https://docs.microsoft.com/en-us/typography/opentype/spec/otvaroverview#coordinate-scales-and-normalization>`_)
-	defines the required method for converting floating point values to
-	fixed-point. In particular it specifies the following rounding strategy:
-
-		for fractional values of 0.5 and higher, take the next higher integer;
-		for other fractional values, truncate.
-
-	This function rounds the floating-point value according to this strategy
-	in preparation for conversion to fixed-point.
-
-	Args:
-		value (float): The input floating-point value.
-
-	Returns
-		float: The rounded value.
-	"""
-	# See this thread for how we ended up with this implementation:
-	# https://github.com/fonttools/fonttools/issues/1248#issuecomment-383198166
-	return int(math.floor(value + 0.5))
-
-def maybeRound(v, tolerance, round=otRound):
-	rounded = round(v)
-	return rounded if abs(rounded - v) <= tolerance else v
-
-def roundFunc(tolerance, round=otRound):
-    if tolerance < 0:
-        raise ValueError("Rounding tolerance must be positive")
-
-    if tolerance == 0:
-        return noRound
-
-    if tolerance >= .5:
-        return round
-
-    return functools.partial(maybeRound, tolerance=tolerance, round=round)
diff --git a/Lib/fontTools/misc/sstruct.py b/Lib/fontTools/misc/sstruct.py
index ba1f878..6b7e783 100644
--- a/Lib/fontTools/misc/sstruct.py
+++ b/Lib/fontTools/misc/sstruct.py
@@ -46,7 +46,8 @@
 	it returns the size of the data in bytes.
 """
 
-from fontTools.misc.py23 import tobytes, tostr
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.fixedTools import fixedToFloat as fi2fl, floatToFixed as fl2fi
 import struct
 import re
@@ -68,7 +69,7 @@
 		if name in fixes:
 			# fixed point conversion
 			value = fl2fi(value, fixes[name])
-		elif isinstance(value, str):
+		elif isinstance(value, basestring):
 			value = tobytes(value)
 		elements.append(value)
 	data = struct.pack(*(formatstring,) + tuple(elements))
diff --git a/Lib/fontTools/misc/symfont.py b/Lib/fontTools/misc/symfont.py
index a1a8730..d09efac 100644
--- a/Lib/fontTools/misc/symfont.py
+++ b/Lib/fontTools/misc/symfont.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.pens.basePen import BasePen
 from functools import partial
 from itertools import count
@@ -111,7 +113,9 @@
 def printGreenPen(penName, funcs, file=sys.stdout):
 
 	print(
-'''from fontTools.pens.basePen import BasePen
+'''from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools.pens.basePen import BasePen
 
 class %s(BasePen):
 
diff --git a/Lib/fontTools/misc/testTools.py b/Lib/fontTools/misc/testTools.py
index 1b258e3..3759d4e 100644
--- a/Lib/fontTools/misc/testTools.py
+++ b/Lib/fontTools/misc/testTools.py
@@ -1,13 +1,17 @@
 """Helpers for writing unit tests."""
 
-from collections.abc import Iterable
-from io import BytesIO
+from __future__ import (print_function, division, absolute_import,
+                        unicode_literals)
+try:
+    from collections.abc import Iterable
+except ImportError:  # python < 3.3
+    from collections import Iterable
 import os
 import shutil
 import sys
 import tempfile
 from unittest import TestCase as _TestCase
-from fontTools.misc.py23 import tobytes
+from fontTools.misc.py23 import *
 from fontTools.misc.xmlWriter import XMLWriter
 
 
@@ -26,7 +30,7 @@
     xml = b"<root>"
     if isinstance(xmlSnippet, bytes):
         xml += xmlSnippet
-    elif isinstance(xmlSnippet, str):
+    elif isinstance(xmlSnippet, unicode):
         xml += tobytes(xmlSnippet, 'utf-8')
     elif isinstance(xmlSnippet, Iterable):
         xml += b"".join(tobytes(s, 'utf-8') for s in xmlSnippet)
@@ -69,9 +73,6 @@
     def getReverseGlyphMap(self):
         return self.reverseGlyphOrderDict_
 
-    def getGlyphNames(self):
-        return sorted(self.getGlyphOrder())
-
 
 class TestXMLReader_(object):
     def __init__(self):
diff --git a/Lib/fontTools/misc/textTools.py b/Lib/fontTools/misc/textTools.py
index 072976a..08c5990 100644
--- a/Lib/fontTools/misc/textTools.py
+++ b/Lib/fontTools/misc/textTools.py
@@ -1,7 +1,8 @@
 """fontTools.misc.textTools.py -- miscellaneous routines."""
 
 
-from fontTools.misc.py23 import bytechr, byteord, bytesjoin, strjoin, tobytes
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 import ast
 import string
 
@@ -12,7 +13,7 @@
 
 def readHex(content):
 	"""Convert a list of hex strings to binary data."""
-	return deHexStr(strjoin(chunk for chunk in content if isinstance(chunk, str)))
+	return deHexStr(strjoin(chunk for chunk in content if isinstance(chunk, basestring)))
 
 
 def deHexStr(hexdata):
diff --git a/Lib/fontTools/misc/timeTools.py b/Lib/fontTools/misc/timeTools.py
index f4b84f6..657d77f 100644
--- a/Lib/fontTools/misc/timeTools.py
+++ b/Lib/fontTools/misc/timeTools.py
@@ -1,9 +1,10 @@
 """fontTools.misc.timeTools.py -- tools for working with OpenType timestamps.
 """
 
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 import os
 import time
-from datetime import datetime, timezone
 import calendar
 
 
@@ -44,12 +45,7 @@
 	return asctime(time.gmtime(max(0, value + epoch_diff)))
 
 def timestampFromString(value):
-	wkday, mnth = value[:7].split()
-	t = datetime.strptime(value[7:], ' %d %H:%M:%S %Y')
-	t = t.replace(month=MONTHNAMES.index(mnth), tzinfo=timezone.utc)
-	wkday_idx = DAYNAMES.index(wkday)
-	assert t.weekday() == wkday_idx, '"' + value + '" has inconsistent weekday'
-	return int(t.timestamp()) - epoch_diff
+	return calendar.timegm(time.strptime(value)) - epoch_diff
 
 def timestampNow():
 	# https://reproducible-builds.org/specs/source-date-epoch/
diff --git a/Lib/fontTools/misc/transform.py b/Lib/fontTools/misc/transform.py
index 997598f..1296571 100644
--- a/Lib/fontTools/misc/transform.py
+++ b/Lib/fontTools/misc/transform.py
@@ -45,8 +45,8 @@
 	>>>
 """
 
-from typing import NamedTuple
-
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 
 __all__ = ["Transform", "Identity", "Offset", "Scale"]
 
@@ -66,7 +66,7 @@
 	return v
 
 
-class Transform(NamedTuple):
+class Transform(object):
 
 	"""2x2 transformation matrix plus offset, a.k.a. Affine transform.
 	Transform instances are immutable: all transforming methods, eg.
@@ -83,68 +83,20 @@
 		>>>
 		>>> t.scale(2, 3).transformPoint((100, 100))
 		(200, 300)
-
-	Transform's constructor takes six arguments, all of which are
-	optional, and can be used as keyword arguments:
-		>>> Transform(12)
-		<Transform [12 0 0 1 0 0]>
-		>>> Transform(dx=12)
-		<Transform [1 0 0 1 12 0]>
-		>>> Transform(yx=12)
-		<Transform [1 0 12 1 0 0]>
-
-	Transform instances also behave like sequences of length 6:
-		>>> len(Identity)
-		6
-		>>> list(Identity)
-		[1, 0, 0, 1, 0, 0]
-		>>> tuple(Identity)
-		(1, 0, 0, 1, 0, 0)
-
-	Transform instances are comparable:
-		>>> t1 = Identity.scale(2, 3).translate(4, 6)
-		>>> t2 = Identity.translate(8, 18).scale(2, 3)
-		>>> t1 == t2
-		1
-
-	But beware of floating point rounding errors:
-		>>> t1 = Identity.scale(0.2, 0.3).translate(0.4, 0.6)
-		>>> t2 = Identity.translate(0.08, 0.18).scale(0.2, 0.3)
-		>>> t1
-		<Transform [0.2 0 0 0.3 0.08 0.18]>
-		>>> t2
-		<Transform [0.2 0 0 0.3 0.08 0.18]>
-		>>> t1 == t2
-		0
-
-	Transform instances are hashable, meaning you can use them as
-	keys in dictionaries:
-		>>> d = {Scale(12, 13): None}
-		>>> d
-		{<Transform [12 0 0 13 0 0]>: None}
-
-	But again, beware of floating point rounding errors:
-		>>> t1 = Identity.scale(0.2, 0.3).translate(0.4, 0.6)
-		>>> t2 = Identity.translate(0.08, 0.18).scale(0.2, 0.3)
-		>>> t1
-		<Transform [0.2 0 0 0.3 0.08 0.18]>
-		>>> t2
-		<Transform [0.2 0 0 0.3 0.08 0.18]>
-		>>> d = {t1: None}
-		>>> d
-		{<Transform [0.2 0 0 0.3 0.08 0.18]>: None}
-		>>> d[t2]
-		Traceback (most recent call last):
-		  File "<stdin>", line 1, in ?
-		KeyError: <Transform [0.2 0 0 0.3 0.08 0.18]>
 	"""
 
-	xx: float = 1
-	xy: float = 0
-	yx: float = 0
-	yy: float = 1
-	dx: float = 0
-	dy: float = 0
+	def __init__(self, xx=1, xy=0, yx=0, yy=1, dx=0, dy=0):
+		"""Transform's constructor takes six arguments, all of which are
+		optional, and can be used as keyword arguments:
+			>>> Transform(12)
+			<Transform [12 0 0 1 0 0]>
+			>>> Transform(dx=12)
+			<Transform [1 0 0 1 12 0]>
+			>>> Transform(yx=12)
+			<Transform [1 0 12 1 0 0]>
+			>>>
+		"""
+		self.__affine = xx, xy, yx, yy, dx, dy
 
 	def transformPoint(self, p):
 		"""Transform a point.
@@ -156,7 +108,7 @@
 			(250.0, 550.0)
 		"""
 		(x, y) = p
-		xx, xy, yx, yy, dx, dy = self
+		xx, xy, yx, yy, dx, dy = self.__affine
 		return (xx*x + yx*y + dx, xy*x + yy*y + dy)
 
 	def transformPoints(self, points):
@@ -168,7 +120,7 @@
 			[(0, 0), (0, 300), (200, 300), (200, 0)]
 			>>>
 		"""
-		xx, xy, yx, yy, dx, dy = self
+		xx, xy, yx, yy, dx, dy = self.__affine
 		return [(xx*x + yx*y + dx, xy*x + yy*y + dy) for x, y in points]
 
 	def translate(self, x=0, y=0):
@@ -237,7 +189,7 @@
 			>>>
 		"""
 		xx1, xy1, yx1, yy1, dx1, dy1 = other
-		xx2, xy2, yx2, yy2, dx2, dy2 = self
+		xx2, xy2, yx2, yy2, dx2, dy2 = self.__affine
 		return self.__class__(
 				xx1*xx2 + xy1*yx2,
 				xx1*xy2 + xy1*yy2,
@@ -259,7 +211,7 @@
 			<Transform [8 6 6 3 21 15]>
 			>>>
 		"""
-		xx1, xy1, yx1, yy1, dx1, dy1 = self
+		xx1, xy1, yx1, yy1, dx1, dy1 = self.__affine
 		xx2, xy2, yx2, yy2, dx2, dy2 = other
 		return self.__class__(
 				xx1*xx2 + xy1*yx2,
@@ -281,9 +233,9 @@
 			(10.0, 20.0)
 			>>>
 		"""
-		if self == Identity:
+		if self.__affine == (1, 0, 0, 1, 0, 0):
 			return self
-		xx, xy, yx, yy, dx, dy = self
+		xx, xy, yx, yy, dx, dy = self.__affine
 		det = xx*yy - yx*xy
 		xx, xy, yx, yy = yy/det, -xy/det, -yx/det, xx/det
 		dx, dy = -xx*dx - yx*dy, -xy*dx - yy*dy
@@ -296,7 +248,77 @@
 			'[2 0 0 3 8 15]'
 			>>>
 		"""
-		return "[%s %s %s %s %s %s]" % self
+		return "[%s %s %s %s %s %s]" % self.__affine
+
+	def __len__(self):
+		"""Transform instances also behave like sequences of length 6:
+			>>> len(Identity)
+			6
+			>>>
+		"""
+		return 6
+
+	def __getitem__(self, index):
+		"""Transform instances also behave like sequences of length 6:
+			>>> list(Identity)
+			[1, 0, 0, 1, 0, 0]
+			>>> tuple(Identity)
+			(1, 0, 0, 1, 0, 0)
+			>>>
+		"""
+		return self.__affine[index]
+
+	def __ne__(self, other):
+		return not self.__eq__(other)
+	def __eq__(self, other):
+		"""Transform instances are comparable:
+			>>> t1 = Identity.scale(2, 3).translate(4, 6)
+			>>> t2 = Identity.translate(8, 18).scale(2, 3)
+			>>> t1 == t2
+			1
+			>>>
+
+		But beware of floating point rounding errors:
+			>>> t1 = Identity.scale(0.2, 0.3).translate(0.4, 0.6)
+			>>> t2 = Identity.translate(0.08, 0.18).scale(0.2, 0.3)
+			>>> t1
+			<Transform [0.2 0 0 0.3 0.08 0.18]>
+			>>> t2
+			<Transform [0.2 0 0 0.3 0.08 0.18]>
+			>>> t1 == t2
+			0
+			>>>
+		"""
+		xx1, xy1, yx1, yy1, dx1, dy1 = self.__affine
+		xx2, xy2, yx2, yy2, dx2, dy2 = other
+		return (xx1, xy1, yx1, yy1, dx1, dy1) == \
+				(xx2, xy2, yx2, yy2, dx2, dy2)
+
+	def __hash__(self):
+		"""Transform instances are hashable, meaning you can use them as
+		keys in dictionaries:
+			>>> d = {Scale(12, 13): None}
+			>>> d
+			{<Transform [12 0 0 13 0 0]>: None}
+			>>>
+
+		But again, beware of floating point rounding errors:
+			>>> t1 = Identity.scale(0.2, 0.3).translate(0.4, 0.6)
+			>>> t2 = Identity.translate(0.08, 0.18).scale(0.2, 0.3)
+			>>> t1
+			<Transform [0.2 0 0 0.3 0.08 0.18]>
+			>>> t2
+			<Transform [0.2 0 0 0.3 0.08 0.18]>
+			>>> d = {t1: None}
+			>>> d
+			{<Transform [0.2 0 0 0.3 0.08 0.18]>: None}
+			>>> d[t2]
+			Traceback (most recent call last):
+			  File "<stdin>", line 1, in ?
+			KeyError: <Transform [0.2 0 0 0.3 0.08 0.18]>
+			>>>
+		"""
+		return hash(self.__affine)
 
 	def __bool__(self):
 		"""Returns True if transform is not identity, False otherwise.
@@ -315,10 +337,13 @@
 			>>> bool(Offset(2))
 			True
 		"""
-		return self != Identity
+		return self.__affine != Identity.__affine
+
+	__nonzero__ = __bool__
 
 	def __repr__(self):
-		return "<%s [%g %g %g %g %g %g]>" % ((self.__class__.__name__,) + self)
+		return "<%s [%g %g %g %g %g %g]>" % ((self.__class__.__name__,) \
+				+ self.__affine)
 
 
 Identity = Transform()
diff --git a/Lib/fontTools/misc/vector.py b/Lib/fontTools/misc/vector.py
deleted file mode 100644
index 81c1484..0000000
--- a/Lib/fontTools/misc/vector.py
+++ /dev/null
@@ -1,143 +0,0 @@
-from numbers import Number
-import math
-import operator
-import warnings
-
-
-__all__ = ["Vector"]
-
-
-class Vector(tuple):
-
-    """A math-like vector.
-
-    Represents an n-dimensional numeric vector. ``Vector`` objects support
-    vector addition and subtraction, scalar multiplication and division,
-    negation, rounding, and comparison tests.
-    """
-
-    __slots__ = ()
-
-    def __new__(cls, values, keep=False):
-        if keep is not False:
-            warnings.warn(
-                "the 'keep' argument has been deprecated",
-                DeprecationWarning,
-            )
-        if type(values) == Vector:
-            # No need to create a new object
-            return values
-        return super().__new__(cls, values)
-
-    def __repr__(self):
-        return f"{self.__class__.__name__}({super().__repr__()})"
-
-    def _vectorOp(self, other, op):
-        if isinstance(other, Vector):
-            assert len(self) == len(other)
-            return self.__class__(op(a, b) for a, b in zip(self, other))
-        if isinstance(other, Number):
-            return self.__class__(op(v, other) for v in self)
-        raise NotImplementedError()
-
-    def _scalarOp(self, other, op):
-        if isinstance(other, Number):
-            return self.__class__(op(v, other) for v in self)
-        raise NotImplementedError()
-
-    def _unaryOp(self, op):
-        return self.__class__(op(v) for v in self)
-
-    def __add__(self, other):
-        return self._vectorOp(other, operator.add)
-
-    __radd__ = __add__
-
-    def __sub__(self, other):
-        return self._vectorOp(other, operator.sub)
-
-    def __rsub__(self, other):
-        return self._vectorOp(other, _operator_rsub)
-
-    def __mul__(self, other):
-        return self._scalarOp(other, operator.mul)
-
-    __rmul__ = __mul__
-
-    def __truediv__(self, other):
-        return self._scalarOp(other, operator.truediv)
-
-    def __rtruediv__(self, other):
-        return self._scalarOp(other, _operator_rtruediv)
-
-    def __pos__(self):
-        return self._unaryOp(operator.pos)
-
-    def __neg__(self):
-        return self._unaryOp(operator.neg)
-
-    def __round__(self, *, round=round):
-        return self._unaryOp(round)
-
-    def __eq__(self, other):
-        if isinstance(other, list):
-            # bw compat Vector([1, 2, 3]) == [1, 2, 3]
-            other = tuple(other)
-        return super().__eq__(other)
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __bool__(self):
-        return any(self)
-
-    __nonzero__ = __bool__
-
-    def __abs__(self):
-        return math.sqrt(sum(x * x for x in self))
-
-    def length(self):
-        """Return the length of the vector. Equivalent to abs(vector)."""
-        return abs(self)
-
-    def normalized(self):
-        """Return the normalized vector of the vector."""
-        return self / abs(self)
-
-    def dot(self, other):
-        """Performs vector dot product, returning the sum of
-        ``a[0] * b[0], a[1] * b[1], ...``"""
-        assert len(self) == len(other)
-        return sum(a * b for a, b in zip(self, other))
-
-    # Deprecated methods/properties
-
-    def toInt(self):
-        warnings.warn(
-            "the 'toInt' method has been deprecated, use round(vector) instead",
-            DeprecationWarning,
-        )
-        return self.__round__()
-
-    @property
-    def values(self):
-        warnings.warn(
-            "the 'values' attribute has been deprecated, use "
-            "the vector object itself instead",
-            DeprecationWarning,
-        )
-        return list(self)
-
-    @values.setter
-    def values(self, values):
-        raise AttributeError(
-            "can't set attribute, the 'values' attribute has been deprecated",
-        )
-
-
-def _operator_rsub(a, b):
-    return operator.sub(b, a)
-
-
-def _operator_rtruediv(a, b):
-    return operator.truediv(b, a)
diff --git a/Lib/fontTools/misc/xmlReader.py b/Lib/fontTools/misc/xmlReader.py
index b2707e9..e9b5cfd 100644
--- a/Lib/fontTools/misc/xmlReader.py
+++ b/Lib/fontTools/misc/xmlReader.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools import ttLib
 from fontTools.misc.textTools import safeEval
 from fontTools.ttLib.tables.DefaultTable import DefaultTable
diff --git a/Lib/fontTools/misc/xmlWriter.py b/Lib/fontTools/misc/xmlWriter.py
index fec127a..ef51a79 100644
--- a/Lib/fontTools/misc/xmlWriter.py
+++ b/Lib/fontTools/misc/xmlWriter.py
@@ -1,6 +1,7 @@
 """xmlWriter.py -- Simple XML authoring class"""
 
-from fontTools.misc.py23 import byteord, strjoin, tobytes, tostr
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 import sys
 import os
 import string
@@ -34,8 +35,8 @@
 			self.totype = tobytes
 		except TypeError:
 			# This better not fail.
-			self.file.write('')
-			self.totype = tostr
+			self.file.write(tounicode(''))
+			self.totype = tounicode
 		self.indentwhite = self.totype(indentwhite)
 		if newlinestr is None:
 			self.newlinestr = self.totype(os.linesep)
@@ -156,7 +157,7 @@
 			return ""
 		data = ""
 		for attr, value in attributes:
-			if not isinstance(value, (bytes, str)):
+			if not isinstance(value, (bytes, unicode)):
 				value = str(value)
 			data = data + ' %s="%s"' % (attr, escapeattr(value))
 		return data
diff --git a/Lib/fontTools/mtiLib/__init__.py b/Lib/fontTools/mtiLib/__init__.py
index 667a216..beec5cb 100644
--- a/Lib/fontTools/mtiLib/__init__.py
+++ b/Lib/fontTools/mtiLib/__init__.py
@@ -6,6 +6,9 @@
 # http://monotype.github.io/OpenType_Table_Source/otl_source.html
 # https://github.com/Monotype/OpenType_Table_Source/
 
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
+from fontTools.misc.py23 import *
 from fontTools import ttLib
 from fontTools.ttLib.tables._c_m_a_p import cmap_classes
 from fontTools.ttLib.tables import otTables as ot
@@ -853,7 +856,7 @@
 
 	lookup.SubTable = subtables
 	lookup.SubTableCount = len(lookup.SubTable)
-	if lookup.SubTableCount == 0:
+	if lookup.SubTableCount is 0:
 		# Remove this return when following is fixed:
 		# https://github.com/fonttools/fonttools/issues/789
 		return None
@@ -1145,33 +1148,11 @@
 		return line
 
 def build(f, font, tableTag=None):
-	"""Convert a Monotype font layout file to an OpenType layout object
-
-	A font object must be passed, but this may be a "dummy" font; it is only
-	used for sorting glyph sets when making coverage tables and to hold the
-	OpenType layout table while it is being built.
-
-	Args:
-		f: A file object.
-		font (TTFont): A font object.
-		tableTag (string): If provided, asserts that the file contains data for the
-			given OpenType table.
-
-	Returns:
-		An object representing the table. (e.g. ``table_G_S_U_B_``)
-	"""
 	lines = Tokenizer(f)
 	return parseTable(lines, font, tableTag=tableTag)
 
 
 def main(args=None, font=None):
-	"""Convert a FontDame OTL file to TTX XML.
-
-	Writes XML output to stdout.
-
-	Args:
-		args: Command line arguments (``--font``, ``--table``, input files).
-	"""
 	import sys
 	from fontTools import configLogger
 	from fontTools.misc.testTools import MockFont
@@ -1184,31 +1165,17 @@
 	# comment this out to enable debug messages from mtiLib's logger
 	# log.setLevel(logging.DEBUG)
 
-	import argparse
-	parser = argparse.ArgumentParser(
-		"fonttools mtiLib",
-		description=main.__doc__,
-	)
-
-	parser.add_argument('--font', '-f', metavar='FILE', dest="font",
-		help="Input TTF files (used for glyph classes and sorting coverage tables)")
-	parser.add_argument('--table', '-t', metavar='TABLE', dest="tableTag",
-		help="Table to fill (sniffed from input file if not provided)")
-	parser.add_argument('inputs', metavar='FILE', type=str, nargs='+',
-		help="Input FontDame .txt files")
-
-	args = parser.parse_args(args)
-
 	if font is None:
-		if args.font:
-			font = ttLib.TTFont(args.font)
-		else:
-			font = MockFont()
+		font = MockFont()
 
-	for f in args.inputs:
+	tableTag = None
+	if args[0].startswith('-t'):
+		tableTag = args[0][2:]
+		del args[0]
+	for f in args:
 		log.debug("Processing %s", f)
 		with open(f, 'rt', encoding="utf-8") as f:
-			table = build(f, font, tableTag=args.tableTag)
+			table = build(f, font, tableTag=tableTag)
 		blob = table.compile(font) # Make sure it compiles
 		decompiled = table.__class__()
 		decompiled.decompile(blob, font) # Make sure it decompiles!
diff --git a/Lib/fontTools/mtiLib/__main__.py b/Lib/fontTools/mtiLib/__main__.py
index fe6b638..0741237 100644
--- a/Lib/fontTools/mtiLib/__main__.py
+++ b/Lib/fontTools/mtiLib/__main__.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 import sys
 from fontTools.mtiLib import main
 
diff --git a/Lib/fontTools/otlLib/builder.py b/Lib/fontTools/otlLib/builder.py
index 182f7da..a087b2d 100644
--- a/Lib/fontTools/otlLib/builder.py
+++ b/Lib/fontTools/otlLib/builder.py
@@ -1,52 +1,11 @@
-from collections import namedtuple, OrderedDict
-from fontTools.misc.fixedTools import fixedToFloat
+from __future__ import print_function, division, absolute_import
+from collections import namedtuple
 from fontTools import ttLib
 from fontTools.ttLib.tables import otTables as ot
-from fontTools.ttLib.tables.otBase import (
-    ValueRecord,
-    valueRecordFormatDict,
-    OTTableWriter,
-    CountReference,
-)
-from fontTools.ttLib.tables import otBase
-from fontTools.feaLib.ast import STATNameStatement
-from fontTools.otlLib.error import OpenTypeLibError
-from functools import reduce
-import logging
-import copy
-
-
-log = logging.getLogger(__name__)
+from fontTools.ttLib.tables.otBase import ValueRecord, valueRecordFormatDict
 
 
 def buildCoverage(glyphs, glyphMap):
-    """Builds a coverage table.
-
-    Coverage tables (as defined in the `OpenType spec <https://docs.microsoft.com/en-gb/typography/opentype/spec/chapter2#coverage-table>`_)
-    are used in all OpenType Layout lookups apart from the Extension type, and
-    define the glyphs involved in a layout subtable. This allows shaping engines
-    to compare the glyph stream with the coverage table and quickly determine
-    whether a subtable should be involved in a shaping operation.
-
-    This function takes a list of glyphs and a glyphname-to-ID map, and
-    returns a ``Coverage`` object representing the coverage table.
-
-    Example::
-
-        glyphMap = font.getReverseGlyphMap()
-        glyphs = [ "A", "B", "C" ]
-        coverage = buildCoverage(glyphs, glyphMap)
-
-    Args:
-        glyphs: a sequence of glyph names.
-        glyphMap: a glyph name to ID map, typically returned from
-            ``font.getReverseGlyphMap()``.
-
-    Returns:
-        An ``otTables.Coverage`` object or ``None`` if there are no glyphs
-        supplied.
-    """
-
     if not glyphs:
         return None
     self = ot.Coverage()
@@ -62,1399 +21,36 @@
 
 
 def buildLookup(subtables, flags=0, markFilterSet=None):
-    """Turns a collection of rules into a lookup.
-
-    A Lookup (as defined in the `OpenType Spec <https://docs.microsoft.com/en-gb/typography/opentype/spec/chapter2#lookupTbl>`_)
-    wraps the individual rules in a layout operation (substitution or
-    positioning) in a data structure expressing their overall lookup type -
-    for example, single substitution, mark-to-base attachment, and so on -
-    as well as the lookup flags and any mark filtering sets. You may import
-    the following constants to express lookup flags:
-
-    - ``LOOKUP_FLAG_RIGHT_TO_LEFT``
-    - ``LOOKUP_FLAG_IGNORE_BASE_GLYPHS``
-    - ``LOOKUP_FLAG_IGNORE_LIGATURES``
-    - ``LOOKUP_FLAG_IGNORE_MARKS``
-    - ``LOOKUP_FLAG_USE_MARK_FILTERING_SET``
-
-    Args:
-        subtables: A list of layout subtable objects (e.g.
-            ``MultipleSubst``, ``PairPos``, etc.) or ``None``.
-        flags (int): This lookup's flags.
-        markFilterSet: Either ``None`` if no mark filtering set is used, or
-            an integer representing the filtering set to be used for this
-            lookup. If a mark filtering set is provided,
-            `LOOKUP_FLAG_USE_MARK_FILTERING_SET` will be set on the lookup's
-            flags.
-
-    Returns:
-        An ``otTables.Lookup`` object or ``None`` if there are no subtables
-        supplied.
-    """
     if subtables is None:
         return None
     subtables = [st for st in subtables if st is not None]
     if not subtables:
         return None
-    assert all(
-        t.LookupType == subtables[0].LookupType for t in subtables
-    ), "all subtables must have the same LookupType; got %s" % repr(
-        [t.LookupType for t in subtables]
-    )
+    assert all(t.LookupType == subtables[0].LookupType for t in subtables), \
+        ("all subtables must have the same LookupType; got %s" %
+         repr([t.LookupType for t in subtables]))
     self = ot.Lookup()
     self.LookupType = subtables[0].LookupType
     self.LookupFlag = flags
     self.SubTable = subtables
     self.SubTableCount = len(self.SubTable)
     if markFilterSet is not None:
-        self.LookupFlag |= LOOKUP_FLAG_USE_MARK_FILTERING_SET
+        assert self.LookupFlag & LOOKUP_FLAG_USE_MARK_FILTERING_SET, \
+            ("if markFilterSet is not None, flags must set "
+             "LOOKUP_FLAG_USE_MARK_FILTERING_SET; flags=0x%04x" % flags)
         assert isinstance(markFilterSet, int), markFilterSet
         self.MarkFilteringSet = markFilterSet
     else:
-        assert (self.LookupFlag & LOOKUP_FLAG_USE_MARK_FILTERING_SET) == 0, (
-            "if markFilterSet is None, flags must not set "
-            "LOOKUP_FLAG_USE_MARK_FILTERING_SET; flags=0x%04x" % flags
-        )
+        assert (self.LookupFlag & LOOKUP_FLAG_USE_MARK_FILTERING_SET) == 0, \
+            ("if markFilterSet is None, flags must not set "
+             "LOOKUP_FLAG_USE_MARK_FILTERING_SET; flags=0x%04x" % flags)
     return self
 
 
-class LookupBuilder(object):
-    SUBTABLE_BREAK_ = "SUBTABLE_BREAK"
-
-    def __init__(self, font, location, table, lookup_type):
-        self.font = font
-        self.glyphMap = font.getReverseGlyphMap()
-        self.location = location
-        self.table, self.lookup_type = table, lookup_type
-        self.lookupflag = 0
-        self.markFilterSet = None
-        self.lookup_index = None  # assigned when making final tables
-        assert table in ("GPOS", "GSUB")
-
-    def equals(self, other):
-        return (
-            isinstance(other, self.__class__)
-            and self.table == other.table
-            and self.lookupflag == other.lookupflag
-            and self.markFilterSet == other.markFilterSet
-        )
-
-    def inferGlyphClasses(self):
-        """Infers glyph glasses for the GDEF table, such as {"cedilla":3}."""
-        return {}
-
-    def getAlternateGlyphs(self):
-        """Helper for building 'aalt' features."""
-        return {}
-
-    def buildLookup_(self, subtables):
-        return buildLookup(subtables, self.lookupflag, self.markFilterSet)
-
-    def buildMarkClasses_(self, marks):
-        """{"cedilla": ("BOTTOM", ast.Anchor), ...} --> {"BOTTOM":0, "TOP":1}
-
-        Helper for MarkBasePostBuilder, MarkLigPosBuilder, and
-        MarkMarkPosBuilder. Seems to return the same numeric IDs
-        for mark classes as the AFDKO makeotf tool.
-        """
-        ids = {}
-        for mark in sorted(marks.keys(), key=self.font.getGlyphID):
-            markClassName, _markAnchor = marks[mark]
-            if markClassName not in ids:
-                ids[markClassName] = len(ids)
-        return ids
-
-    def setBacktrackCoverage_(self, prefix, subtable):
-        subtable.BacktrackGlyphCount = len(prefix)
-        subtable.BacktrackCoverage = []
-        for p in reversed(prefix):
-            coverage = buildCoverage(p, self.glyphMap)
-            subtable.BacktrackCoverage.append(coverage)
-
-    def setLookAheadCoverage_(self, suffix, subtable):
-        subtable.LookAheadGlyphCount = len(suffix)
-        subtable.LookAheadCoverage = []
-        for s in suffix:
-            coverage = buildCoverage(s, self.glyphMap)
-            subtable.LookAheadCoverage.append(coverage)
-
-    def setInputCoverage_(self, glyphs, subtable):
-        subtable.InputGlyphCount = len(glyphs)
-        subtable.InputCoverage = []
-        for g in glyphs:
-            coverage = buildCoverage(g, self.glyphMap)
-            subtable.InputCoverage.append(coverage)
-
-    def setCoverage_(self, glyphs, subtable):
-        subtable.GlyphCount = len(glyphs)
-        subtable.Coverage = []
-        for g in glyphs:
-            coverage = buildCoverage(g, self.glyphMap)
-            subtable.Coverage.append(coverage)
-
-    def build_subst_subtables(self, mapping, klass):
-        substitutions = [{}]
-        for key in mapping:
-            if key[0] == self.SUBTABLE_BREAK_:
-                substitutions.append({})
-            else:
-                substitutions[-1][key] = mapping[key]
-        subtables = [klass(s) for s in substitutions]
-        return subtables
-
-    def add_subtable_break(self, location):
-        """Add an explicit subtable break.
-
-        Args:
-            location: A string or tuple representing the location in the
-                original source which produced this break, or ``None`` if
-                no location is provided.
-        """
-        log.warning(
-            OpenTypeLibError(
-                'unsupported "subtable" statement for lookup type', location
-            )
-        )
-
-
-class AlternateSubstBuilder(LookupBuilder):
-    """Builds an Alternate Substitution (GSUB3) lookup.
-
-    Users are expected to manually add alternate glyph substitutions to
-    the ``alternates`` attribute after the object has been initialized,
-    e.g.::
-
-        builder.alternates["A"] = ["A.alt1", "A.alt2"]
-
-    Attributes:
-        font (``fontTools.TTLib.TTFont``): A font object.
-        location: A string or tuple representing the location in the original
-            source which produced this lookup.
-        alternates: An ordered dictionary of alternates, mapping glyph names
-            to a list of names of alternates.
-        lookupflag (int): The lookup's flag
-        markFilterSet: Either ``None`` if no mark filtering set is used, or
-            an integer representing the filtering set to be used for this
-            lookup. If a mark filtering set is provided,
-            `LOOKUP_FLAG_USE_MARK_FILTERING_SET` will be set on the lookup's
-            flags.
-    """
-
-    def __init__(self, font, location):
-        LookupBuilder.__init__(self, font, location, "GSUB", 3)
-        self.alternates = OrderedDict()
-
-    def equals(self, other):
-        return LookupBuilder.equals(self, other) and self.alternates == other.alternates
-
-    def build(self):
-        """Build the lookup.
-
-        Returns:
-            An ``otTables.Lookup`` object representing the alternate
-            substitution lookup.
-        """
-        subtables = self.build_subst_subtables(
-            self.alternates, buildAlternateSubstSubtable
-        )
-        return self.buildLookup_(subtables)
-
-    def getAlternateGlyphs(self):
-        return self.alternates
-
-    def add_subtable_break(self, location):
-        self.alternates[(self.SUBTABLE_BREAK_, location)] = self.SUBTABLE_BREAK_
-
-
-class ChainContextualRule(
-    namedtuple("ChainContextualRule", ["prefix", "glyphs", "suffix", "lookups"])
-):
-    @property
-    def is_subtable_break(self):
-        return self.prefix == LookupBuilder.SUBTABLE_BREAK_
-
-
-class ChainContextualRuleset:
-    def __init__(self):
-        self.rules = []
-
-    def addRule(self, rule):
-        self.rules.append(rule)
-
-    @property
-    def hasPrefixOrSuffix(self):
-        # Do we have any prefixes/suffixes? If this is False for all
-        # rulesets, we can express the whole lookup as GPOS5/GSUB7.
-        for rule in self.rules:
-            if len(rule.prefix) > 0 or len(rule.suffix) > 0:
-                return True
-        return False
-
-    @property
-    def hasAnyGlyphClasses(self):
-        # Do we use glyph classes anywhere in the rules? If this is False
-        # we can express this subtable as a Format 1.
-        for rule in self.rules:
-            for coverage in (rule.prefix, rule.glyphs, rule.suffix):
-                if any(len(x) > 1 for x in coverage):
-                    return True
-        return False
-
-    def format2ClassDefs(self):
-        PREFIX, GLYPHS, SUFFIX = 0, 1, 2
-        classDefBuilders = []
-        for ix in [PREFIX, GLYPHS, SUFFIX]:
-            context = []
-            for r in self.rules:
-                context.append(r[ix])
-            classes = self._classBuilderForContext(context)
-            if not classes:
-                return None
-            classDefBuilders.append(classes)
-        return classDefBuilders
-
-    def _classBuilderForContext(self, context):
-        classdefbuilder = ClassDefBuilder(useClass0=False)
-        for position in context:
-            for glyphset in position:
-                glyphs = set(glyphset)
-                if not classdefbuilder.canAdd(glyphs):
-                    return None
-                classdefbuilder.add(glyphs)
-        return classdefbuilder
-
-
-class ChainContextualBuilder(LookupBuilder):
-    def equals(self, other):
-        return LookupBuilder.equals(self, other) and self.rules == other.rules
-
-    def rulesets(self):
-        # Return a list of ChainContextRuleset objects, taking explicit
-        # subtable breaks into account
-        ruleset = [ChainContextualRuleset()]
-        for rule in self.rules:
-            if rule.is_subtable_break:
-                ruleset.append(ChainContextualRuleset())
-                continue
-            ruleset[-1].addRule(rule)
-        # Squish any empty subtables
-        return [x for x in ruleset if len(x.rules) > 0]
-
-    def getCompiledSize_(self, subtables):
-        size = 0
-        for st in subtables:
-            w = OTTableWriter()
-            w["LookupType"] = CountReference(
-                {"LookupType": st.LookupType}, "LookupType"
-            )
-            # We need to make a copy here because compiling
-            # modifies the subtable (finalizing formats etc.)
-            copy.deepcopy(st).compile(w, self.font)
-            size += len(w.getAllData())
-        return size
-
-    def build(self):
-        """Build the lookup.
-
-        Returns:
-            An ``otTables.Lookup`` object representing the chained
-            contextual positioning lookup.
-        """
-        subtables = []
-        chaining = False
-        rulesets = self.rulesets()
-        chaining = any(ruleset.hasPrefixOrSuffix for ruleset in rulesets)
-        for ruleset in rulesets:
-            # Determine format strategy. We try to build formats 1, 2 and 3
-            # subtables and then work out which is best. candidates list holds
-            # the subtables in each format for this ruleset (including a dummy
-            # "format 0" to make the addressing match the format numbers).
-
-            # We can always build a format 3 lookup by accumulating each of
-            # the rules into a list, so start with that.
-            candidates = [None, None, None, []]
-            for rule in ruleset.rules:
-                candidates[3].append(self.buildFormat3Subtable(rule, chaining))
-
-            # Can we express the whole ruleset as a format 2 subtable?
-            classdefs = ruleset.format2ClassDefs()
-            if classdefs:
-                candidates[2] = [
-                    self.buildFormat2Subtable(ruleset, classdefs, chaining)
-                ]
-
-            if not ruleset.hasAnyGlyphClasses:
-                candidates[1] = [self.buildFormat1Subtable(ruleset, chaining)]
-
-            candidates = [x for x in candidates if x is not None]
-            winner = min(candidates, key=self.getCompiledSize_)
-            subtables.extend(winner)
-
-        # If we are not chaining, lookup type will be automatically fixed by
-        # buildLookup_
-        return self.buildLookup_(subtables)
-
-    def buildFormat1Subtable(self, ruleset, chaining=True):
-        st = self.newSubtable_(chaining=chaining)
-        st.Format = 1
-        st.populateDefaults()
-        coverage = set()
-        rulesetsByFirstGlyph = {}
-        ruleAttr = self.ruleAttr_(format=1, chaining=chaining)
-
-        for rule in ruleset.rules:
-            ruleAsSubtable = self.newRule_(format=1, chaining=chaining)
-
-            if chaining:
-                ruleAsSubtable.BacktrackGlyphCount = len(rule.prefix)
-                ruleAsSubtable.LookAheadGlyphCount = len(rule.suffix)
-                ruleAsSubtable.Backtrack = [list(x)[0] for x in reversed(rule.prefix)]
-                ruleAsSubtable.LookAhead = [list(x)[0] for x in rule.suffix]
-
-                ruleAsSubtable.InputGlyphCount = len(rule.glyphs)
-            else:
-                ruleAsSubtable.GlyphCount = len(rule.glyphs)
-
-            ruleAsSubtable.Input = [list(x)[0] for x in rule.glyphs[1:]]
-
-            self.buildLookupList(rule, ruleAsSubtable)
-
-            firstGlyph = list(rule.glyphs[0])[0]
-            if firstGlyph not in rulesetsByFirstGlyph:
-                coverage.add(firstGlyph)
-                rulesetsByFirstGlyph[firstGlyph] = []
-            rulesetsByFirstGlyph[firstGlyph].append(ruleAsSubtable)
-
-        st.Coverage = buildCoverage(coverage, self.glyphMap)
-        ruleSets = []
-        for g in st.Coverage.glyphs:
-            ruleSet = self.newRuleSet_(format=1, chaining=chaining)
-            setattr(ruleSet, ruleAttr, rulesetsByFirstGlyph[g])
-            setattr(ruleSet, f"{ruleAttr}Count", len(rulesetsByFirstGlyph[g]))
-            ruleSets.append(ruleSet)
-
-        setattr(st, self.ruleSetAttr_(format=1, chaining=chaining), ruleSets)
-        setattr(
-            st, self.ruleSetAttr_(format=1, chaining=chaining) + "Count", len(ruleSets)
-        )
-
-        return st
-
-    def buildFormat2Subtable(self, ruleset, classdefs, chaining=True):
-        st = self.newSubtable_(chaining=chaining)
-        st.Format = 2
-        st.populateDefaults()
-
-        if chaining:
-            (
-                st.BacktrackClassDef,
-                st.InputClassDef,
-                st.LookAheadClassDef,
-            ) = [c.build() for c in classdefs]
-        else:
-            st.ClassDef = classdefs[1].build()
-
-        inClasses = classdefs[1].classes()
-
-        classSets = []
-        for _ in inClasses:
-            classSet = self.newRuleSet_(format=2, chaining=chaining)
-            classSets.append(classSet)
-
-        coverage = set()
-        classRuleAttr = self.ruleAttr_(format=2, chaining=chaining)
-
-        for rule in ruleset.rules:
-            ruleAsSubtable = self.newRule_(format=2, chaining=chaining)
-            if chaining:
-                ruleAsSubtable.BacktrackGlyphCount = len(rule.prefix)
-                ruleAsSubtable.LookAheadGlyphCount = len(rule.suffix)
-                # The glyphs in the rule may be list, tuple, odict_keys...
-                # Order is not important anyway because they are guaranteed
-                # to be members of the same class.
-                ruleAsSubtable.Backtrack = [
-                    st.BacktrackClassDef.classDefs[list(x)[0]]
-                    for x in reversed(rule.prefix)
-                ]
-                ruleAsSubtable.LookAhead = [
-                    st.LookAheadClassDef.classDefs[list(x)[0]] for x in rule.suffix
-                ]
-
-                ruleAsSubtable.InputGlyphCount = len(rule.glyphs)
-                ruleAsSubtable.Input = [
-                    st.InputClassDef.classDefs[list(x)[0]] for x in rule.glyphs[1:]
-                ]
-                setForThisRule = classSets[
-                    st.InputClassDef.classDefs[list(rule.glyphs[0])[0]]
-                ]
-            else:
-                ruleAsSubtable.GlyphCount = len(rule.glyphs)
-                ruleAsSubtable.Class = [  # The spec calls this InputSequence
-                    st.ClassDef.classDefs[list(x)[0]] for x in rule.glyphs[1:]
-                ]
-                setForThisRule = classSets[
-                    st.ClassDef.classDefs[list(rule.glyphs[0])[0]]
-                ]
-
-            self.buildLookupList(rule, ruleAsSubtable)
-            coverage |= set(rule.glyphs[0])
-
-            getattr(setForThisRule, classRuleAttr).append(ruleAsSubtable)
-            setattr(
-                setForThisRule,
-                f"{classRuleAttr}Count",
-                getattr(setForThisRule, f"{classRuleAttr}Count") + 1,
-            )
-        setattr(st, self.ruleSetAttr_(format=2, chaining=chaining), classSets)
-        setattr(
-            st, self.ruleSetAttr_(format=2, chaining=chaining) + "Count", len(classSets)
-        )
-        st.Coverage = buildCoverage(coverage, self.glyphMap)
-        return st
-
-    def buildFormat3Subtable(self, rule, chaining=True):
-        st = self.newSubtable_(chaining=chaining)
-        st.Format = 3
-        if chaining:
-            self.setBacktrackCoverage_(rule.prefix, st)
-            self.setLookAheadCoverage_(rule.suffix, st)
-            self.setInputCoverage_(rule.glyphs, st)
-        else:
-            self.setCoverage_(rule.glyphs, st)
-        self.buildLookupList(rule, st)
-        return st
-
-    def buildLookupList(self, rule, st):
-        for sequenceIndex, lookupList in enumerate(rule.lookups):
-            if lookupList is not None:
-                if not isinstance(lookupList, list):
-                    # Can happen with synthesised lookups
-                    lookupList = [lookupList]
-                for l in lookupList:
-                    if l.lookup_index is None:
-                        if isinstance(self, ChainContextPosBuilder):
-                            other = "substitution"
-                        else:
-                            other = "positioning"
-                        raise OpenTypeLibError(
-                            "Missing index of the specified "
-                            f"lookup, might be a {other} lookup",
-                            self.location,
-                        )
-                    rec = self.newLookupRecord_(st)
-                    rec.SequenceIndex = sequenceIndex
-                    rec.LookupListIndex = l.lookup_index
-
-    def add_subtable_break(self, location):
-        self.rules.append(
-            ChainContextualRule(
-                self.SUBTABLE_BREAK_,
-                self.SUBTABLE_BREAK_,
-                self.SUBTABLE_BREAK_,
-                [self.SUBTABLE_BREAK_],
-            )
-        )
-
-    def newSubtable_(self, chaining=True):
-        subtablename = f"Context{self.subtable_type}"
-        if chaining:
-            subtablename = "Chain" + subtablename
-        st = getattr(ot, subtablename)()  # ot.ChainContextPos()/ot.ChainSubst()/etc.
-        setattr(st, f"{self.subtable_type}Count", 0)
-        setattr(st, f"{self.subtable_type}LookupRecord", [])
-        return st
-
-    # Format 1 and format 2 GSUB5/GSUB6/GPOS7/GPOS8 rulesets and rules form a family:
-    #
-    #       format 1 ruleset      format 1 rule      format 2 ruleset      format 2 rule
-    # GSUB5 SubRuleSet            SubRule            SubClassSet           SubClassRule
-    # GSUB6 ChainSubRuleSet       ChainSubRule       ChainSubClassSet      ChainSubClassRule
-    # GPOS7 PosRuleSet            PosRule            PosClassSet           PosClassRule
-    # GPOS8 ChainPosRuleSet       ChainPosRule       ChainPosClassSet      ChainPosClassRule
-    #
-    # The following functions generate the attribute names and subtables according
-    # to this naming convention.
-    def ruleSetAttr_(self, format=1, chaining=True):
-        if format == 1:
-            formatType = "Rule"
-        elif format == 2:
-            formatType = "Class"
-        else:
-            raise AssertionError(formatType)
-        subtablename = f"{self.subtable_type[0:3]}{formatType}Set"  # Sub, not Subst.
-        if chaining:
-            subtablename = "Chain" + subtablename
-        return subtablename
-
-    def ruleAttr_(self, format=1, chaining=True):
-        if format == 1:
-            formatType = ""
-        elif format == 2:
-            formatType = "Class"
-        else:
-            raise AssertionError(formatType)
-        subtablename = f"{self.subtable_type[0:3]}{formatType}Rule"  # Sub, not Subst.
-        if chaining:
-            subtablename = "Chain" + subtablename
-        return subtablename
-
-    def newRuleSet_(self, format=1, chaining=True):
-        st = getattr(
-            ot, self.ruleSetAttr_(format, chaining)
-        )()  # ot.ChainPosRuleSet()/ot.SubRuleSet()/etc.
-        st.populateDefaults()
-        return st
-
-    def newRule_(self, format=1, chaining=True):
-        st = getattr(
-            ot, self.ruleAttr_(format, chaining)
-        )()  # ot.ChainPosClassRule()/ot.SubClassRule()/etc.
-        st.populateDefaults()
-        return st
-
-    def attachSubtableWithCount_(
-        self, st, subtable_name, count_name, existing=None, index=None, chaining=False
-    ):
-        if chaining:
-            subtable_name = "Chain" + subtable_name
-            count_name = "Chain" + count_name
-
-        if not hasattr(st, count_name):
-            setattr(st, count_name, 0)
-            setattr(st, subtable_name, [])
-
-        if existing:
-            new_subtable = existing
-        else:
-            # Create a new, empty subtable from otTables
-            new_subtable = getattr(ot, subtable_name)()
-
-        setattr(st, count_name, getattr(st, count_name) + 1)
-
-        if index:
-            getattr(st, subtable_name).insert(index, new_subtable)
-        else:
-            getattr(st, subtable_name).append(new_subtable)
-
-        return new_subtable
-
-    def newLookupRecord_(self, st):
-        return self.attachSubtableWithCount_(
-            st,
-            f"{self.subtable_type}LookupRecord",
-            f"{self.subtable_type}Count",
-            chaining=False,
-        )  # Oddly, it isn't ChainSubstLookupRecord
-
-
-class ChainContextPosBuilder(ChainContextualBuilder):
-    """Builds a Chained Contextual Positioning (GPOS8) lookup.
-
-    Users are expected to manually add rules to the ``rules`` attribute after
-    the object has been initialized, e.g.::
-
-        # pos [A B] [C D] x' lookup lu1 y' z' lookup lu2 E;
-
-        prefix  = [ ["A", "B"], ["C", "D"] ]
-        suffix  = [ ["E"] ]
-        glyphs  = [ ["x"], ["y"], ["z"] ]
-        lookups = [ [lu1], None,  [lu2] ]
-        builder.rules.append( (prefix, glyphs, suffix, lookups) )
-
-    Attributes:
-        font (``fontTools.TTLib.TTFont``): A font object.
-        location: A string or tuple representing the location in the original
-            source which produced this lookup.
-        rules: A list of tuples representing the rules in this lookup.
-        lookupflag (int): The lookup's flag
-        markFilterSet: Either ``None`` if no mark filtering set is used, or
-            an integer representing the filtering set to be used for this
-            lookup. If a mark filtering set is provided,
-            `LOOKUP_FLAG_USE_MARK_FILTERING_SET` will be set on the lookup's
-            flags.
-    """
-
-    def __init__(self, font, location):
-        LookupBuilder.__init__(self, font, location, "GPOS", 8)
-        self.rules = []
-        self.subtable_type = "Pos"
-
-    def find_chainable_single_pos(self, lookups, glyphs, value):
-        """Helper for add_single_pos_chained_()"""
-        res = None
-        for lookup in lookups[::-1]:
-            if lookup == self.SUBTABLE_BREAK_:
-                return res
-            if isinstance(lookup, SinglePosBuilder) and all(
-                lookup.can_add(glyph, value) for glyph in glyphs
-            ):
-                res = lookup
-        return res
-
-
-class ChainContextSubstBuilder(ChainContextualBuilder):
-    """Builds a Chained Contextual Substitution (GSUB6) lookup.
-
-    Users are expected to manually add rules to the ``rules`` attribute after
-    the object has been initialized, e.g.::
-
-        # sub [A B] [C D] x' lookup lu1 y' z' lookup lu2 E;
-
-        prefix  = [ ["A", "B"], ["C", "D"] ]
-        suffix  = [ ["E"] ]
-        glyphs  = [ ["x"], ["y"], ["z"] ]
-        lookups = [ [lu1], None,  [lu2] ]
-        builder.rules.append( (prefix, glyphs, suffix, lookups) )
-
-    Attributes:
-        font (``fontTools.TTLib.TTFont``): A font object.
-        location: A string or tuple representing the location in the original
-            source which produced this lookup.
-        rules: A list of tuples representing the rules in this lookup.
-        lookupflag (int): The lookup's flag
-        markFilterSet: Either ``None`` if no mark filtering set is used, or
-            an integer representing the filtering set to be used for this
-            lookup. If a mark filtering set is provided,
-            `LOOKUP_FLAG_USE_MARK_FILTERING_SET` will be set on the lookup's
-            flags.
-    """
-
-    def __init__(self, font, location):
-        LookupBuilder.__init__(self, font, location, "GSUB", 6)
-        self.rules = []  # (prefix, input, suffix, lookups)
-        self.subtable_type = "Subst"
-
-    def getAlternateGlyphs(self):
-        result = {}
-        for rule in self.rules:
-            if rule.is_subtable_break:
-                continue
-            for lookups in rule.lookups:
-                if not isinstance(lookups, list):
-                    lookups = [lookups]
-                for lookup in lookups:
-                    if lookup is not None:
-                        alts = lookup.getAlternateGlyphs()
-                        for glyph, replacements in alts.items():
-                            result.setdefault(glyph, set()).update(replacements)
-        return result
-
-    def find_chainable_single_subst(self, glyphs):
-        """Helper for add_single_subst_chained_()"""
-        res = None
-        for rule in self.rules[::-1]:
-            if rule.is_subtable_break:
-                return res
-            for sub in rule.lookups:
-                if isinstance(sub, SingleSubstBuilder) and not any(
-                    g in glyphs for g in sub.mapping.keys()
-                ):
-                    res = sub
-        return res
-
-
-class LigatureSubstBuilder(LookupBuilder):
-    """Builds a Ligature Substitution (GSUB4) lookup.
-
-    Users are expected to manually add ligatures to the ``ligatures``
-    attribute after the object has been initialized, e.g.::
-
-        # sub f i by f_i;
-        builder.ligatures[("f","f","i")] = "f_f_i"
-
-    Attributes:
-        font (``fontTools.TTLib.TTFont``): A font object.
-        location: A string or tuple representing the location in the original
-            source which produced this lookup.
-        ligatures: An ordered dictionary mapping a tuple of glyph names to the
-            ligature glyphname.
-        lookupflag (int): The lookup's flag
-        markFilterSet: Either ``None`` if no mark filtering set is used, or
-            an integer representing the filtering set to be used for this
-            lookup. If a mark filtering set is provided,
-            `LOOKUP_FLAG_USE_MARK_FILTERING_SET` will be set on the lookup's
-            flags.
-    """
-
-    def __init__(self, font, location):
-        LookupBuilder.__init__(self, font, location, "GSUB", 4)
-        self.ligatures = OrderedDict()  # {('f','f','i'): 'f_f_i'}
-
-    def equals(self, other):
-        return LookupBuilder.equals(self, other) and self.ligatures == other.ligatures
-
-    def build(self):
-        """Build the lookup.
-
-        Returns:
-            An ``otTables.Lookup`` object representing the ligature
-            substitution lookup.
-        """
-        subtables = self.build_subst_subtables(
-            self.ligatures, buildLigatureSubstSubtable
-        )
-        return self.buildLookup_(subtables)
-
-    def add_subtable_break(self, location):
-        self.ligatures[(self.SUBTABLE_BREAK_, location)] = self.SUBTABLE_BREAK_
-
-
-class MultipleSubstBuilder(LookupBuilder):
-    """Builds a Multiple Substitution (GSUB2) lookup.
-
-    Users are expected to manually add substitutions to the ``mapping``
-    attribute after the object has been initialized, e.g.::
-
-        # sub uni06C0 by uni06D5.fina hamza.above;
-        builder.mapping["uni06C0"] = [ "uni06D5.fina", "hamza.above"]
-
-    Attributes:
-        font (``fontTools.TTLib.TTFont``): A font object.
-        location: A string or tuple representing the location in the original
-            source which produced this lookup.
-        mapping: An ordered dictionary mapping a glyph name to a list of
-            substituted glyph names.
-        lookupflag (int): The lookup's flag
-        markFilterSet: Either ``None`` if no mark filtering set is used, or
-            an integer representing the filtering set to be used for this
-            lookup. If a mark filtering set is provided,
-            `LOOKUP_FLAG_USE_MARK_FILTERING_SET` will be set on the lookup's
-            flags.
-    """
-
-    def __init__(self, font, location):
-        LookupBuilder.__init__(self, font, location, "GSUB", 2)
-        self.mapping = OrderedDict()
-
-    def equals(self, other):
-        return LookupBuilder.equals(self, other) and self.mapping == other.mapping
-
-    def build(self):
-        subtables = self.build_subst_subtables(self.mapping, buildMultipleSubstSubtable)
-        return self.buildLookup_(subtables)
-
-    def add_subtable_break(self, location):
-        self.mapping[(self.SUBTABLE_BREAK_, location)] = self.SUBTABLE_BREAK_
-
-
-class CursivePosBuilder(LookupBuilder):
-    """Builds a Cursive Positioning (GPOS3) lookup.
-
-    Attributes:
-        font (``fontTools.TTLib.TTFont``): A font object.
-        location: A string or tuple representing the location in the original
-            source which produced this lookup.
-        attachments: An ordered dictionary mapping a glyph name to a two-element
-            tuple of ``otTables.Anchor`` objects.
-        lookupflag (int): The lookup's flag
-        markFilterSet: Either ``None`` if no mark filtering set is used, or
-            an integer representing the filtering set to be used for this
-            lookup. If a mark filtering set is provided,
-            `LOOKUP_FLAG_USE_MARK_FILTERING_SET` will be set on the lookup's
-            flags.
-    """
-
-    def __init__(self, font, location):
-        LookupBuilder.__init__(self, font, location, "GPOS", 3)
-        self.attachments = {}
-
-    def equals(self, other):
-        return (
-            LookupBuilder.equals(self, other) and self.attachments == other.attachments
-        )
-
-    def add_attachment(self, location, glyphs, entryAnchor, exitAnchor):
-        """Adds attachment information to the cursive positioning lookup.
-
-        Args:
-            location: A string or tuple representing the location in the
-                original source which produced this lookup. (Unused.)
-            glyphs: A list of glyph names sharing these entry and exit
-                anchor locations.
-            entryAnchor: A ``otTables.Anchor`` object representing the
-                entry anchor, or ``None`` if no entry anchor is present.
-            exitAnchor: A ``otTables.Anchor`` object representing the
-                exit anchor, or ``None`` if no exit anchor is present.
-        """
-        for glyph in glyphs:
-            self.attachments[glyph] = (entryAnchor, exitAnchor)
-
-    def build(self):
-        """Build the lookup.
-
-        Returns:
-            An ``otTables.Lookup`` object representing the cursive
-            positioning lookup.
-        """
-        st = buildCursivePosSubtable(self.attachments, self.glyphMap)
-        return self.buildLookup_([st])
-
-
-class MarkBasePosBuilder(LookupBuilder):
-    """Builds a Mark-To-Base Positioning (GPOS4) lookup.
-
-    Users are expected to manually add marks and bases to the ``marks``
-    and ``bases`` attributes after the object has been initialized, e.g.::
-
-        builder.marks["acute"]   = (0, a1)
-        builder.marks["grave"]   = (0, a1)
-        builder.marks["cedilla"] = (1, a2)
-        builder.bases["a"] = {0: a3, 1: a5}
-        builder.bases["b"] = {0: a4, 1: a5}
-
-    Attributes:
-        font (``fontTools.TTLib.TTFont``): A font object.
-        location: A string or tuple representing the location in the original
-            source which produced this lookup.
-        marks: An dictionary mapping a glyph name to a two-element
-            tuple containing a mark class ID and ``otTables.Anchor`` object.
-        bases: An dictionary mapping a glyph name to a dictionary of
-            mark class IDs and ``otTables.Anchor`` object.
-        lookupflag (int): The lookup's flag
-        markFilterSet: Either ``None`` if no mark filtering set is used, or
-            an integer representing the filtering set to be used for this
-            lookup. If a mark filtering set is provided,
-            `LOOKUP_FLAG_USE_MARK_FILTERING_SET` will be set on the lookup's
-            flags.
-    """
-
-    def __init__(self, font, location):
-        LookupBuilder.__init__(self, font, location, "GPOS", 4)
-        self.marks = {}  # glyphName -> (markClassName, anchor)
-        self.bases = {}  # glyphName -> {markClassName: anchor}
-
-    def equals(self, other):
-        return (
-            LookupBuilder.equals(self, other)
-            and self.marks == other.marks
-            and self.bases == other.bases
-        )
-
-    def inferGlyphClasses(self):
-        result = {glyph: 1 for glyph in self.bases}
-        result.update({glyph: 3 for glyph in self.marks})
-        return result
-
-    def build(self):
-        """Build the lookup.
-
-        Returns:
-            An ``otTables.Lookup`` object representing the mark-to-base
-            positioning lookup.
-        """
-        markClasses = self.buildMarkClasses_(self.marks)
-        marks = {
-            mark: (markClasses[mc], anchor) for mark, (mc, anchor) in self.marks.items()
-        }
-        bases = {}
-        for glyph, anchors in self.bases.items():
-            bases[glyph] = {markClasses[mc]: anchor for (mc, anchor) in anchors.items()}
-        subtables = buildMarkBasePos(marks, bases, self.glyphMap)
-        return self.buildLookup_(subtables)
-
-
-class MarkLigPosBuilder(LookupBuilder):
-    """Builds a Mark-To-Ligature Positioning (GPOS5) lookup.
-
-    Users are expected to manually add marks and bases to the ``marks``
-    and ``ligatures`` attributes after the object has been initialized, e.g.::
-
-        builder.marks["acute"]   = (0, a1)
-        builder.marks["grave"]   = (0, a1)
-        builder.marks["cedilla"] = (1, a2)
-        builder.ligatures["f_i"] = [
-            { 0: a3, 1: a5 }, # f
-            { 0: a4, 1: a5 }  # i
-        ]
-
-    Attributes:
-        font (``fontTools.TTLib.TTFont``): A font object.
-        location: A string or tuple representing the location in the original
-            source which produced this lookup.
-        marks: An dictionary mapping a glyph name to a two-element
-            tuple containing a mark class ID and ``otTables.Anchor`` object.
-        ligatures: An dictionary mapping a glyph name to an array with one
-            element for each ligature component. Each array element should be
-            a dictionary mapping mark class IDs to ``otTables.Anchor`` objects.
-        lookupflag (int): The lookup's flag
-        markFilterSet: Either ``None`` if no mark filtering set is used, or
-            an integer representing the filtering set to be used for this
-            lookup. If a mark filtering set is provided,
-            `LOOKUP_FLAG_USE_MARK_FILTERING_SET` will be set on the lookup's
-            flags.
-    """
-
-    def __init__(self, font, location):
-        LookupBuilder.__init__(self, font, location, "GPOS", 5)
-        self.marks = {}  # glyphName -> (markClassName, anchor)
-        self.ligatures = {}  # glyphName -> [{markClassName: anchor}, ...]
-
-    def equals(self, other):
-        return (
-            LookupBuilder.equals(self, other)
-            and self.marks == other.marks
-            and self.ligatures == other.ligatures
-        )
-
-    def inferGlyphClasses(self):
-        result = {glyph: 2 for glyph in self.ligatures}
-        result.update({glyph: 3 for glyph in self.marks})
-        return result
-
-    def build(self):
-        """Build the lookup.
-
-        Returns:
-            An ``otTables.Lookup`` object representing the mark-to-ligature
-            positioning lookup.
-        """
-        markClasses = self.buildMarkClasses_(self.marks)
-        marks = {
-            mark: (markClasses[mc], anchor) for mark, (mc, anchor) in self.marks.items()
-        }
-        ligs = {}
-        for lig, components in self.ligatures.items():
-            ligs[lig] = []
-            for c in components:
-                ligs[lig].append({markClasses[mc]: a for mc, a in c.items()})
-        subtables = buildMarkLigPos(marks, ligs, self.glyphMap)
-        return self.buildLookup_(subtables)
-
-
-class MarkMarkPosBuilder(LookupBuilder):
-    """Builds a Mark-To-Mark Positioning (GPOS6) lookup.
-
-    Users are expected to manually add marks and bases to the ``marks``
-    and ``baseMarks`` attributes after the object has been initialized, e.g.::
-
-        builder.marks["acute"]     = (0, a1)
-        builder.marks["grave"]     = (0, a1)
-        builder.marks["cedilla"]   = (1, a2)
-        builder.baseMarks["acute"] = {0: a3}
-
-    Attributes:
-        font (``fontTools.TTLib.TTFont``): A font object.
-        location: A string or tuple representing the location in the original
-            source which produced this lookup.
-        marks: An dictionary mapping a glyph name to a two-element
-            tuple containing a mark class ID and ``otTables.Anchor`` object.
-        baseMarks: An dictionary mapping a glyph name to a dictionary
-            containing one item: a mark class ID and a ``otTables.Anchor`` object.
-        lookupflag (int): The lookup's flag
-        markFilterSet: Either ``None`` if no mark filtering set is used, or
-            an integer representing the filtering set to be used for this
-            lookup. If a mark filtering set is provided,
-            `LOOKUP_FLAG_USE_MARK_FILTERING_SET` will be set on the lookup's
-            flags.
-    """
-
-    def __init__(self, font, location):
-        LookupBuilder.__init__(self, font, location, "GPOS", 6)
-        self.marks = {}  # glyphName -> (markClassName, anchor)
-        self.baseMarks = {}  # glyphName -> {markClassName: anchor}
-
-    def equals(self, other):
-        return (
-            LookupBuilder.equals(self, other)
-            and self.marks == other.marks
-            and self.baseMarks == other.baseMarks
-        )
-
-    def inferGlyphClasses(self):
-        result = {glyph: 3 for glyph in self.baseMarks}
-        result.update({glyph: 3 for glyph in self.marks})
-        return result
-
-    def build(self):
-        """Build the lookup.
-
-        Returns:
-            An ``otTables.Lookup`` object representing the mark-to-mark
-            positioning lookup.
-        """
-        markClasses = self.buildMarkClasses_(self.marks)
-        markClassList = sorted(markClasses.keys(), key=markClasses.get)
-        marks = {
-            mark: (markClasses[mc], anchor) for mark, (mc, anchor) in self.marks.items()
-        }
-
-        st = ot.MarkMarkPos()
-        st.Format = 1
-        st.ClassCount = len(markClasses)
-        st.Mark1Coverage = buildCoverage(marks, self.glyphMap)
-        st.Mark2Coverage = buildCoverage(self.baseMarks, self.glyphMap)
-        st.Mark1Array = buildMarkArray(marks, self.glyphMap)
-        st.Mark2Array = ot.Mark2Array()
-        st.Mark2Array.Mark2Count = len(st.Mark2Coverage.glyphs)
-        st.Mark2Array.Mark2Record = []
-        for base in st.Mark2Coverage.glyphs:
-            anchors = [self.baseMarks[base].get(mc) for mc in markClassList]
-            st.Mark2Array.Mark2Record.append(buildMark2Record(anchors))
-        return self.buildLookup_([st])
-
-
-class ReverseChainSingleSubstBuilder(LookupBuilder):
-    """Builds a Reverse Chaining Contextual Single Substitution (GSUB8) lookup.
-
-    Users are expected to manually add substitutions to the ``substitutions``
-    attribute after the object has been initialized, e.g.::
-
-        # reversesub [a e n] d' by d.alt;
-        prefix = [ ["a", "e", "n"] ]
-        suffix = []
-        mapping = { "d": "d.alt" }
-        builder.substitutions.append( (prefix, suffix, mapping) )
-
-    Attributes:
-        font (``fontTools.TTLib.TTFont``): A font object.
-        location: A string or tuple representing the location in the original
-            source which produced this lookup.
-        substitutions: A three-element tuple consisting of a prefix sequence,
-            a suffix sequence, and a dictionary of single substitutions.
-        lookupflag (int): The lookup's flag
-        markFilterSet: Either ``None`` if no mark filtering set is used, or
-            an integer representing the filtering set to be used for this
-            lookup. If a mark filtering set is provided,
-            `LOOKUP_FLAG_USE_MARK_FILTERING_SET` will be set on the lookup's
-            flags.
-    """
-
-    def __init__(self, font, location):
-        LookupBuilder.__init__(self, font, location, "GSUB", 8)
-        self.rules = []  # (prefix, suffix, mapping)
-
-    def equals(self, other):
-        return LookupBuilder.equals(self, other) and self.rules == other.rules
-
-    def build(self):
-        """Build the lookup.
-
-        Returns:
-            An ``otTables.Lookup`` object representing the chained
-            contextual substitution lookup.
-        """
-        subtables = []
-        for prefix, suffix, mapping in self.rules:
-            st = ot.ReverseChainSingleSubst()
-            st.Format = 1
-            self.setBacktrackCoverage_(prefix, st)
-            self.setLookAheadCoverage_(suffix, st)
-            st.Coverage = buildCoverage(mapping.keys(), self.glyphMap)
-            st.GlyphCount = len(mapping)
-            st.Substitute = [mapping[g] for g in st.Coverage.glyphs]
-            subtables.append(st)
-        return self.buildLookup_(subtables)
-
-    def add_subtable_break(self, location):
-        # Nothing to do here, each substitution is in its own subtable.
-        pass
-
-
-class SingleSubstBuilder(LookupBuilder):
-    """Builds a Single Substitution (GSUB1) lookup.
-
-    Users are expected to manually add substitutions to the ``mapping``
-    attribute after the object has been initialized, e.g.::
-
-        # sub x by y;
-        builder.mapping["x"] = "y"
-
-    Attributes:
-        font (``fontTools.TTLib.TTFont``): A font object.
-        location: A string or tuple representing the location in the original
-            source which produced this lookup.
-        mapping: A dictionary mapping a single glyph name to another glyph name.
-        lookupflag (int): The lookup's flag
-        markFilterSet: Either ``None`` if no mark filtering set is used, or
-            an integer representing the filtering set to be used for this
-            lookup. If a mark filtering set is provided,
-            `LOOKUP_FLAG_USE_MARK_FILTERING_SET` will be set on the lookup's
-            flags.
-    """
-
-    def __init__(self, font, location):
-        LookupBuilder.__init__(self, font, location, "GSUB", 1)
-        self.mapping = OrderedDict()
-
-    def equals(self, other):
-        return LookupBuilder.equals(self, other) and self.mapping == other.mapping
-
-    def build(self):
-        """Build the lookup.
-
-        Returns:
-            An ``otTables.Lookup`` object representing the multiple
-            substitution lookup.
-        """
-        subtables = self.build_subst_subtables(self.mapping, buildSingleSubstSubtable)
-        return self.buildLookup_(subtables)
-
-    def getAlternateGlyphs(self):
-        return {glyph: set([repl]) for glyph, repl in self.mapping.items()}
-
-    def add_subtable_break(self, location):
-        self.mapping[(self.SUBTABLE_BREAK_, location)] = self.SUBTABLE_BREAK_
-
-
-class ClassPairPosSubtableBuilder(object):
-    """Builds class-based Pair Positioning (GPOS2 format 2) subtables.
-
-    Note that this does *not* build a GPOS2 ``otTables.Lookup`` directly,
-    but builds a list of ``otTables.PairPos`` subtables. It is used by the
-    :class:`PairPosBuilder` below.
-
-    Attributes:
-        builder (PairPosBuilder): A pair positioning lookup builder.
-    """
-
-    def __init__(self, builder):
-        self.builder_ = builder
-        self.classDef1_, self.classDef2_ = None, None
-        self.values_ = {}  # (glyphclass1, glyphclass2) --> (value1, value2)
-        self.forceSubtableBreak_ = False
-        self.subtables_ = []
-
-    def addPair(self, gc1, value1, gc2, value2):
-        """Add a pair positioning rule.
-
-        Args:
-            gc1: A set of glyph names for the "left" glyph
-            value1: An ``otTables.ValueRecord`` object for the left glyph's
-                positioning.
-            gc2: A set of glyph names for the "right" glyph
-            value2: An ``otTables.ValueRecord`` object for the right glyph's
-                positioning.
-        """
-        mergeable = (
-            not self.forceSubtableBreak_
-            and self.classDef1_ is not None
-            and self.classDef1_.canAdd(gc1)
-            and self.classDef2_ is not None
-            and self.classDef2_.canAdd(gc2)
-        )
-        if not mergeable:
-            self.flush_()
-            self.classDef1_ = ClassDefBuilder(useClass0=True)
-            self.classDef2_ = ClassDefBuilder(useClass0=False)
-            self.values_ = {}
-        self.classDef1_.add(gc1)
-        self.classDef2_.add(gc2)
-        self.values_[(gc1, gc2)] = (value1, value2)
-
-    def addSubtableBreak(self):
-        """Add an explicit subtable break at this point."""
-        self.forceSubtableBreak_ = True
-
-    def subtables(self):
-        """Return the list of ``otTables.PairPos`` subtables constructed."""
-        self.flush_()
-        return self.subtables_
-
-    def flush_(self):
-        if self.classDef1_ is None or self.classDef2_ is None:
-            return
-        st = buildPairPosClassesSubtable(self.values_, self.builder_.glyphMap)
-        if st.Coverage is None:
-            return
-        self.subtables_.append(st)
-        self.forceSubtableBreak_ = False
-
-
-class PairPosBuilder(LookupBuilder):
-    """Builds a Pair Positioning (GPOS2) lookup.
-
-    Attributes:
-        font (``fontTools.TTLib.TTFont``): A font object.
-        location: A string or tuple representing the location in the original
-            source which produced this lookup.
-        pairs: An array of class-based pair positioning tuples. Usually
-            manipulated with the :meth:`addClassPair` method below.
-        glyphPairs: A dictionary mapping a tuple of glyph names to a tuple
-            of ``otTables.ValueRecord`` objects. Usually manipulated with the
-            :meth:`addGlyphPair` method below.
-        lookupflag (int): The lookup's flag
-        markFilterSet: Either ``None`` if no mark filtering set is used, or
-            an integer representing the filtering set to be used for this
-            lookup. If a mark filtering set is provided,
-            `LOOKUP_FLAG_USE_MARK_FILTERING_SET` will be set on the lookup's
-            flags.
-    """
-
-    def __init__(self, font, location):
-        LookupBuilder.__init__(self, font, location, "GPOS", 2)
-        self.pairs = []  # [(gc1, value1, gc2, value2)*]
-        self.glyphPairs = {}  # (glyph1, glyph2) --> (value1, value2)
-        self.locations = {}  # (gc1, gc2) --> (filepath, line, column)
-
-    def addClassPair(self, location, glyphclass1, value1, glyphclass2, value2):
-        """Add a class pair positioning rule to the current lookup.
-
-        Args:
-            location: A string or tuple representing the location in the
-                original source which produced this rule. Unused.
-            glyphclass1: A set of glyph names for the "left" glyph in the pair.
-            value1: A ``otTables.ValueRecord`` for positioning the left glyph.
-            glyphclass2: A set of glyph names for the "right" glyph in the pair.
-            value2: A ``otTables.ValueRecord`` for positioning the right glyph.
-        """
-        self.pairs.append((glyphclass1, value1, glyphclass2, value2))
-
-    def addGlyphPair(self, location, glyph1, value1, glyph2, value2):
-        """Add a glyph pair positioning rule to the current lookup.
-
-        Args:
-            location: A string or tuple representing the location in the
-                original source which produced this rule.
-            glyph1: A glyph name for the "left" glyph in the pair.
-            value1: A ``otTables.ValueRecord`` for positioning the left glyph.
-            glyph2: A glyph name for the "right" glyph in the pair.
-            value2: A ``otTables.ValueRecord`` for positioning the right glyph.
-        """
-        key = (glyph1, glyph2)
-        oldValue = self.glyphPairs.get(key, None)
-        if oldValue is not None:
-            # the Feature File spec explicitly allows specific pairs generated
-            # by an 'enum' rule to be overridden by preceding single pairs
-            otherLoc = self.locations[key]
-            log.debug(
-                "Already defined position for pair %s %s at %s; "
-                "choosing the first value",
-                glyph1,
-                glyph2,
-                otherLoc,
-            )
-        else:
-            self.glyphPairs[key] = (value1, value2)
-            self.locations[key] = location
-
-    def add_subtable_break(self, location):
-        self.pairs.append(
-            (
-                self.SUBTABLE_BREAK_,
-                self.SUBTABLE_BREAK_,
-                self.SUBTABLE_BREAK_,
-                self.SUBTABLE_BREAK_,
-            )
-        )
-
-    def equals(self, other):
-        return (
-            LookupBuilder.equals(self, other)
-            and self.glyphPairs == other.glyphPairs
-            and self.pairs == other.pairs
-        )
-
-    def build(self):
-        """Build the lookup.
-
-        Returns:
-            An ``otTables.Lookup`` object representing the pair positioning
-            lookup.
-        """
-        builders = {}
-        builder = None
-        for glyphclass1, value1, glyphclass2, value2 in self.pairs:
-            if glyphclass1 is self.SUBTABLE_BREAK_:
-                if builder is not None:
-                    builder.addSubtableBreak()
-                continue
-            valFormat1, valFormat2 = 0, 0
-            if value1:
-                valFormat1 = value1.getFormat()
-            if value2:
-                valFormat2 = value2.getFormat()
-            builder = builders.get((valFormat1, valFormat2))
-            if builder is None:
-                builder = ClassPairPosSubtableBuilder(self)
-                builders[(valFormat1, valFormat2)] = builder
-            builder.addPair(glyphclass1, value1, glyphclass2, value2)
-        subtables = []
-        if self.glyphPairs:
-            subtables.extend(buildPairPosGlyphs(self.glyphPairs, self.glyphMap))
-        for key in sorted(builders.keys()):
-            subtables.extend(builders[key].subtables())
-        return self.buildLookup_(subtables)
-
-
-class SinglePosBuilder(LookupBuilder):
-    """Builds a Single Positioning (GPOS1) lookup.
-
-    Attributes:
-        font (``fontTools.TTLib.TTFont``): A font object.
-        location: A string or tuple representing the location in the original
-            source which produced this lookup.
-        mapping: A dictionary mapping a glyph name to a ``otTables.ValueRecord``
-            objects. Usually manipulated with the :meth:`add_pos` method below.
-        lookupflag (int): The lookup's flag
-        markFilterSet: Either ``None`` if no mark filtering set is used, or
-            an integer representing the filtering set to be used for this
-            lookup. If a mark filtering set is provided,
-            `LOOKUP_FLAG_USE_MARK_FILTERING_SET` will be set on the lookup's
-            flags.
-    """
-
-    def __init__(self, font, location):
-        LookupBuilder.__init__(self, font, location, "GPOS", 1)
-        self.locations = {}  # glyph -> (filename, line, column)
-        self.mapping = {}  # glyph -> ot.ValueRecord
-
-    def add_pos(self, location, glyph, otValueRecord):
-        """Add a single positioning rule.
-
-        Args:
-            location: A string or tuple representing the location in the
-                original source which produced this lookup.
-            glyph: A glyph name.
-            otValueRection: A ``otTables.ValueRecord`` used to position the
-                glyph.
-        """
-        if not self.can_add(glyph, otValueRecord):
-            otherLoc = self.locations[glyph]
-            raise OpenTypeLibError(
-                'Already defined different position for glyph "%s" at %s'
-                % (glyph, otherLoc),
-                location,
-            )
-        if otValueRecord:
-            self.mapping[glyph] = otValueRecord
-        self.locations[glyph] = location
-
-    def can_add(self, glyph, value):
-        assert isinstance(value, ValueRecord)
-        curValue = self.mapping.get(glyph)
-        return curValue is None or curValue == value
-
-    def equals(self, other):
-        return LookupBuilder.equals(self, other) and self.mapping == other.mapping
-
-    def build(self):
-        """Build the lookup.
-
-        Returns:
-            An ``otTables.Lookup`` object representing the single positioning
-            lookup.
-        """
-        subtables = buildSinglePos(self.mapping, self.glyphMap)
-        return self.buildLookup_(subtables)
-
-
 # GSUB
 
 
 def buildSingleSubstSubtable(mapping):
-    """Builds a single substitution (GSUB1) subtable.
-
-    Note that if you are implementing a layout compiler, you may find it more
-    flexible to use
-    :py:class:`fontTools.otlLib.lookupBuilders.SingleSubstBuilder` instead.
-
-    Args:
-        mapping: A dictionary mapping input glyph names to output glyph names.
-
-    Returns:
-        An ``otTables.SingleSubst`` object, or ``None`` if the mapping dictionary
-        is empty.
-    """
     if not mapping:
         return None
     self = ot.SingleSubst()
@@ -1463,30 +59,6 @@
 
 
 def buildMultipleSubstSubtable(mapping):
-    """Builds a multiple substitution (GSUB2) subtable.
-
-    Note that if you are implementing a layout compiler, you may find it more
-    flexible to use
-    :py:class:`fontTools.otlLib.lookupBuilders.MultipleSubstBuilder` instead.
-
-    Example::
-
-        # sub uni06C0 by uni06D5.fina hamza.above
-        # sub uni06C2 by uni06C1.fina hamza.above;
-
-        subtable = buildMultipleSubstSubtable({
-            "uni06C0": [ "uni06D5.fina", "hamza.above"],
-            "uni06C2": [ "uni06D1.fina", "hamza.above"]
-        })
-
-    Args:
-        mapping: A dictionary mapping input glyph names to a list of output
-            glyph names.
-
-    Returns:
-        An ``otTables.MultipleSubst`` object or ``None`` if the mapping dictionary
-        is empty.
-    """
     if not mapping:
         return None
     self = ot.MultipleSubst()
@@ -1495,20 +67,6 @@
 
 
 def buildAlternateSubstSubtable(mapping):
-    """Builds an alternate substitution (GSUB3) subtable.
-
-    Note that if you are implementing a layout compiler, you may find it more
-    flexible to use
-    :py:class:`fontTools.otlLib.lookupBuilders.AlternateSubstBuilder` instead.
-
-    Args:
-        mapping: A dictionary mapping input glyph names to a list of output
-            glyph names.
-
-    Returns:
-        An ``otTables.AlternateSubst`` object or ``None`` if the mapping dictionary
-        is empty.
-    """
     if not mapping:
         return None
     self = ot.AlternateSubst()
@@ -1517,44 +75,20 @@
 
 
 def _getLigatureKey(components):
-    # Computes a key for ordering ligatures in a GSUB Type-4 lookup.
+    """Computes a key for ordering ligatures in a GSUB Type-4 lookup.
 
-    # When building the OpenType lookup, we need to make sure that
-    # the longest sequence of components is listed first, so we
-    # use the negative length as the primary key for sorting.
-    # To make buildLigatureSubstSubtable() deterministic, we use the
-    # component sequence as the secondary key.
+    When building the OpenType lookup, we need to make sure that
+    the longest sequence of components is listed first, so we
+    use the negative length as the primary key for sorting.
+    To make buildLigatureSubstSubtable() deterministic, we use the
+    component sequence as the secondary key.
 
-    # For example, this will sort (f,f,f) < (f,f,i) < (f,f) < (f,i) < (f,l).
+    For example, this will sort (f,f,f) < (f,f,i) < (f,f) < (f,i) < (f,l).
+    """
     return (-len(components), components)
 
 
 def buildLigatureSubstSubtable(mapping):
-    """Builds a ligature substitution (GSUB4) subtable.
-
-    Note that if you are implementing a layout compiler, you may find it more
-    flexible to use
-    :py:class:`fontTools.otlLib.lookupBuilders.LigatureSubstBuilder` instead.
-
-    Example::
-
-        # sub f f i by f_f_i;
-        # sub f i by f_i;
-
-        subtable = buildLigatureSubstSubtable({
-            ("f", "f", "i"): "f_f_i",
-            ("f", "i"): "f_i",
-        })
-
-    Args:
-        mapping: A dictionary mapping tuples of glyph names to output
-            glyph names.
-
-    Returns:
-        An ``otTables.LigatureSubst`` object or ``None`` if the mapping dictionary
-        is empty.
-    """
-
     if not mapping:
         return None
     self = ot.LigatureSubst()
@@ -1576,20 +110,6 @@
 
 
 def buildAnchor(x, y, point=None, deviceX=None, deviceY=None):
-    """Builds an Anchor table.
-
-    This determines the appropriate anchor format based on the passed parameters.
-
-    Args:
-        x (int): X coordinate.
-        y (int): Y coordinate.
-        point (int): Index of glyph contour point, if provided.
-        deviceX (``otTables.Device``): X coordinate device table, if provided.
-        deviceY (``otTables.Device``): Y coordinate device table, if provided.
-
-    Returns:
-        An ``otTables.Anchor`` object.
-    """
     self = ot.Anchor()
     self.XCoordinate, self.YCoordinate = x, y
     self.Format = 1
@@ -1597,9 +117,8 @@
         self.AnchorPoint = point
         self.Format = 2
     if deviceX is not None or deviceY is not None:
-        assert (
-            self.Format == 1
-        ), "Either point, or both of deviceX/deviceY, must be None."
+        assert self.Format == 1, \
+            "Either point, or both of deviceX/deviceY, must be None."
         self.XDeviceTable = deviceX
         self.YDeviceTable = deviceY
         self.Format = 3
@@ -1607,31 +126,6 @@
 
 
 def buildBaseArray(bases, numMarkClasses, glyphMap):
-    """Builds a base array record.
-
-    As part of building mark-to-base positioning rules, you will need to define
-    a ``BaseArray`` record, which "defines for each base glyph an array of
-    anchors, one for each mark class." This function builds the base array
-    subtable.
-
-    Example::
-
-        bases = {"a": {0: a3, 1: a5}, "b": {0: a4, 1: a5}}
-        basearray = buildBaseArray(bases, 2, font.getReverseGlyphMap())
-
-    Args:
-        bases (dict): A dictionary mapping anchors to glyphs; the keys being
-            glyph names, and the values being dictionaries mapping mark class ID
-            to the appropriate ``otTables.Anchor`` object used for attaching marks
-            of that class.
-        numMarkClasses (int): The total number of mark classes for which anchors
-            are defined.
-        glyphMap: a glyph name to ID map, typically returned from
-            ``font.getReverseGlyphMap()``.
-
-    Returns:
-        An ``otTables.BaseArray`` object.
-    """
     self = ot.BaseArray()
     self.BaseRecord = []
     for base in sorted(bases, key=glyphMap.__getitem__):
@@ -1643,27 +137,14 @@
 
 
 def buildBaseRecord(anchors):
-    # [otTables.Anchor, otTables.Anchor, ...] --> otTables.BaseRecord
+    """[otTables.Anchor, otTables.Anchor, ...] --> otTables.BaseRecord"""
     self = ot.BaseRecord()
     self.BaseAnchor = anchors
     return self
 
 
 def buildComponentRecord(anchors):
-    """Builds a component record.
-
-    As part of building mark-to-ligature positioning rules, you will need to
-    define ``ComponentRecord`` objects, which contain "an array of offsets...
-    to the Anchor tables that define all the attachment points used to attach
-    marks to the component." This function builds the component record.
-
-    Args:
-        anchors: A list of ``otTables.Anchor`` objects or ``None``.
-
-    Returns:
-        A ``otTables.ComponentRecord`` object or ``None`` if no anchors are
-        supplied.
-    """
+    """[otTables.Anchor, otTables.Anchor, ...] --> otTables.ComponentRecord"""
     if not anchors:
         return None
     self = ot.ComponentRecord()
@@ -1672,30 +153,7 @@
 
 
 def buildCursivePosSubtable(attach, glyphMap):
-    """Builds a cursive positioning (GPOS3) subtable.
-
-    Cursive positioning lookups are made up of a coverage table of glyphs,
-    and a set of ``EntryExitRecord`` records containing the anchors for
-    each glyph. This function builds the cursive positioning subtable.
-
-    Example::
-
-        subtable = buildCursivePosSubtable({
-            "AlifIni": (None, buildAnchor(0, 50)),
-            "BehMed": (buildAnchor(500,250), buildAnchor(0,50)),
-            # ...
-        }, font.getReverseGlyphMap())
-
-    Args:
-        attach (dict): A mapping between glyph names and a tuple of two
-            ``otTables.Anchor`` objects representing entry and exit anchors.
-        glyphMap: a glyph name to ID map, typically returned from
-            ``font.getReverseGlyphMap()``.
-
-    Returns:
-        An ``otTables.CursivePos`` object, or ``None`` if the attachment
-        dictionary was empty.
-    """
+    """{"alef": (entry, exit)} --> otTables.CursivePos"""
     if not attach:
         return None
     self = ot.CursivePos()
@@ -1713,22 +171,7 @@
 
 
 def buildDevice(deltas):
-    """Builds a Device record as part of a ValueRecord or Anchor.
-
-    Device tables specify size-specific adjustments to value records
-    and anchors to reflect changes based on the resolution of the output.
-    For example, one could specify that an anchor's Y position should be
-    increased by 1 pixel when displayed at 8 pixels per em. This routine
-    builds device records.
-
-    Args:
-        deltas: A dictionary mapping pixels-per-em sizes to the delta
-            adjustment in pixels when the font is displayed at that size.
-
-    Returns:
-        An ``otTables.Device`` object if any deltas were supplied, or
-        ``None`` otherwise.
-    """
+    """{8:+1, 10:-3, ...} --> otTables.Device"""
     if not deltas:
         return None
     self = ot.Device()
@@ -1737,8 +180,8 @@
     self.EndSize = endSize = max(keys)
     assert 0 <= startSize <= endSize
     self.DeltaValue = deltaValues = [
-        deltas.get(size, 0) for size in range(startSize, endSize + 1)
-    ]
+        deltas.get(size, 0)
+        for size in range(startSize, endSize + 1)]
     maxDelta = max(deltaValues)
     minDelta = min(deltaValues)
     assert minDelta > -129 and maxDelta < 128
@@ -1752,36 +195,6 @@
 
 
 def buildLigatureArray(ligs, numMarkClasses, glyphMap):
-    """Builds a LigatureArray subtable.
-
-    As part of building a mark-to-ligature lookup, you will need to define
-    the set of anchors (for each mark class) on each component of the ligature
-    where marks can be attached. For example, for an Arabic divine name ligature
-    (lam lam heh), you may want to specify mark attachment positioning for
-    superior marks (fatha, etc.) and inferior marks (kasra, etc.) on each glyph
-    of the ligature. This routine builds the ligature array record.
-
-    Example::
-
-        buildLigatureArray({
-            "lam-lam-heh": [
-                { 0: superiorAnchor1, 1: inferiorAnchor1 }, # attach points for lam1
-                { 0: superiorAnchor2, 1: inferiorAnchor2 }, # attach points for lam2
-                { 0: superiorAnchor3, 1: inferiorAnchor3 }, # attach points for heh
-            ]
-        }, 2, font.getReverseGlyphMap())
-
-    Args:
-        ligs (dict): A mapping of ligature names to an array of dictionaries:
-            for each component glyph in the ligature, an dictionary mapping
-            mark class IDs to anchors.
-        numMarkClasses (int): The number of mark classes.
-        glyphMap: a glyph name to ID map, typically returned from
-            ``font.getReverseGlyphMap()``.
-
-    Returns:
-        An ``otTables.LigatureArray`` object if deltas were supplied.
-    """
     self = ot.LigatureArray()
     self.LigatureAttach = []
     for lig in sorted(ligs, key=glyphMap.__getitem__):
@@ -1794,7 +207,7 @@
 
 
 def buildLigatureAttach(components):
-    # [[Anchor, Anchor], [Anchor, Anchor, Anchor]] --> LigatureAttach
+    """[[Anchor, Anchor], [Anchor, Anchor, Anchor]] --> LigatureAttach"""
     self = ot.LigatureAttach()
     self.ComponentRecord = [buildComponentRecord(c) for c in components]
     self.ComponentCount = len(self.ComponentRecord)
@@ -1802,31 +215,7 @@
 
 
 def buildMarkArray(marks, glyphMap):
-    """Builds a mark array subtable.
-
-    As part of building mark-to-* positioning rules, you will need to define
-    a MarkArray subtable, which "defines the class and the anchor point
-    for a mark glyph." This function builds the mark array subtable.
-
-    Example::
-
-        mark = {
-            "acute": (0, buildAnchor(300,712)),
-            # ...
-        }
-        markarray = buildMarkArray(marks, font.getReverseGlyphMap())
-
-    Args:
-        marks (dict): A dictionary mapping anchors to glyphs; the keys being
-            glyph names, and the values being a tuple of mark class number and
-            an ``otTables.Anchor`` object representing the mark's attachment
-            point.
-        glyphMap: a glyph name to ID map, typically returned from
-            ``font.getReverseGlyphMap()``.
-
-    Returns:
-        An ``otTables.MarkArray`` object.
-    """
+    """{"acute": (markClass, otTables.Anchor)} --> otTables.MarkArray"""
     self = ot.MarkArray()
     self.MarkRecord = []
     for mark in sorted(marks.keys(), key=glyphMap.__getitem__):
@@ -1838,40 +227,11 @@
 
 
 def buildMarkBasePos(marks, bases, glyphMap):
-    """Build a list of MarkBasePos (GPOS4) subtables.
+    """Build a list of MarkBasePos subtables.
 
-    This routine turns a set of marks and bases into a list of mark-to-base
-    positioning subtables. Currently the list will contain a single subtable
-    containing all marks and bases, although at a later date it may return the
-    optimal list of subtables subsetting the marks and bases into groups which
-    save space. See :func:`buildMarkBasePosSubtable` below.
-
-    Note that if you are implementing a layout compiler, you may find it more
-    flexible to use
-    :py:class:`fontTools.otlLib.lookupBuilders.MarkBasePosBuilder` instead.
-
-    Example::
-
-        # a1, a2, a3, a4, a5 = buildAnchor(500, 100), ...
-
-        marks = {"acute": (0, a1), "grave": (0, a1), "cedilla": (1, a2)}
-        bases = {"a": {0: a3, 1: a5}, "b": {0: a4, 1: a5}}
-        markbaseposes = buildMarkBasePos(marks, bases, font.getReverseGlyphMap())
-
-    Args:
-        marks (dict): A dictionary mapping anchors to glyphs; the keys being
-            glyph names, and the values being a tuple of mark class number and
-            an ``otTables.Anchor`` object representing the mark's attachment
-            point. (See :func:`buildMarkArray`.)
-        bases (dict): A dictionary mapping anchors to glyphs; the keys being
-            glyph names, and the values being dictionaries mapping mark class ID
-            to the appropriate ``otTables.Anchor`` object used for attaching marks
-            of that class. (See :func:`buildBaseArray`.)
-        glyphMap: a glyph name to ID map, typically returned from
-            ``font.getReverseGlyphMap()``.
-
-    Returns:
-        A list of ``otTables.MarkBasePos`` objects.
+    a1, a2, a3, a4, a5 = buildAnchor(500, 100), ...
+    marks = {"acute": (0, a1), "grave": (0, a1), "cedilla": (1, a2)}
+    bases = {"a": {0: a3, 1: a5}, "b": {0: a4, 1: a5}}
     """
     # TODO: Consider emitting multiple subtables to save space.
     # Partition the marks and bases into disjoint subsets, so that
@@ -1888,25 +248,11 @@
 
 
 def buildMarkBasePosSubtable(marks, bases, glyphMap):
-    """Build a single MarkBasePos (GPOS4) subtable.
+    """Build a single MarkBasePos subtable.
 
-    This builds a mark-to-base lookup subtable containing all of the referenced
-    marks and bases. See :func:`buildMarkBasePos`.
-
-    Args:
-        marks (dict): A dictionary mapping anchors to glyphs; the keys being
-            glyph names, and the values being a tuple of mark class number and
-            an ``otTables.Anchor`` object representing the mark's attachment
-            point. (See :func:`buildMarkArray`.)
-        bases (dict): A dictionary mapping anchors to glyphs; the keys being
-            glyph names, and the values being dictionaries mapping mark class ID
-            to the appropriate ``otTables.Anchor`` object used for attaching marks
-            of that class. (See :func:`buildBaseArray`.)
-        glyphMap: a glyph name to ID map, typically returned from
-            ``font.getReverseGlyphMap()``.
-
-    Returns:
-        A ``otTables.MarkBasePos`` object.
+    a1, a2, a3, a4, a5 = buildAnchor(500, 100), ...
+    marks = {"acute": (0, a1), "grave": (0, a1), "cedilla": (1, a2)}
+    bases = {"a": {0: a3, 1: a5}, "b": {0: a4, 1: a5}}
     """
     self = ot.MarkBasePos()
     self.Format = 1
@@ -1919,50 +265,11 @@
 
 
 def buildMarkLigPos(marks, ligs, glyphMap):
-    """Build a list of MarkLigPos (GPOS5) subtables.
+    """Build a list of MarkLigPos subtables.
 
-    This routine turns a set of marks and ligatures into a list of mark-to-ligature
-    positioning subtables. Currently the list will contain a single subtable
-    containing all marks and ligatures, although at a later date it may return
-    the optimal list of subtables subsetting the marks and ligatures into groups
-    which save space. See :func:`buildMarkLigPosSubtable` below.
-
-    Note that if you are implementing a layout compiler, you may find it more
-    flexible to use
-    :py:class:`fontTools.otlLib.lookupBuilders.MarkLigPosBuilder` instead.
-
-    Example::
-
-        # a1, a2, a3, a4, a5 = buildAnchor(500, 100), ...
-        marks = {
-            "acute": (0, a1),
-            "grave": (0, a1),
-            "cedilla": (1, a2)
-        }
-        ligs = {
-            "f_i": [
-                { 0: a3, 1: a5 }, # f
-                { 0: a4, 1: a5 }  # i
-                ],
-        #   "c_t": [{...}, {...}]
-        }
-        markligposes = buildMarkLigPos(marks, ligs,
-            font.getReverseGlyphMap())
-
-    Args:
-        marks (dict): A dictionary mapping anchors to glyphs; the keys being
-            glyph names, and the values being a tuple of mark class number and
-            an ``otTables.Anchor`` object representing the mark's attachment
-            point. (See :func:`buildMarkArray`.)
-        ligs (dict): A mapping of ligature names to an array of dictionaries:
-            for each component glyph in the ligature, an dictionary mapping
-            mark class IDs to anchors. (See :func:`buildLigatureArray`.)
-        glyphMap: a glyph name to ID map, typically returned from
-            ``font.getReverseGlyphMap()``.
-
-    Returns:
-        A list of ``otTables.MarkLigPos`` objects.
-
+    a1, a2, a3, a4, a5 = buildAnchor(500, 100), ...
+    marks = {"acute": (0, a1), "grave": (0, a1), "cedilla": (1, a2)}
+    ligs = {"f_i": [{0: a3, 1: a5},  {0: a4, 1: a5}], "c_t": [{...}, {...}]}
     """
     # TODO: Consider splitting into multiple subtables to save space,
     # as with MarkBasePos, this would be a trade-off that would need
@@ -1972,24 +279,11 @@
 
 
 def buildMarkLigPosSubtable(marks, ligs, glyphMap):
-    """Build a single MarkLigPos (GPOS5) subtable.
+    """Build a single MarkLigPos subtable.
 
-    This builds a mark-to-base lookup subtable containing all of the referenced
-    marks and bases. See :func:`buildMarkLigPos`.
-
-    Args:
-        marks (dict): A dictionary mapping anchors to glyphs; the keys being
-            glyph names, and the values being a tuple of mark class number and
-            an ``otTables.Anchor`` object representing the mark's attachment
-            point. (See :func:`buildMarkArray`.)
-        ligs (dict): A mapping of ligature names to an array of dictionaries:
-            for each component glyph in the ligature, an dictionary mapping
-            mark class IDs to anchors. (See :func:`buildLigatureArray`.)
-        glyphMap: a glyph name to ID map, typically returned from
-            ``font.getReverseGlyphMap()``.
-
-    Returns:
-        A ``otTables.MarkLigPos`` object.
+    a1, a2, a3, a4, a5 = buildAnchor(500, 100), ...
+    marks = {"acute": (0, a1), "grave": (0, a1), "cedilla": (1, a2)}
+    ligs = {"f_i": [{0: a3, 1: a5},  {0: a4, 1: a5}], "c_t": [{...}, {...}]}
     """
     self = ot.MarkLigPos()
     self.Format = 1
@@ -2011,14 +305,14 @@
 
 
 def buildMark2Record(anchors):
-    # [otTables.Anchor, otTables.Anchor, ...] --> otTables.Mark2Record
+    """[otTables.Anchor, otTables.Anchor, ...] --> otTables.Mark2Record"""
     self = ot.Mark2Record()
     self.Mark2Anchor = anchors
     return self
 
 
 def _getValueFormat(f, values, i):
-    # Helper for buildPairPos{Glyphs|Classes}Subtable.
+    """Helper for buildPairPos{Glyphs|Classes}Subtable."""
     if f is not None:
         return f
     mask = 0
@@ -2028,45 +322,8 @@
     return mask
 
 
-def buildPairPosClassesSubtable(pairs, glyphMap, valueFormat1=None, valueFormat2=None):
-    """Builds a class pair adjustment (GPOS2 format 2) subtable.
-
-    Kerning tables are generally expressed as pair positioning tables using
-    class-based pair adjustments. This routine builds format 2 PairPos
-    subtables.
-
-    Note that if you are implementing a layout compiler, you may find it more
-    flexible to use
-    :py:class:`fontTools.otlLib.lookupBuilders.ClassPairPosSubtableBuilder`
-    instead, as this takes care of ensuring that the supplied pairs can be
-    formed into non-overlapping classes and emitting individual subtables
-    whenever the non-overlapping requirement means that a new subtable is
-    required.
-
-    Example::
-
-        pairs = {}
-
-        pairs[(
-            [ "K", "X" ],
-            [ "W", "V" ]
-        )] = ( buildValue(xAdvance=+5), buildValue() )
-        # pairs[(... , ...)] = (..., ...)
-
-        pairpos = buildPairPosClassesSubtable(pairs, font.getReverseGlyphMap())
-
-    Args:
-        pairs (dict): Pair positioning data; the keys being a two-element
-            tuple of lists of glyphnames, and the values being a two-element
-            tuple of ``otTables.ValueRecord`` objects.
-        glyphMap: a glyph name to ID map, typically returned from
-            ``font.getReverseGlyphMap()``.
-        valueFormat1: Force the "left" value records to the given format.
-        valueFormat2: Force the "right" value records to the given format.
-
-    Returns:
-        A ``otTables.PairPos`` object.
-    """
+def buildPairPosClassesSubtable(pairs, glyphMap,
+                                valueFormat1=None, valueFormat2=None):
     coverage = set()
     classDef1 = ClassDefBuilder(useClass0=True)
     classDef2 = ClassDefBuilder(useClass0=False)
@@ -2076,8 +333,8 @@
         classDef2.add(gc2)
     self = ot.PairPos()
     self.Format = 2
-    valueFormat1 = self.ValueFormat1 = _getValueFormat(valueFormat1, pairs.values(), 0)
-    valueFormat2 = self.ValueFormat2 = _getValueFormat(valueFormat2, pairs.values(), 1)
+    self.ValueFormat1 = _getValueFormat(valueFormat1, pairs.values(), 0)
+    self.ValueFormat2 = _getValueFormat(valueFormat2, pairs.values(), 1)
     self.Coverage = buildCoverage(coverage, glyphMap)
     self.ClassDef1 = classDef1.build()
     self.ClassDef2 = classDef2.build()
@@ -2090,9 +347,7 @@
         self.Class1Record.append(rec1)
         for c2 in classes2:
             rec2 = ot.Class2Record()
-            val1, val2 = pairs.get((c1, c2), (None, None))
-            rec2.Value1 = ValueRecord(src=val1, valueFormat=valueFormat1) if valueFormat1 else None
-            rec2.Value2 = ValueRecord(src=val2, valueFormat=valueFormat2) if valueFormat2 else None
+            rec2.Value1, rec2.Value2 = pairs.get((c1, c2), (None, None))
             rec1.Class2Record.append(rec2)
     self.Class1Count = len(self.Class1Record)
     self.Class2Count = len(classes2)
@@ -2100,37 +355,6 @@
 
 
 def buildPairPosGlyphs(pairs, glyphMap):
-    """Builds a list of glyph-based pair adjustment (GPOS2 format 1) subtables.
-
-    This organises a list of pair positioning adjustments into subtables based
-    on common value record formats.
-
-    Note that if you are implementing a layout compiler, you may find it more
-    flexible to use
-    :py:class:`fontTools.otlLib.lookupBuilders.PairPosBuilder`
-    instead.
-
-    Example::
-
-        pairs = {
-            ("K", "W"): ( buildValue(xAdvance=+5), buildValue() ),
-            ("K", "V"): ( buildValue(xAdvance=+5), buildValue() ),
-            # ...
-        }
-
-        subtables = buildPairPosGlyphs(pairs, font.getReverseGlyphMap())
-
-    Args:
-        pairs (dict): Pair positioning data; the keys being a two-element
-            tuple of glyphnames, and the values being a two-element
-            tuple of ``otTables.ValueRecord`` objects.
-        glyphMap: a glyph name to ID map, typically returned from
-            ``font.getReverseGlyphMap()``.
-
-    Returns:
-        A list of ``otTables.PairPos`` objects.
-    """
-
     p = {}  # (formatA, formatB) --> {(glyphA, glyphB): (valA, valB)}
     for (glyphA, glyphB), (valA, valB) in pairs.items():
         formatA = valA.getFormat() if valA is not None else 0
@@ -2139,46 +363,15 @@
         pos[(glyphA, glyphB)] = (valA, valB)
     return [
         buildPairPosGlyphsSubtable(pos, glyphMap, formatA, formatB)
-        for ((formatA, formatB), pos) in sorted(p.items())
-    ]
+        for ((formatA, formatB), pos) in sorted(p.items())]
 
 
-def buildPairPosGlyphsSubtable(pairs, glyphMap, valueFormat1=None, valueFormat2=None):
-    """Builds a single glyph-based pair adjustment (GPOS2 format 1) subtable.
-
-    This builds a PairPos subtable from a dictionary of glyph pairs and
-    their positioning adjustments. See also :func:`buildPairPosGlyphs`.
-
-    Note that if you are implementing a layout compiler, you may find it more
-    flexible to use
-    :py:class:`fontTools.otlLib.lookupBuilders.PairPosBuilder` instead.
-
-    Example::
-
-        pairs = {
-            ("K", "W"): ( buildValue(xAdvance=+5), buildValue() ),
-            ("K", "V"): ( buildValue(xAdvance=+5), buildValue() ),
-            # ...
-        }
-
-        pairpos = buildPairPosGlyphsSubtable(pairs, font.getReverseGlyphMap())
-
-    Args:
-        pairs (dict): Pair positioning data; the keys being a two-element
-            tuple of glyphnames, and the values being a two-element
-            tuple of ``otTables.ValueRecord`` objects.
-        glyphMap: a glyph name to ID map, typically returned from
-            ``font.getReverseGlyphMap()``.
-        valueFormat1: Force the "left" value records to the given format.
-        valueFormat2: Force the "right" value records to the given format.
-
-    Returns:
-        A ``otTables.PairPos`` object.
-    """
+def buildPairPosGlyphsSubtable(pairs, glyphMap,
+                               valueFormat1=None, valueFormat2=None):
     self = ot.PairPos()
     self.Format = 1
-    valueFormat1 = self.ValueFormat1 = _getValueFormat(valueFormat1, pairs.values(), 0)
-    valueFormat2 = self.ValueFormat2 = _getValueFormat(valueFormat2, pairs.values(), 1)
+    self.ValueFormat1 = _getValueFormat(valueFormat1, pairs.values(), 0)
+    self.ValueFormat2 = _getValueFormat(valueFormat2, pairs.values(), 1)
     p = {}
     for (glyphA, glyphB), (valA, valB) in pairs.items():
         p.setdefault(glyphA, []).append((glyphB, valA, valB))
@@ -2188,11 +381,12 @@
         ps = ot.PairSet()
         ps.PairValueRecord = []
         self.PairSet.append(ps)
-        for glyph2, val1, val2 in sorted(p[glyph], key=lambda x: glyphMap[x[0]]):
+        for glyph2, val1, val2 in \
+                sorted(p[glyph], key=lambda x: glyphMap[x[0]]):
             pvr = ot.PairValueRecord()
             pvr.SecondGlyph = glyph2
-            pvr.Value1 = ValueRecord(src=val1, valueFormat=valueFormat1) if valueFormat1 else None
-            pvr.Value2 = ValueRecord(src=val2, valueFormat=valueFormat2) if valueFormat2 else None
+            pvr.Value1 = val1 if val1 and val1.getFormat() != 0 else None
+            pvr.Value2 = val2 if val2 and val2.getFormat() != 0 else None
             ps.PairValueRecord.append(pvr)
         ps.PairValueCount = len(ps.PairValueRecord)
     self.PairSetCount = len(self.PairSet)
@@ -2200,35 +394,7 @@
 
 
 def buildSinglePos(mapping, glyphMap):
-    """Builds a list of single adjustment (GPOS1) subtables.
-
-    This builds a list of SinglePos subtables from a dictionary of glyph
-    names and their positioning adjustments. The format of the subtables are
-    determined to optimize the size of the resulting subtables.
-    See also :func:`buildSinglePosSubtable`.
-
-    Note that if you are implementing a layout compiler, you may find it more
-    flexible to use
-    :py:class:`fontTools.otlLib.lookupBuilders.SinglePosBuilder` instead.
-
-    Example::
-
-        mapping = {
-            "V": buildValue({ "xAdvance" : +5 }),
-            # ...
-        }
-
-        subtables = buildSinglePos(pairs, font.getReverseGlyphMap())
-
-    Args:
-        mapping (dict): A mapping between glyphnames and
-            ``otTables.ValueRecord`` objects.
-        glyphMap: a glyph name to ID map, typically returned from
-            ``font.getReverseGlyphMap()``.
-
-    Returns:
-        A list of ``otTables.SinglePos`` objects.
-    """
+    """{"glyph": ValueRecord} --> [otTables.SinglePos*]"""
     result, handled = [], set()
     # In SinglePos format 1, the covered glyphs all share the same ValueRecord.
     # In format 2, each glyph has its own ValueRecord, but these records
@@ -2282,39 +448,13 @@
 
 
 def buildSinglePosSubtable(values, glyphMap):
-    """Builds a single adjustment (GPOS1) subtable.
-
-    This builds a list of SinglePos subtables from a dictionary of glyph
-    names and their positioning adjustments. The format of the subtable is
-    determined to optimize the size of the output.
-    See also :func:`buildSinglePos`.
-
-    Note that if you are implementing a layout compiler, you may find it more
-    flexible to use
-    :py:class:`fontTools.otlLib.lookupBuilders.SinglePosBuilder` instead.
-
-    Example::
-
-        mapping = {
-            "V": buildValue({ "xAdvance" : +5 }),
-            # ...
-        }
-
-        subtable = buildSinglePos(pairs, font.getReverseGlyphMap())
-
-    Args:
-        mapping (dict): A mapping between glyphnames and
-            ``otTables.ValueRecord`` objects.
-        glyphMap: a glyph name to ID map, typically returned from
-            ``font.getReverseGlyphMap()``.
-
-    Returns:
-        A ``otTables.SinglePos`` object.
-    """
+    """{glyphName: otBase.ValueRecord} --> otTables.SinglePos"""
     self = ot.SinglePos()
     self.Coverage = buildCoverage(values.keys(), glyphMap)
-    valueFormat = self.ValueFormat = reduce(int.__or__, [v.getFormat() for v in values.values()], 0)
-    valueRecords = [ValueRecord(src=values[g], valueFormat=valueFormat) for g in self.Coverage.glyphs]
+    valueRecords = [values[g] for g in self.Coverage.glyphs]
+    self.ValueFormat = 0
+    for v in valueRecords:
+        self.ValueFormat |= v.getFormat()
     if all(v == valueRecords[0] for v in valueRecords):
         self.Format = 1
         if self.ValueFormat != 0:
@@ -2335,7 +475,7 @@
 
 
 def _getSinglePosValueKey(valueRecord):
-    # otBase.ValueRecord --> (2, ("YPlacement": 12))
+    """otBase.ValueRecord --> (2, ("YPlacement": 12))"""
     assert isinstance(valueRecord, ValueRecord), valueRecord
     valueFormat, result = 0, []
     for name, value in valueRecord.__dict__.items():
@@ -2353,17 +493,17 @@
 
 
 def _makeDeviceTuple(device):
-    # otTables.Device --> tuple, for making device tables unique
+    """otTables.Device --> tuple, for making device tables unique"""
     return _DeviceTuple(
         device.DeltaFormat,
         device.StartSize,
         device.EndSize,
-        () if device.DeltaFormat & 0x8000 else tuple(device.DeltaValue),
+        () if device.DeltaFormat & 0x8000 else tuple(device.DeltaValue)
     )
 
 
 def _getSinglePosValueSize(valueKey):
-    # Returns how many ushorts this valueKey (short form of ValueRecord) takes up
+    """Returns how many ushorts this valueKey (short form of ValueRecord) takes up"""
     count = 0
     for _, v in valueKey[1:]:
         if isinstance(v, _DeviceTuple):
@@ -2372,29 +512,7 @@
             count += 1
     return count
 
-
 def buildValue(value):
-    """Builds a positioning value record.
-
-    Value records are used to specify coordinates and adjustments for
-    positioning and attaching glyphs. Many of the positioning functions
-    in this library take ``otTables.ValueRecord`` objects as arguments.
-    This function builds value records from dictionaries.
-
-    Args:
-        value (dict): A dictionary with zero or more of the following keys:
-            - ``xPlacement``
-            - ``yPlacement``
-            - ``xAdvance``
-            - ``yAdvance``
-            - ``xPlaDevice``
-            - ``yPlaDevice``
-            - ``xAdvDevice``
-            - ``yAdvDevice``
-
-    Returns:
-        An ``otTables.ValueRecord`` object.
-    """
     self = ValueRecord()
     for k, v in value.items():
         setattr(self, k, v)
@@ -2403,34 +521,20 @@
 
 # GDEF
 
-
 def buildAttachList(attachPoints, glyphMap):
-    """Builds an AttachList subtable.
-
-    A GDEF table may contain an Attachment Point List table (AttachList)
-    which stores the contour indices of attachment points for glyphs with
-    attachment points. This routine builds AttachList subtables.
-
-    Args:
-        attachPoints (dict): A mapping between glyph names and a list of
-            contour indices.
-
-    Returns:
-        An ``otTables.AttachList`` object if attachment points are supplied,
-            or ``None`` otherwise.
-    """
+    """{"glyphName": [4, 23]} --> otTables.AttachList, or None"""
     if not attachPoints:
         return None
     self = ot.AttachList()
     self.Coverage = buildCoverage(attachPoints.keys(), glyphMap)
-    self.AttachPoint = [buildAttachPoint(attachPoints[g]) for g in self.Coverage.glyphs]
+    self.AttachPoint = [buildAttachPoint(attachPoints[g])
+                        for g in self.Coverage.glyphs]
     self.GlyphCount = len(self.AttachPoint)
     return self
 
 
 def buildAttachPoint(points):
-    # [4, 23, 41] --> otTables.AttachPoint
-    # Only used by above.
+    """[4, 23, 41] --> otTables.AttachPoint"""
     if not points:
         return None
     self = ot.AttachPoint()
@@ -2440,7 +544,7 @@
 
 
 def buildCaretValueForCoord(coord):
-    # 500 --> otTables.CaretValue, format 1
+    """500 --> otTables.CaretValue, format 1"""
     self = ot.CaretValue()
     self.Format = 1
     self.Coordinate = coord
@@ -2448,7 +552,7 @@
 
 
 def buildCaretValueForPoint(point):
-    # 4 --> otTables.CaretValue, format 2
+    """4 --> otTables.CaretValue, format 2"""
     self = ot.CaretValue()
     self.Format = 2
     self.CaretValuePoint = point
@@ -2456,37 +560,7 @@
 
 
 def buildLigCaretList(coords, points, glyphMap):
-    """Builds a ligature caret list table.
-
-    Ligatures appear as a single glyph representing multiple characters; however
-    when, for example, editing text containing a ``f_i`` ligature, the user may
-    want to place the cursor between the ``f`` and the ``i``. The ligature caret
-    list in the GDEF table specifies the position to display the "caret" (the
-    character insertion indicator, typically a flashing vertical bar) "inside"
-    the ligature to represent an insertion point. The insertion positions may
-    be specified either by coordinate or by contour point.
-
-    Example::
-
-        coords = {
-            "f_f_i": [300, 600] # f|fi cursor at 300 units, ff|i cursor at 600.
-        }
-        points = {
-            "c_t": [28] # c|t cursor appears at coordinate of contour point 28.
-        }
-        ligcaretlist = buildLigCaretList(coords, points, font.getReverseGlyphMap())
-
-    Args:
-        coords: A mapping between glyph names and a list of coordinates for
-            the insertion point of each ligature component after the first one.
-        points: A mapping between glyph names and a list of contour points for
-            the insertion point of each ligature component after the first one.
-        glyphMap: a glyph name to ID map, typically returned from
-            ``font.getReverseGlyphMap()``.
-
-    Returns:
-        A ``otTables.LigCaretList`` object if any carets are present, or
-            ``None`` otherwise."""
+    """{"f_f_i":[300,600]}, {"c_t":[28]} --> otTables.LigCaretList, or None"""
     glyphs = set(coords.keys()) if coords else set()
     if points:
         glyphs.update(points.keys())
@@ -2502,7 +576,7 @@
 
 
 def buildLigGlyph(coords, points):
-    # ([500], [4]) --> otTables.LigGlyph; None for empty coords/points
+    """([500], [4]) --> otTables.LigGlyph; None for empty coords/points"""
     carets = []
     if coords:
         carets.extend([buildCaretValueForCoord(c) for c in sorted(coords)])
@@ -2517,30 +591,7 @@
 
 
 def buildMarkGlyphSetsDef(markSets, glyphMap):
-    """Builds a mark glyph sets definition table.
-
-    OpenType Layout lookups may choose to use mark filtering sets to consider
-    or ignore particular combinations of marks. These sets are specified by
-    setting a flag on the lookup, but the mark filtering sets are defined in
-    the ``GDEF`` table. This routine builds the subtable containing the mark
-    glyph set definitions.
-
-    Example::
-
-        set0 = set("acute", "grave")
-        set1 = set("caron", "grave")
-
-        markglyphsets = buildMarkGlyphSetsDef([set0, set1], font.getReverseGlyphMap())
-
-    Args:
-
-        markSets: A list of sets of glyphnames.
-        glyphMap: a glyph name to ID map, typically returned from
-            ``font.getReverseGlyphMap()``.
-
-    Returns
-        An ``otTables.MarkGlyphSetsDef`` object.
-    """
+    """[{"acute","grave"}, {"caron","grave"}] --> otTables.MarkGlyphSetsDef"""
     if not markSets:
         return None
     self = ot.MarkGlyphSetsDef()
@@ -2552,7 +603,6 @@
 
 class ClassDefBuilder(object):
     """Helper for building ClassDef tables."""
-
     def __init__(self, useClass0):
         self.classes_ = set()
         self.glyphs_ = {}
@@ -2577,10 +627,7 @@
             return
         self.classes_.add(glyphs)
         for glyph in glyphs:
-            if glyph in self.glyphs_:
-                raise OpenTypeLibError(
-                    f"Glyph {glyph} is already present in class.", None
-                )
+            assert glyph not in self.glyphs_
             self.glyphs_[glyph] = glyphs
 
     def classes(self):
@@ -2611,211 +658,3 @@
         classDef = ot.ClassDef()
         classDef.classDefs = glyphClasses
         return classDef
-
-
-AXIS_VALUE_NEGATIVE_INFINITY = fixedToFloat(-0x80000000, 16)
-AXIS_VALUE_POSITIVE_INFINITY = fixedToFloat(0x7FFFFFFF, 16)
-
-
-def buildStatTable(ttFont, axes, locations=None, elidedFallbackName=2):
-    """Add a 'STAT' table to 'ttFont'.
-
-    'axes' is a list of dictionaries describing axes and their
-    values.
-
-    Example::
-
-        axes = [
-            dict(
-                tag="wght",
-                name="Weight",
-                ordering=0,  # optional
-                values=[
-                    dict(value=100, name='Thin'),
-                    dict(value=300, name='Light'),
-                    dict(value=400, name='Regular', flags=0x2),
-                    dict(value=900, name='Black'),
-                ],
-            )
-        ]
-
-    Each axis dict must have 'tag' and 'name' items. 'tag' maps
-    to the 'AxisTag' field. 'name' can be a name ID (int), a string,
-    or a dictionary containing multilingual names (see the
-    addMultilingualName() name table method), and will translate to
-    the AxisNameID field.
-
-    An axis dict may contain an 'ordering' item that maps to the
-    AxisOrdering field. If omitted, the order of the axes list is
-    used to calculate AxisOrdering fields.
-
-    The axis dict may contain a 'values' item, which is a list of
-    dictionaries describing AxisValue records belonging to this axis.
-
-    Each value dict must have a 'name' item, which can be a name ID
-    (int), a string, or a dictionary containing multilingual names,
-    like the axis name. It translates to the ValueNameID field.
-
-    Optionally the value dict can contain a 'flags' item. It maps to
-    the AxisValue Flags field, and will be 0 when omitted.
-
-    The format of the AxisValue is determined by the remaining contents
-    of the value dictionary:
-
-    If the value dict contains a 'value' item, an AxisValue record
-    Format 1 is created. If in addition to the 'value' item it contains
-    a 'linkedValue' item, an AxisValue record Format 3 is built.
-
-    If the value dict contains a 'nominalValue' item, an AxisValue
-    record Format 2 is built. Optionally it may contain 'rangeMinValue'
-    and 'rangeMaxValue' items. These map to -Infinity and +Infinity
-    respectively if omitted.
-
-    You cannot specify Format 4 AxisValue tables this way, as they are
-    not tied to a single axis, and specify a name for a location that
-    is defined by multiple axes values. Instead, you need to supply the
-    'locations' argument.
-
-    The optional 'locations' argument specifies AxisValue Format 4
-    tables. It should be a list of dicts, where each dict has a 'name'
-    item, which works just like the value dicts above, an optional
-    'flags' item (defaulting to 0x0), and a 'location' dict. A
-    location dict key is an axis tag, and the associated value is the
-    location on the specified axis. They map to the AxisIndex and Value
-    fields of the AxisValueRecord.
-
-    Example::
-
-        locations = [
-            dict(name='Regular ABCD', location=dict(wght=300, ABCD=100)),
-            dict(name='Bold ABCD XYZ', location=dict(wght=600, ABCD=200)),
-        ]
-
-    The optional 'elidedFallbackName' argument can be a name ID (int),
-    a string, a dictionary containing multilingual names, or a list of
-    STATNameStatements. It translates to the ElidedFallbackNameID field.
-
-    The 'ttFont' argument must be a TTFont instance that already has a
-    'name' table. If a 'STAT' table already exists, it will be
-    overwritten by the newly created one.
-    """
-    ttFont["STAT"] = ttLib.newTable("STAT")
-    statTable = ttFont["STAT"].table = ot.STAT()
-    nameTable = ttFont["name"]
-    statTable.ElidedFallbackNameID = _addName(nameTable, elidedFallbackName)
-
-    # 'locations' contains data for AxisValue Format 4
-    axisRecords, axisValues = _buildAxisRecords(axes, nameTable)
-    if not locations:
-        statTable.Version = 0x00010001
-    else:
-        # We'll be adding Format 4 AxisValue records, which
-        # requires a higher table version
-        statTable.Version = 0x00010002
-        multiAxisValues = _buildAxisValuesFormat4(locations, axes, nameTable)
-        axisValues = multiAxisValues + axisValues
-
-    # Store AxisRecords
-    axisRecordArray = ot.AxisRecordArray()
-    axisRecordArray.Axis = axisRecords
-    # XXX these should not be hard-coded but computed automatically
-    statTable.DesignAxisRecordSize = 8
-    statTable.DesignAxisRecord = axisRecordArray
-    statTable.DesignAxisCount = len(axisRecords)
-
-    if axisValues:
-        # Store AxisValueRecords
-        axisValueArray = ot.AxisValueArray()
-        axisValueArray.AxisValue = axisValues
-        statTable.AxisValueArray = axisValueArray
-        statTable.AxisValueCount = len(axisValues)
-
-
-def _buildAxisRecords(axes, nameTable):
-    axisRecords = []
-    axisValues = []
-    for axisRecordIndex, axisDict in enumerate(axes):
-        axis = ot.AxisRecord()
-        axis.AxisTag = axisDict["tag"]
-        axis.AxisNameID = _addName(nameTable, axisDict["name"], 256)
-        axis.AxisOrdering = axisDict.get("ordering", axisRecordIndex)
-        axisRecords.append(axis)
-
-        for axisVal in axisDict.get("values", ()):
-            axisValRec = ot.AxisValue()
-            axisValRec.AxisIndex = axisRecordIndex
-            axisValRec.Flags = axisVal.get("flags", 0)
-            axisValRec.ValueNameID = _addName(nameTable, axisVal["name"])
-
-            if "value" in axisVal:
-                axisValRec.Value = axisVal["value"]
-                if "linkedValue" in axisVal:
-                    axisValRec.Format = 3
-                    axisValRec.LinkedValue = axisVal["linkedValue"]
-                else:
-                    axisValRec.Format = 1
-            elif "nominalValue" in axisVal:
-                axisValRec.Format = 2
-                axisValRec.NominalValue = axisVal["nominalValue"]
-                axisValRec.RangeMinValue = axisVal.get(
-                    "rangeMinValue", AXIS_VALUE_NEGATIVE_INFINITY
-                )
-                axisValRec.RangeMaxValue = axisVal.get(
-                    "rangeMaxValue", AXIS_VALUE_POSITIVE_INFINITY
-                )
-            else:
-                raise ValueError("Can't determine format for AxisValue")
-
-            axisValues.append(axisValRec)
-    return axisRecords, axisValues
-
-
-def _buildAxisValuesFormat4(locations, axes, nameTable):
-    axisTagToIndex = {}
-    for axisRecordIndex, axisDict in enumerate(axes):
-        axisTagToIndex[axisDict["tag"]] = axisRecordIndex
-
-    axisValues = []
-    for axisLocationDict in locations:
-        axisValRec = ot.AxisValue()
-        axisValRec.Format = 4
-        axisValRec.ValueNameID = _addName(nameTable, axisLocationDict["name"])
-        axisValRec.Flags = axisLocationDict.get("flags", 0)
-        axisValueRecords = []
-        for tag, value in axisLocationDict["location"].items():
-            avr = ot.AxisValueRecord()
-            avr.AxisIndex = axisTagToIndex[tag]
-            avr.Value = value
-            axisValueRecords.append(avr)
-        axisValueRecords.sort(key=lambda avr: avr.AxisIndex)
-        axisValRec.AxisCount = len(axisValueRecords)
-        axisValRec.AxisValueRecord = axisValueRecords
-        axisValues.append(axisValRec)
-    return axisValues
-
-
-def _addName(nameTable, value, minNameID=0):
-    if isinstance(value, int):
-        # Already a nameID
-        return value
-    if isinstance(value, str):
-        names = dict(en=value)
-    elif isinstance(value, dict):
-        names = value
-    elif isinstance(value, list):
-        nameID = nameTable._findUnusedNameID()
-        for nameRecord in value:
-            if isinstance(nameRecord, STATNameStatement):
-                nameTable.setName(
-                    nameRecord.string,
-                    nameID,
-                    nameRecord.platformID,
-                    nameRecord.platEncID,
-                    nameRecord.langID,
-                )
-            else:
-                raise TypeError("value must be a list of STATNameStatements")
-        return nameID
-    else:
-        raise TypeError("value must be int, str, dict or list")
-    return nameTable.addMultilingualName(names, minNameID=minNameID)
diff --git a/Lib/fontTools/otlLib/builder.py.sketch b/Lib/fontTools/otlLib/builder.py.sketch
deleted file mode 100644
index 9addf8c..0000000
--- a/Lib/fontTools/otlLib/builder.py.sketch
+++ /dev/null
@@ -1,105 +0,0 @@
-
-from fontTools.otlLib import builder as builder
-
-GDEF::mark filtering sets
-name::
-
-lookup_flags = builder.LOOKUP_FLAG_IGNORE_MARKS | builder.LOOKUP_FLAG_RTL
-smcp_subtable = builder.buildSingleSubstitute({'a':'a.scmp'})
-smcp_lookup = builder.buildLookup([smcp_subtable], lookup_flags=lookup_flags, mark_filter_set=int)
-
-lookups = [smcp_lookup, ...]
-
-scmp_feature = builder.buildFeature('smcp', [scmp_lookup], lookup_list=lookups)
-scmp_feature = builder.buildFeature('smcp', [0])
-
-features = [smcp_feature]
-
-default_langsys = builder.buildLangSys(set([scmp_feature]), requiredFeature=None, featureOrder=features)
-default_langsys = builder.buildLangSys(set([0]), requiredFeature=None)
-
-script = 
-
-
-#GSUB:
-
-builder.buildSingleSubst({'a':'a.scmp'})
-builder.buildLigatureSubst({('f','i'):'fi'})
-builder.buildMultipleSubst({'a':('a0','a1')})
-builder.buildAlternateSubst({'a':('a.0','a.1')})
-
-
-class ChainSequence : namedtuple(['backtrack', 'input', 'lookahead')])
-	pass
-
-ChainSequence(backtrack=..., input=..., lookahead=...)
-
-klass0 = frozenset()
-
-builder.buildChainContextGlyphs(
-	[
-		( (None, ('f','f','i'), (,)), ( (1,lookup_fi), (1,lookup_2) ) ),
-	],
-	glyphMap
-)
-builder.buildChainContextClass(
-	[
-		( (None, (2,0,1), (,)), ( (1,lookup_fi), (1,lookup_2) ) ),
-	],
-	klasses = ( backtrackClass, ... ),
-	glyphMap
-)
-builder.buildChainContextCoverage(
-	( (None, (frozenset('f'),frozenset('f'),frozenset('i')), (,)), ( (1,lookup_fi), (1,lookup_2) ) ),
-	glyphMap
-)
-builder.buildExtension(...)
-
-#GPOS:
-device = builder.buildDevice()
-builder.buildAnchor(100, -200) or (100,-200)
-builder.buildAnchor(100, -200, device=device)
-builder.buildAnchor(100, -200, point=2)
-
-valueRecord = builder.buildValue({'XAdvance':-200, ...})
-
-builder.buildSinglePos({'a':valueRecord})
-builder.buildPairPosGlyphs(
-	{
-		('a','b'): (valueRecord1,valueRecord2),
-	},
-	glyphMap,
-	, valueFormat1=None, valueFormat2=None
-)
-builder.buildPairPosClasses(
-	{
-		(frozenset(['a']),frozenset(['b'])): (valueRecord1,valueRecord2),
-	},
-	glyphMap,
-	, valueFormat1=None, valueFormat2=None
-)
-
-builder.buildCursivePos(
-	{
-		'alef': (entry,exit),
-	}
-	glyphMap
-)
-builder.buildMarkBasePos(
-	marks = {
-		'mark1': (klass, anchor),
-	},
-	bases = {
-		'base0': [anchor0, anchor1, anchor2],
-	},
-	glyphMap
-)
-builder.buildMarkBasePos(
-	marks = {
-		'mark1': (name, anchor),
-	},
-	bases = {
-		'base0': {'top':anchor0, 'left':anchor1},
-	},
-	glyphMap
-)
diff --git a/Lib/fontTools/otlLib/error.py b/Lib/fontTools/otlLib/error.py
deleted file mode 100644
index 1cbef57..0000000
--- a/Lib/fontTools/otlLib/error.py
+++ /dev/null
@@ -1,11 +0,0 @@
-class OpenTypeLibError(Exception):
-    def __init__(self, message, location):
-        Exception.__init__(self, message)
-        self.location = location
-
-    def __str__(self):
-        message = Exception.__str__(self)
-        if self.location:
-            return f"{self.location}: {message}"
-        else:
-            return message
diff --git a/Lib/fontTools/otlLib/maxContextCalc.py b/Lib/fontTools/otlLib/maxContextCalc.py
index 03e7561..5659310 100644
--- a/Lib/fontTools/otlLib/maxContextCalc.py
+++ b/Lib/fontTools/otlLib/maxContextCalc.py
@@ -1,11 +1,13 @@
-__all__ = ["maxCtxFont"]
+from __future__ import print_function, division, absolute_import, unicode_literals
+
+__all__ = ['maxCtxFont']
 
 
 def maxCtxFont(font):
     """Calculate the usMaxContext value for an entire font."""
 
     maxCtx = 0
-    for tag in ("GSUB", "GPOS"):
+    for tag in ('GSUB', 'GPOS'):
         if tag not in font:
             continue
         table = font[tag].table
@@ -23,59 +25,62 @@
     """
 
     # single positioning, single / multiple substitution
-    if (tag == "GPOS" and lookupType == 1) or (
-        tag == "GSUB" and lookupType in (1, 2, 3)
-    ):
+    if (tag == 'GPOS' and lookupType == 1) or (
+        tag == 'GSUB' and lookupType in (1, 2, 3)):
         maxCtx = max(maxCtx, 1)
 
     # pair positioning
-    elif tag == "GPOS" and lookupType == 2:
+    elif tag == 'GPOS' and lookupType == 2:
         maxCtx = max(maxCtx, 2)
 
     # ligatures
-    elif tag == "GSUB" and lookupType == 4:
+    elif tag == 'GSUB' and lookupType == 4:
         for ligatures in st.ligatures.values():
             for ligature in ligatures:
                 maxCtx = max(maxCtx, ligature.CompCount)
 
     # context
-    elif (tag == "GPOS" and lookupType == 7) or (tag == "GSUB" and lookupType == 5):
-        maxCtx = maxCtxContextualSubtable(maxCtx, st, "Pos" if tag == "GPOS" else "Sub")
+    elif (tag == 'GPOS' and lookupType == 7) or (
+          tag == 'GSUB' and lookupType == 5):
+        maxCtx = maxCtxContextualSubtable(
+            maxCtx, st, 'Pos' if tag == 'GPOS' else 'Sub')
 
     # chained context
-    elif (tag == "GPOS" and lookupType == 8) or (tag == "GSUB" and lookupType == 6):
+    elif (tag == 'GPOS' and lookupType == 8) or (
+          tag == 'GSUB' and lookupType == 6):
         maxCtx = maxCtxContextualSubtable(
-            maxCtx, st, "Pos" if tag == "GPOS" else "Sub", "Chain"
-        )
+            maxCtx, st, 'Pos' if tag == 'GPOS' else 'Sub', 'Chain')
 
     # extensions
-    elif (tag == "GPOS" and lookupType == 9) or (tag == "GSUB" and lookupType == 7):
-        maxCtx = maxCtxSubtable(maxCtx, tag, st.ExtensionLookupType, st.ExtSubTable)
+    elif (tag == 'GPOS' and lookupType == 9) or (
+          tag == 'GSUB' and lookupType == 7):
+        maxCtx = maxCtxSubtable(
+            maxCtx, tag, st.ExtensionLookupType, st.ExtSubTable)
 
     # reverse-chained context
-    elif tag == "GSUB" and lookupType == 8:
-        maxCtx = maxCtxContextualRule(maxCtx, st, "Reverse")
+    elif tag == 'GSUB' and lookupType == 8:
+        maxCtx = maxCtxContextualRule(maxCtx, st, 'Reverse')
 
     return maxCtx
 
 
-def maxCtxContextualSubtable(maxCtx, st, ruleType, chain=""):
+def maxCtxContextualSubtable(maxCtx, st, ruleType, chain=''):
     """Calculate usMaxContext based on a contextual feature subtable."""
 
     if st.Format == 1:
-        for ruleset in getattr(st, "%s%sRuleSet" % (chain, ruleType)):
+        for ruleset in getattr(st, '%s%sRuleSet' % (chain, ruleType)):
             if ruleset is None:
                 continue
-            for rule in getattr(ruleset, "%s%sRule" % (chain, ruleType)):
+            for rule in getattr(ruleset, '%s%sRule' % (chain, ruleType)):
                 if rule is None:
                     continue
                 maxCtx = maxCtxContextualRule(maxCtx, rule, chain)
 
     elif st.Format == 2:
-        for ruleset in getattr(st, "%s%sClassSet" % (chain, ruleType)):
+        for ruleset in getattr(st, '%s%sClassSet' % (chain, ruleType)):
             if ruleset is None:
                 continue
-            for rule in getattr(ruleset, "%s%sClassRule" % (chain, ruleType)):
+            for rule in getattr(ruleset, '%s%sClassRule' % (chain, ruleType)):
                 if rule is None:
                     continue
                 maxCtx = maxCtxContextualRule(maxCtx, rule, chain)
@@ -91,6 +96,6 @@
 
     if not chain:
         return max(maxCtx, st.GlyphCount)
-    elif chain == "Reverse":
+    elif chain == 'Reverse':
         return max(maxCtx, st.GlyphCount + st.LookAheadGlyphCount)
     return max(maxCtx, st.InputGlyphCount + st.LookAheadGlyphCount)
diff --git a/Lib/fontTools/pens/__init__.py b/Lib/fontTools/pens/__init__.py
index 156cb23..3f9abc9 100644
--- a/Lib/fontTools/pens/__init__.py
+++ b/Lib/fontTools/pens/__init__.py
@@ -1 +1,4 @@
 """Empty __init__.py file to signal Python this directory is a package."""
+
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
diff --git a/Lib/fontTools/pens/areaPen.py b/Lib/fontTools/pens/areaPen.py
index 403afe7..564caa4 100644
--- a/Lib/fontTools/pens/areaPen.py
+++ b/Lib/fontTools/pens/areaPen.py
@@ -1,5 +1,7 @@
 """Calculate the area of a glyph."""
 
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.pens.basePen import BasePen
 
 
diff --git a/Lib/fontTools/pens/basePen.py b/Lib/fontTools/pens/basePen.py
index 2161e02..e0d3ae0 100644
--- a/Lib/fontTools/pens/basePen.py
+++ b/Lib/fontTools/pens/basePen.py
@@ -36,27 +36,27 @@
 sequence of length 2 will do.
 """
 
-from typing import Tuple
-
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.loggingTools import LogMixin
 
 __all__ =  ["AbstractPen", "NullPen", "BasePen",
 			"decomposeSuperBezierSegment", "decomposeQuadraticSegment"]
 
 
-class AbstractPen:
+class AbstractPen(object):
 
-	def moveTo(self, pt: Tuple[float, float]) -> None:
+	def moveTo(self, pt):
 		"""Begin a new sub path, set the current point to 'pt'. You must
 		end each sub path with a call to pen.closePath() or pen.endPath().
 		"""
 		raise NotImplementedError
 
-	def lineTo(self, pt: Tuple[float, float]) -> None:
+	def lineTo(self, pt):
 		"""Draw a straight line from the current point to 'pt'."""
 		raise NotImplementedError
 
-	def curveTo(self, *points: Tuple[float, float]) -> None:
+	def curveTo(self, *points):
 		"""Draw a cubic bezier with an arbitrary number of control points.
 
 		The last point specified is on-curve, all others are off-curve
@@ -77,7 +77,7 @@
 		"""
 		raise NotImplementedError
 
-	def qCurveTo(self, *points: Tuple[float, float]) -> None:
+	def qCurveTo(self, *points):
 		"""Draw a whole string of quadratic curve segments.
 
 		The last point specified is on-curve, all others are off-curve
@@ -94,23 +94,19 @@
 		"""
 		raise NotImplementedError
 
-	def closePath(self) -> None:
+	def closePath(self):
 		"""Close the current sub path. You must call either pen.closePath()
 		or pen.endPath() after each sub path.
 		"""
 		pass
 
-	def endPath(self) -> None:
+	def endPath(self):
 		"""End the current sub path, but don't close it. You must call
 		either pen.closePath() or pen.endPath() after each sub path.
 		"""
 		pass
 
-	def addComponent(
-		self,
-		glyphName: str,
-		transformation: Tuple[float, float, float, float, float, float]
-	) -> None:
+	def addComponent(self, glyphName, transformation):
 		"""Add a sub glyph. The 'transformation' argument must be a 6-tuple
 		containing an affine transformation, or a Transform object from the
 		fontTools.misc.transform module. More precisely: it should be a
@@ -119,7 +115,7 @@
 		raise NotImplementedError
 
 
-class NullPen(AbstractPen):
+class NullPen(object):
 
 	"""A pen that does nothing.
 	"""
@@ -152,10 +148,6 @@
 	pass
 
 
-class MissingComponentError(KeyError):
-	"""Indicates a component pointing to a non-existent glyph in the glyphset."""
-
-
 class DecomposingPen(LoggingPen):
 
 	""" Implements a 'addComponent' method that decomposes components
@@ -164,12 +156,10 @@
 
 	You must override moveTo, lineTo, curveTo and qCurveTo. You may
 	additionally override closePath, endPath and addComponent.
-
-	By default a warning message is logged when a base glyph is missing;
-	set the class variable ``skipMissingComponents`` to False if you want
-	to raise a :class:`MissingComponentError` exception.
 	"""
 
+	# By default a warning message is logged when a base glyph is missing;
+	# set this to False if you want to raise a 'KeyError' exception
 	skipMissingComponents = True
 
 	def __init__(self, glyphSet):
@@ -187,7 +177,7 @@
 			glyph = self.glyphSet[glyphName]
 		except KeyError:
 			if not self.skipMissingComponents:
-				raise MissingComponentError(glyphName)
+				raise
 			self.log.warning(
 				"glyph '%s' is missing from glyphSet; skipped" % glyphName)
 		else:
diff --git a/Lib/fontTools/pens/boundsPen.py b/Lib/fontTools/pens/boundsPen.py
index 810715c..3a103e3 100644
--- a/Lib/fontTools/pens/boundsPen.py
+++ b/Lib/fontTools/pens/boundsPen.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.arrayTools import updateBounds, pointInRect, unionRect
 from fontTools.misc.bezierTools import calcCubicBounds, calcQuadraticBounds
 from fontTools.pens.basePen import BasePen
diff --git a/Lib/fontTools/pens/cocoaPen.py b/Lib/fontTools/pens/cocoaPen.py
index 67482b4..9920ab0 100644
--- a/Lib/fontTools/pens/cocoaPen.py
+++ b/Lib/fontTools/pens/cocoaPen.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.pens.basePen import BasePen
 
 
diff --git a/Lib/fontTools/pens/cu2quPen.py b/Lib/fontTools/pens/cu2quPen.py
deleted file mode 100644
index 497585b..0000000
--- a/Lib/fontTools/pens/cu2quPen.py
+++ /dev/null
@@ -1,257 +0,0 @@
-# Copyright 2016 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from fontTools.cu2qu import curve_to_quadratic
-from fontTools.pens.basePen import AbstractPen, decomposeSuperBezierSegment
-from fontTools.pens.reverseContourPen import ReverseContourPen
-from fontTools.pens.pointPen import BasePointToSegmentPen
-from fontTools.pens.pointPen import ReverseContourPointPen
-
-
-class Cu2QuPen(AbstractPen):
-    """ A filter pen to convert cubic bezier curves to quadratic b-splines
-    using the FontTools SegmentPen protocol.
-
-    other_pen: another SegmentPen used to draw the transformed outline.
-    max_err: maximum approximation error in font units. For optimal results,
-        if you know the UPEM of the font, we recommend setting this to a
-        value equal, or close to UPEM / 1000.
-    reverse_direction: flip the contours' direction but keep starting point.
-    stats: a dictionary counting the point numbers of quadratic segments.
-    ignore_single_points: don't emit contours containing only a single point
-
-    NOTE: The "ignore_single_points" argument is deprecated since v1.3.0,
-    which dropped Robofab subpport. It's no longer needed to special-case
-    UFO2-style anchors (aka "named points") when using ufoLib >= 2.0,
-    as these are no longer drawn onto pens as single-point contours,
-    but are handled separately as anchors.
-    """
-
-    def __init__(self, other_pen, max_err, reverse_direction=False,
-                 stats=None, ignore_single_points=False):
-        if reverse_direction:
-            self.pen = ReverseContourPen(other_pen)
-        else:
-            self.pen = other_pen
-        self.max_err = max_err
-        self.stats = stats
-        if ignore_single_points:
-            import warnings
-            warnings.warn("ignore_single_points is deprecated and "
-                          "will be removed in future versions",
-                          UserWarning, stacklevel=2)
-        self.ignore_single_points = ignore_single_points
-        self.start_pt = None
-        self.current_pt = None
-
-    def _check_contour_is_open(self):
-        if self.current_pt is None:
-            raise AssertionError("moveTo is required")
-
-    def _check_contour_is_closed(self):
-        if self.current_pt is not None:
-            raise AssertionError("closePath or endPath is required")
-
-    def _add_moveTo(self):
-        if self.start_pt is not None:
-            self.pen.moveTo(self.start_pt)
-            self.start_pt = None
-
-    def moveTo(self, pt):
-        self._check_contour_is_closed()
-        self.start_pt = self.current_pt = pt
-        if not self.ignore_single_points:
-            self._add_moveTo()
-
-    def lineTo(self, pt):
-        self._check_contour_is_open()
-        self._add_moveTo()
-        self.pen.lineTo(pt)
-        self.current_pt = pt
-
-    def qCurveTo(self, *points):
-        self._check_contour_is_open()
-        n = len(points)
-        if n == 1:
-            self.lineTo(points[0])
-        elif n > 1:
-            self._add_moveTo()
-            self.pen.qCurveTo(*points)
-            self.current_pt = points[-1]
-        else:
-            raise AssertionError("illegal qcurve segment point count: %d" % n)
-
-    def _curve_to_quadratic(self, pt1, pt2, pt3):
-        curve = (self.current_pt, pt1, pt2, pt3)
-        quadratic = curve_to_quadratic(curve, self.max_err)
-        if self.stats is not None:
-            n = str(len(quadratic) - 2)
-            self.stats[n] = self.stats.get(n, 0) + 1
-        self.qCurveTo(*quadratic[1:])
-
-    def curveTo(self, *points):
-        self._check_contour_is_open()
-        n = len(points)
-        if n == 3:
-            # this is the most common case, so we special-case it
-            self._curve_to_quadratic(*points)
-        elif n > 3:
-            for segment in decomposeSuperBezierSegment(points):
-                self._curve_to_quadratic(*segment)
-        elif n == 2:
-            self.qCurveTo(*points)
-        elif n == 1:
-            self.lineTo(points[0])
-        else:
-            raise AssertionError("illegal curve segment point count: %d" % n)
-
-    def closePath(self):
-        self._check_contour_is_open()
-        if self.start_pt is None:
-            # if 'start_pt' is _not_ None, we are ignoring single-point paths
-            self.pen.closePath()
-        self.current_pt = self.start_pt = None
-
-    def endPath(self):
-        self._check_contour_is_open()
-        if self.start_pt is None:
-            self.pen.endPath()
-        self.current_pt = self.start_pt = None
-
-    def addComponent(self, glyphName, transformation):
-        self._check_contour_is_closed()
-        self.pen.addComponent(glyphName, transformation)
-
-
-class Cu2QuPointPen(BasePointToSegmentPen):
-    """ A filter pen to convert cubic bezier curves to quadratic b-splines
-    using the RoboFab PointPen protocol.
-
-    other_point_pen: another PointPen used to draw the transformed outline.
-    max_err: maximum approximation error in font units. For optimal results,
-        if you know the UPEM of the font, we recommend setting this to a
-        value equal, or close to UPEM / 1000.
-    reverse_direction: reverse the winding direction of all contours.
-    stats: a dictionary counting the point numbers of quadratic segments.
-    """
-
-    def __init__(self, other_point_pen, max_err, reverse_direction=False,
-                 stats=None):
-        BasePointToSegmentPen.__init__(self)
-        if reverse_direction:
-            self.pen = ReverseContourPointPen(other_point_pen)
-        else:
-            self.pen = other_point_pen
-        self.max_err = max_err
-        self.stats = stats
-
-    def _flushContour(self, segments):
-        assert len(segments) >= 1
-        closed = segments[0][0] != "move"
-        new_segments = []
-        prev_points = segments[-1][1]
-        prev_on_curve = prev_points[-1][0]
-        for segment_type, points in segments:
-            if segment_type == 'curve':
-                for sub_points in self._split_super_bezier_segments(points):
-                    on_curve, smooth, name, kwargs = sub_points[-1]
-                    bcp1, bcp2 = sub_points[0][0], sub_points[1][0]
-                    cubic = [prev_on_curve, bcp1, bcp2, on_curve]
-                    quad = curve_to_quadratic(cubic, self.max_err)
-                    if self.stats is not None:
-                        n = str(len(quad) - 2)
-                        self.stats[n] = self.stats.get(n, 0) + 1
-                    new_points = [(pt, False, None, {}) for pt in quad[1:-1]]
-                    new_points.append((on_curve, smooth, name, kwargs))
-                    new_segments.append(["qcurve", new_points])
-                    prev_on_curve = sub_points[-1][0]
-            else:
-                new_segments.append([segment_type, points])
-                prev_on_curve = points[-1][0]
-        if closed:
-            # the BasePointToSegmentPen.endPath method that calls _flushContour
-            # rotates the point list of closed contours so that they end with
-            # the first on-curve point. We restore the original starting point.
-            new_segments = new_segments[-1:] + new_segments[:-1]
-        self._drawPoints(new_segments)
-
-    def _split_super_bezier_segments(self, points):
-        sub_segments = []
-        # n is the number of control points
-        n = len(points) - 1
-        if n == 2:
-            # a simple bezier curve segment
-            sub_segments.append(points)
-        elif n > 2:
-            # a "super" bezier; decompose it
-            on_curve, smooth, name, kwargs = points[-1]
-            num_sub_segments = n - 1
-            for i, sub_points in enumerate(decomposeSuperBezierSegment([
-                    pt for pt, _, _, _ in points])):
-                new_segment = []
-                for point in sub_points[:-1]:
-                    new_segment.append((point, False, None, {}))
-                if i == (num_sub_segments - 1):
-                    # the last on-curve keeps its original attributes
-                    new_segment.append((on_curve, smooth, name, kwargs))
-                else:
-                    # on-curves of sub-segments are always "smooth"
-                    new_segment.append((sub_points[-1], True, None, {}))
-                sub_segments.append(new_segment)
-        else:
-            raise AssertionError(
-                "expected 2 control points, found: %d" % n)
-        return sub_segments
-
-    def _drawPoints(self, segments):
-        pen = self.pen
-        pen.beginPath()
-        last_offcurves = []
-        for i, (segment_type, points) in enumerate(segments):
-            if segment_type in ("move", "line"):
-                assert len(points) == 1, (
-                    "illegal line segment point count: %d" % len(points))
-                pt, smooth, name, kwargs = points[0]
-                pen.addPoint(pt, segment_type, smooth, name, **kwargs)
-            elif segment_type == "qcurve":
-                assert len(points) >= 2, (
-                    "illegal qcurve segment point count: %d" % len(points))
-                offcurves = points[:-1]
-                if offcurves:
-                    if i == 0:
-                        # any off-curve points preceding the first on-curve
-                        # will be appended at the end of the contour
-                        last_offcurves = offcurves
-                    else:
-                        for (pt, smooth, name, kwargs) in offcurves:
-                            pen.addPoint(pt, None, smooth, name, **kwargs)
-                pt, smooth, name, kwargs = points[-1]
-                if pt is None:
-                    # special quadratic contour with no on-curve points:
-                    # we need to skip the "None" point. See also the Pen
-                    # protocol's qCurveTo() method and fontTools.pens.basePen
-                    pass
-                else:
-                    pen.addPoint(pt, segment_type, smooth, name, **kwargs)
-            else:
-                # 'curve' segments must have been converted to 'qcurve' by now
-                raise AssertionError(
-                    "unexpected segment type: %r" % segment_type)
-        for (pt, smooth, name, kwargs) in last_offcurves:
-            pen.addPoint(pt, None, smooth, name, **kwargs)
-        pen.endPath()
-
-    def addComponent(self, baseGlyphName, transformation):
-        assert self.currentPath is None
-        self.pen.addComponent(baseGlyphName, transformation)
diff --git a/Lib/fontTools/pens/filterPen.py b/Lib/fontTools/pens/filterPen.py
index 4355ba4..2f94550 100644
--- a/Lib/fontTools/pens/filterPen.py
+++ b/Lib/fontTools/pens/filterPen.py
@@ -1,12 +1,13 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.pens.basePen import AbstractPen
-from fontTools.pens.pointPen import AbstractPointPen
 from fontTools.pens.recordingPen import RecordingPen
 
 
 class _PassThruComponentsMixin(object):
 
-    def addComponent(self, glyphName, transformation, **kwargs):
-        self._outPen.addComponent(glyphName, transformation, **kwargs)
+    def addComponent(self, glyphName, transformation):
+        self._outPen.addComponent(glyphName, transformation)
 
 
 class FilterPen(_PassThruComponentsMixin, AbstractPen):
@@ -118,41 +119,3 @@
         Otherwise, the return value is drawn with the output pen.
         """
         return  # or return contour
-
-
-class FilterPointPen(_PassThruComponentsMixin, AbstractPointPen):
-    """ Baseclass for point pens that apply some transformation to the
-    coordinates they receive and pass them to another point pen.
-
-    You can override any of its methods. The default implementation does
-    nothing, but passes the commands unmodified to the other pen.
-
-    >>> from fontTools.pens.recordingPen import RecordingPointPen
-    >>> rec = RecordingPointPen()
-    >>> pen = FilterPointPen(rec)
-    >>> v = iter(rec.value)
-    >>> pen.beginPath(identifier="abc")
-    >>> next(v)
-    ('beginPath', (), {'identifier': 'abc'})
-    >>> pen.addPoint((1, 2), "line", False)
-    >>> next(v)
-    ('addPoint', ((1, 2), 'line', False, None), {})
-    >>> pen.addComponent("a", (2, 0, 0, 2, 10, -10), identifier="0001")
-    >>> next(v)
-    ('addComponent', ('a', (2, 0, 0, 2, 10, -10)), {'identifier': '0001'})
-    >>> pen.endPath()
-    >>> next(v)
-    ('endPath', (), {})
-    """
-
-    def __init__(self, outPointPen):
-        self._outPen = outPointPen
-
-    def beginPath(self, **kwargs):
-        self._outPen.beginPath(**kwargs)
-
-    def endPath(self):
-        self._outPen.endPath()
-
-    def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs):
-        self._outPen.addPoint(pt, segmentType, smooth, name, **kwargs)
diff --git a/Lib/fontTools/pens/hashPointPen.py b/Lib/fontTools/pens/hashPointPen.py
deleted file mode 100644
index 9aef5d8..0000000
--- a/Lib/fontTools/pens/hashPointPen.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# Modified from https://github.com/adobe-type-tools/psautohint/blob/08b346865710ed3c172f1eb581d6ef243b203f99/python/psautohint/ufoFont.py#L800-L838
-import hashlib
-
-from fontTools.pens.basePen import MissingComponentError
-from fontTools.pens.pointPen import AbstractPointPen
-
-
-class HashPointPen(AbstractPointPen):
-    """
-    This pen can be used to check if a glyph's contents (outlines plus
-    components) have changed.
-
-    Components are added as the original outline plus each composite's
-    transformation.
-
-    Example: You have some TrueType hinting code for a glyph which you want to
-    compile. The hinting code specifies a hash value computed with HashPointPen
-    that was valid for the glyph's outlines at the time the hinting code was
-    written. Now you can calculate the hash for the glyph's current outlines to
-    check if the outlines have changed, which would probably make the hinting
-    code invalid.
-
-    > glyph = ufo[name]
-    > hash_pen = HashPointPen(glyph.width, ufo)
-    > glyph.drawPoints(hash_pen)
-    > ttdata = glyph.lib.get("public.truetype.instructions", None)
-    > stored_hash = ttdata.get("id", None)  # The hash is stored in the "id" key
-    > if stored_hash is None or stored_hash != hash_pen.hash:
-    >    logger.error(f"Glyph hash mismatch, glyph '{name}' will have no instructions in font.")
-    > else:
-    >    # The hash values are identical, the outline has not changed.
-    >    # Compile the hinting code ...
-    >    pass
-    """
-
-    def __init__(self, glyphWidth=0, glyphSet=None):
-        self.glyphset = glyphSet
-        self.data = ["w%s" % round(glyphWidth, 9)]
-
-    @property
-    def hash(self):
-        data = "".join(self.data)
-        if len(data) >= 128:
-            data = hashlib.sha512(data.encode("ascii")).hexdigest()
-        return data
-
-    def beginPath(self, identifier=None, **kwargs):
-        pass
-
-    def endPath(self):
-        self.data.append("|")
-
-    def addPoint(
-        self,
-        pt,
-        segmentType=None,
-        smooth=False,
-        name=None,
-        identifier=None,
-        **kwargs,
-    ):
-        if segmentType is None:
-            pt_type = "o"  # offcurve
-        else:
-            pt_type = segmentType[0]
-        self.data.append(f"{pt_type}{pt[0]:g}{pt[1]:+g}")
-
-    def addComponent(
-        self, baseGlyphName, transformation, identifier=None, **kwargs
-    ):
-        tr = "".join([f"{t:+}" for t in transformation])
-        self.data.append("[")
-        try:
-            self.glyphset[baseGlyphName].drawPoints(self)
-        except KeyError:
-            raise MissingComponentError(baseGlyphName)
-        self.data.append(f"({tr})]")
diff --git a/Lib/fontTools/pens/momentsPen.py b/Lib/fontTools/pens/momentsPen.py
index 8c90f70..b83102c 100644
--- a/Lib/fontTools/pens/momentsPen.py
+++ b/Lib/fontTools/pens/momentsPen.py
@@ -1,15 +1,13 @@
 """Pen calculating 0th, 1st, and 2nd moments of area of glyph shapes.
 This is low-level, autogenerated pen. Use statisticsPen instead."""
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.pens.basePen import BasePen
 
 
 __all__ = ["MomentsPen"]
 
 
-class OpenContourError(NotImplementedError):
-    pass
-
-
 class MomentsPen(BasePen):
 
 	def __init__(self, glyphset=None):
@@ -33,9 +31,8 @@
 	def _endPath(self):
 		p0 = self._getCurrentPoint()
 		if p0 != self.__startPoint:
-			raise OpenContourError(
-							"Green theorem is not defined on open contours."
-			)
+			# Green theorem is not defined on open contours.
+			raise NotImplementedError
 
 	def _lineTo(self, p1):
 		x0,y0 = self._getCurrentPoint()
diff --git a/Lib/fontTools/pens/perimeterPen.py b/Lib/fontTools/pens/perimeterPen.py
index 9a09cb8..12e7e47 100644
--- a/Lib/fontTools/pens/perimeterPen.py
+++ b/Lib/fontTools/pens/perimeterPen.py
@@ -1,6 +1,8 @@
 # -*- coding: utf-8 -*-
 """Calculate the perimeter of a glyph."""
 
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.pens.basePen import BasePen
 from fontTools.misc.bezierTools import approximateQuadraticArcLengthC, calcQuadraticArcLengthC, approximateCubicArcLengthC, calcCubicArcLengthC
 import math
diff --git a/Lib/fontTools/pens/pointInsidePen.py b/Lib/fontTools/pens/pointInsidePen.py
index 34597f4..3311841 100644
--- a/Lib/fontTools/pens/pointInsidePen.py
+++ b/Lib/fontTools/pens/pointInsidePen.py
@@ -2,6 +2,8 @@
 for shapes.
 """
 
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.pens.basePen import BasePen
 from fontTools.misc.bezierTools import solveQuadratic, solveCubic
 
diff --git a/Lib/fontTools/pens/pointPen.py b/Lib/fontTools/pens/pointPen.py
index 26f99d4..6299e86 100644
--- a/Lib/fontTools/pens/pointPen.py
+++ b/Lib/fontTools/pens/pointPen.py
@@ -11,11 +11,9 @@
 This allows the caller to provide more data for each point.
 For instance, whether or not a point is smooth, and its name.
 """
-
-import math
-from typing import Any, Optional, Tuple
-
+from __future__ import absolute_import, unicode_literals
 from fontTools.pens.basePen import AbstractPen
+import math
 
 __all__ = [
 	"AbstractPointPen",
@@ -27,36 +25,26 @@
 ]
 
 
-class AbstractPointPen:
-	"""Baseclass for all PointPens."""
+class AbstractPointPen(object):
+	"""
+	Baseclass for all PointPens.
+	"""
 
-	def beginPath(self, identifier: Optional[str] = None, **kwargs: Any) -> None:
+	def beginPath(self, identifier=None, **kwargs):
 		"""Start a new sub path."""
 		raise NotImplementedError
 
-	def endPath(self) -> None:
+	def endPath(self):
 		"""End the current sub path."""
 		raise NotImplementedError
 
-	def addPoint(
-		self,
-		pt: Tuple[float, float],
-		segmentType: Optional[str] = None,
-		smooth: bool = False,
-		name: Optional[str] = None,
-		identifier: Optional[str] = None,
-		**kwargs: Any
-	) -> None:
+	def addPoint(self, pt, segmentType=None, smooth=False, name=None,
+				 identifier=None, **kwargs):
 		"""Add a point to the current sub path."""
 		raise NotImplementedError
 
-	def addComponent(
-		self,
-		baseGlyphName: str,
-		transformation: Tuple[float, float, float, float, float, float],
-		identifier: Optional[str] = None,
-		**kwargs: Any
-	) -> None:
+	def addComponent(self, baseGlyphName, transformation, identifier=None,
+					 **kwargs):
 		"""Add a sub glyph."""
 		raise NotImplementedError
 
@@ -193,36 +181,18 @@
 			pen.moveTo(movePt)
 		outputImpliedClosingLine = self.outputImpliedClosingLine
 		nSegments = len(segments)
-		lastPt = movePt
 		for i in range(nSegments):
 			segmentType, points = segments[i]
 			points = [pt for pt, smooth, name, kwargs in points]
 			if segmentType == "line":
 				assert len(points) == 1, "illegal line segment point count: %d" % len(points)
 				pt = points[0]
-				# For closed contours, a 'lineTo' is always implied from the last oncurve
-				# point to the starting point, thus we can omit it when the last and
-				# starting point don't overlap.
-				# However, when the last oncurve point is a "line" segment and has same
-				# coordinates as the starting point of a closed contour, we need to output
-				# the closing 'lineTo' explicitly (regardless of the value of the
-				# 'outputImpliedClosingLine' option) in order to disambiguate this case from
-				# the implied closing 'lineTo', otherwise the duplicate point would be lost.
-				# See https://github.com/googlefonts/fontmake/issues/572.
-				if (
-					i + 1 != nSegments
-					or outputImpliedClosingLine
-					or not closed
-					or pt == lastPt
-				):
+				if i + 1 != nSegments or outputImpliedClosingLine or not closed:
 					pen.lineTo(pt)
-					lastPt = pt
 			elif segmentType == "curve":
 				pen.curveTo(*points)
-				lastPt = points[-1]
 			elif segmentType == "qcurve":
 				pen.qCurveTo(*points)
-				lastPt = points[-1]
 			else:
 				assert 0, "illegal segmentType: %s" % segmentType
 		if closed:
@@ -260,11 +230,9 @@
 		self.contour.append((pt, "move"))
 
 	def lineTo(self, pt):
-		assert self.contour is not None, "contour missing required initial moveTo"
 		self.contour.append((pt, "line"))
 
 	def curveTo(self, *pts):
-		assert self.contour is not None, "contour missing required initial moveTo"
 		for pt in pts[:-1]:
 			self.contour.append((pt, None))
 		self.contour.append((pts[-1], "curve"))
@@ -272,15 +240,12 @@
 	def qCurveTo(self, *pts):
 		if pts[-1] is None:
 			self.contour = []
-		else:
-			assert self.contour is not None, "contour missing required initial moveTo"
 		for pt in pts[:-1]:
 			self.contour.append((pt, None))
 		if pts[-1] is not None:
 			self.contour.append((pts[-1], "qcurve"))
 
 	def closePath(self):
-		assert self.contour is not None, "contour missing required initial moveTo"
 		if len(self.contour) > 1 and self.contour[0][0] == self.contour[-1][0]:
 			self.contour[0] = self.contour[-1]
 			del self.contour[-1]
@@ -294,7 +259,6 @@
 		self.contour = None
 
 	def endPath(self):
-		assert self.contour is not None, "contour missing required initial moveTo"
 		self._flushContour()
 		self.contour = None
 
diff --git a/Lib/fontTools/pens/qtPen.py b/Lib/fontTools/pens/qtPen.py
index 3473645..01cb37a 100644
--- a/Lib/fontTools/pens/qtPen.py
+++ b/Lib/fontTools/pens/qtPen.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.pens.basePen import BasePen
 
 
diff --git a/Lib/fontTools/pens/quartzPen.py b/Lib/fontTools/pens/quartzPen.py
deleted file mode 100644
index 16b9c2d..0000000
--- a/Lib/fontTools/pens/quartzPen.py
+++ /dev/null
@@ -1,45 +0,0 @@
-from fontTools.pens.basePen import BasePen
-
-from Quartz.CoreGraphics import CGPathCreateMutable, CGPathMoveToPoint
-from Quartz.CoreGraphics import CGPathAddLineToPoint, CGPathAddCurveToPoint
-from Quartz.CoreGraphics import CGPathAddQuadCurveToPoint, CGPathCloseSubpath
-	
-
-__all__ = ["QuartzPen"]
-
-
-class QuartzPen(BasePen):
-	
-	"""A pen that creates a CGPath
-	
-	Parameters
-	- path: an optional CGPath to add to
-	- xform: an optional CGAffineTransform to apply to the path
-	"""
-
-	def __init__(self, glyphSet, path=None, xform=None):
-		BasePen.__init__(self, glyphSet)
-		if path is None:
-			path = CGPathCreateMutable()
-		self.path = path
-		self.xform = xform
-
-	def _moveTo(self, pt):
-		x, y = pt
-		CGPathMoveToPoint(self.path, self.xform, x, y)
-
-	def _lineTo(self, pt):
-		x, y = pt
-		CGPathAddLineToPoint(self.path, self.xform, x, y)
-
-	def _curveToOne(self, p1, p2, p3):
-		(x1, y1), (x2, y2), (x3, y3) = p1, p2, p3
-		CGPathAddCurveToPoint(self.path, self.xform, x1, y1, x2, y2, x3, y3)
-		
-	def _qCurveToOne(self, p1, p2):
-		(x1, y1), (x2, y2) = p1, p2
-		CGPathAddQuadCurveToPoint(self.path, self.xform, x1, y1, x2, y2)
-	
-	def _closePath(self):
-		CGPathCloseSubpath(self.path)
-
diff --git a/Lib/fontTools/pens/recordingPen.py b/Lib/fontTools/pens/recordingPen.py
index 99e87e5..e583c8f 100644
--- a/Lib/fontTools/pens/recordingPen.py
+++ b/Lib/fontTools/pens/recordingPen.py
@@ -1,14 +1,10 @@
 """Pen recording operations that can be accessed or replayed."""
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.pens.basePen import AbstractPen, DecomposingPen
-from fontTools.pens.pointPen import AbstractPointPen
 
 
-__all__ = [
-	"replayRecording",
-	"RecordingPen",
-	"DecomposingRecordingPen",
-	"RecordingPointPen",
-]
+__all__ = ["replayRecording", "RecordingPen", "DecomposingRecordingPen"]
 
 
 def replayRecording(recording, pen):
@@ -94,52 +90,8 @@
 	skipMissingComponents = False
 
 
-class RecordingPointPen(AbstractPointPen):
-	"""PointPen recording operations that can be accessed or replayed.
-
-	The recording can be accessed as pen.value; or replayed using
-	pointPen.replay(otherPointPen).
-
-	Usage example:
-	==============
-	from defcon import Font
-	from fontTools.pens.recordingPen import RecordingPointPen
-
-	glyph_name = 'a'
-	font_path = 'MyFont.ufo'
-
-	font = Font(font_path)
-	glyph = font[glyph_name]
-
-	pen = RecordingPointPen()
-	glyph.drawPoints(pen)
-	print(pen.value)
-
-	new_glyph = font.newGlyph('b')
-	pen.replay(new_glyph.getPointPen())
-	"""
-
-	def __init__(self):
-		self.value = []
-
-	def beginPath(self, **kwargs):
-		self.value.append(("beginPath", (), kwargs))
-
-	def endPath(self):
-		self.value.append(("endPath", (), {}))
-
-	def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs):
-		self.value.append(("addPoint", (pt, segmentType, smooth, name), kwargs))
-
-	def addComponent(self, baseGlyphName, transformation, **kwargs):
-		self.value.append(("addComponent", (baseGlyphName, transformation), kwargs))
-
-	def replay(self, pointPen):
-		for operator, args, kwargs in self.value:
-			getattr(pointPen, operator)(*args, **kwargs)
-
-
 if __name__ == "__main__":
+	from fontTools.pens.basePen import _TestPen
 	pen = RecordingPen()
 	pen.moveTo((0, 0))
 	pen.lineTo((0, 100))
diff --git a/Lib/fontTools/pens/reportLabPen.py b/Lib/fontTools/pens/reportLabPen.py
index c0a4610..2068b25 100644
--- a/Lib/fontTools/pens/reportLabPen.py
+++ b/Lib/fontTools/pens/reportLabPen.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.pens.basePen import BasePen
 from reportlab.graphics.shapes import Path
 
diff --git a/Lib/fontTools/pens/reverseContourPen.py b/Lib/fontTools/pens/reverseContourPen.py
index 9b3241b..27e54d7 100644
--- a/Lib/fontTools/pens/reverseContourPen.py
+++ b/Lib/fontTools/pens/reverseContourPen.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.arrayTools import pairwise
 from fontTools.pens.filterPen import ContourFilterPen
 
diff --git a/Lib/fontTools/pens/roundingPen.py b/Lib/fontTools/pens/roundingPen.py
deleted file mode 100644
index 2a7c476..0000000
--- a/Lib/fontTools/pens/roundingPen.py
+++ /dev/null
@@ -1,112 +0,0 @@
-from fontTools.misc.roundTools import otRound
-from fontTools.misc.transform import Transform
-from fontTools.pens.filterPen import FilterPen, FilterPointPen
-
-
-__all__ = ["RoundingPen", "RoundingPointPen"]
-
-
-class RoundingPen(FilterPen):
-    """
-    Filter pen that rounds point coordinates and component XY offsets to integer.
-
-    >>> from fontTools.pens.recordingPen import RecordingPen
-    >>> recpen = RecordingPen()
-    >>> roundpen = RoundingPen(recpen)
-    >>> roundpen.moveTo((0.4, 0.6))
-    >>> roundpen.lineTo((1.6, 2.5))
-    >>> roundpen.qCurveTo((2.4, 4.6), (3.3, 5.7), (4.9, 6.1))
-    >>> roundpen.curveTo((6.4, 8.6), (7.3, 9.7), (8.9, 10.1))
-    >>> roundpen.addComponent("a", (1.5, 0, 0, 1.5, 10.5, -10.5))
-    >>> recpen.value == [
-    ...     ('moveTo', ((0, 1),)),
-    ...     ('lineTo', ((2, 3),)),
-    ...     ('qCurveTo', ((2, 5), (3, 6), (5, 6))),
-    ...     ('curveTo', ((6, 9), (7, 10), (9, 10))),
-    ...     ('addComponent', ('a', (1.5, 0, 0, 1.5, 11, -10))),
-    ... ]
-    True
-    """
-
-    def __init__(self, outPen, roundFunc=otRound):
-        super().__init__(outPen)
-        self.roundFunc = roundFunc
-
-    def moveTo(self, pt):
-        self._outPen.moveTo((self.roundFunc(pt[0]), self.roundFunc(pt[1])))
-
-    def lineTo(self, pt):
-        self._outPen.lineTo((self.roundFunc(pt[0]), self.roundFunc(pt[1])))
-
-    def curveTo(self, *points):
-        self._outPen.curveTo(
-            *((self.roundFunc(x), self.roundFunc(y)) for x, y in points)
-        )
-
-    def qCurveTo(self, *points):
-        self._outPen.qCurveTo(
-            *((self.roundFunc(x), self.roundFunc(y)) for x, y in points)
-        )
-
-    def addComponent(self, glyphName, transformation):
-        self._outPen.addComponent(
-            glyphName,
-            Transform(
-                *transformation[:4],
-                self.roundFunc(transformation[4]),
-                self.roundFunc(transformation[5]),
-            ),
-        )
-
-
-class RoundingPointPen(FilterPointPen):
-    """
-    Filter point pen that rounds point coordinates and component XY offsets to integer.
-
-    >>> from fontTools.pens.recordingPen import RecordingPointPen
-    >>> recpen = RecordingPointPen()
-    >>> roundpen = RoundingPointPen(recpen)
-    >>> roundpen.beginPath()
-    >>> roundpen.addPoint((0.4, 0.6), 'line')
-    >>> roundpen.addPoint((1.6, 2.5), 'line')
-    >>> roundpen.addPoint((2.4, 4.6))
-    >>> roundpen.addPoint((3.3, 5.7))
-    >>> roundpen.addPoint((4.9, 6.1), 'qcurve')
-    >>> roundpen.endPath()
-    >>> roundpen.addComponent("a", (1.5, 0, 0, 1.5, 10.5, -10.5))
-    >>> recpen.value == [
-    ...     ('beginPath', (), {}),
-    ...     ('addPoint', ((0, 1), 'line', False, None), {}),
-    ...     ('addPoint', ((2, 3), 'line', False, None), {}),
-    ...     ('addPoint', ((2, 5), None, False, None), {}),
-    ...     ('addPoint', ((3, 6), None, False, None), {}),
-    ...     ('addPoint', ((5, 6), 'qcurve', False, None), {}),
-    ...     ('endPath', (), {}),
-    ...     ('addComponent', ('a', (1.5, 0, 0, 1.5, 11, -10)), {}),
-    ... ]
-    True
-    """
-
-    def __init__(self, outPen, roundFunc=otRound):
-        super().__init__(outPen)
-        self.roundFunc = roundFunc
-
-    def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs):
-        self._outPen.addPoint(
-            (self.roundFunc(pt[0]), self.roundFunc(pt[1])),
-            segmentType=segmentType,
-            smooth=smooth,
-            name=name,
-            **kwargs,
-        )
-
-    def addComponent(self, baseGlyphName, transformation, **kwargs):
-        self._outPen.addComponent(
-            baseGlyphName,
-            Transform(
-                *transformation[:4],
-                self.roundFunc(transformation[4]),
-                self.roundFunc(transformation[5]),
-            ),
-            **kwargs,
-        )
diff --git a/Lib/fontTools/pens/statisticsPen.py b/Lib/fontTools/pens/statisticsPen.py
index abd6ff5..7c2e85c 100644
--- a/Lib/fontTools/pens/statisticsPen.py
+++ b/Lib/fontTools/pens/statisticsPen.py
@@ -1,5 +1,7 @@
 """Pen calculating area, center of mass, variance and standard-deviation,
 covariance and correlation, and slant, of glyph shapes."""
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 import math
 from fontTools.pens.momentsPen import MomentsPen
 
diff --git a/Lib/fontTools/pens/svgPathPen.py b/Lib/fontTools/pens/svgPathPen.py
index 4352ba4..17e4ccc 100644
--- a/Lib/fontTools/pens/svgPathPen.py
+++ b/Lib/fontTools/pens/svgPathPen.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.pens.basePen import BasePen
 
 
diff --git a/Lib/fontTools/pens/t2CharStringPen.py b/Lib/fontTools/pens/t2CharStringPen.py
index 0fddec1..2025fd5 100644
--- a/Lib/fontTools/pens/t2CharStringPen.py
+++ b/Lib/fontTools/pens/t2CharStringPen.py
@@ -1,12 +1,38 @@
 # Copyright (c) 2009 Type Supply LLC
 # Author: Tal Leming
 
-from fontTools.misc.roundTools import otRound, roundFunc
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools.misc.fixedTools import otRound
 from fontTools.misc.psCharStrings import T2CharString
 from fontTools.pens.basePen import BasePen
 from fontTools.cffLib.specializer import specializeCommands, commandsToProgram
 
 
+def t2c_round(number, tolerance=0.5):
+    if tolerance == 0:
+        return number  # no-op
+    rounded = otRound(number)
+    # return rounded integer if the tolerance >= 0.5, or if the absolute
+    # difference between the original float and the rounded integer is
+    # within the tolerance
+    if tolerance >= .5 or abs(rounded - number) <= tolerance:
+        return rounded
+    else:
+        # else return the value un-rounded
+        return number
+
+def makeRoundFunc(tolerance):
+    if tolerance < 0:
+        raise ValueError("Rounding tolerance must be positive")
+
+    def roundPoint(point):
+        x, y = point
+        return t2c_round(x, tolerance), t2c_round(y, tolerance)
+
+    return roundPoint
+
+
 class T2CharStringPen(BasePen):
     """Pen to draw Type 2 CharStrings.
 
@@ -20,7 +46,7 @@
 
     def __init__(self, width, glyphSet, roundTolerance=0.5, CFF2=False):
         super(T2CharStringPen, self).__init__(glyphSet)
-        self.round = roundFunc(roundTolerance)
+        self.roundPoint = makeRoundFunc(roundTolerance)
         self._CFF2 = CFF2
         self._width = width
         self._commands = []
@@ -28,7 +54,7 @@
 
     def _p(self, pt):
         p0 = self._p0
-        pt = self._p0 = (self.round(pt[0]), self.round(pt[1]))
+        pt = self._p0 = self.roundPoint(pt)
         return [pt[0]-p0[0], pt[1]-p0[1]]
 
     def _moveTo(self, pt):
diff --git a/Lib/fontTools/pens/teePen.py b/Lib/fontTools/pens/teePen.py
index 2f30e92..ce22c85 100644
--- a/Lib/fontTools/pens/teePen.py
+++ b/Lib/fontTools/pens/teePen.py
@@ -1,4 +1,6 @@
 """Pen multiplexing drawing to one or more pens."""
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.pens.basePen import AbstractPen
 
 
diff --git a/Lib/fontTools/pens/transformPen.py b/Lib/fontTools/pens/transformPen.py
index 2dcf83b..8f4fcd0 100644
--- a/Lib/fontTools/pens/transformPen.py
+++ b/Lib/fontTools/pens/transformPen.py
@@ -1,4 +1,6 @@
-from fontTools.pens.filterPen import FilterPen, FilterPointPen
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools.pens.filterPen import FilterPen
 
 
 __all__ = ["TransformPen"]
@@ -54,51 +56,6 @@
 		self._outPen.addComponent(glyphName, transformation)
 
 
-class TransformPointPen(FilterPointPen):
-	"""PointPen that transforms all coordinates using a Affine transformation,
-	and passes them to another PointPen.
-
-	>>> from fontTools.pens.recordingPen import RecordingPointPen
-	>>> rec = RecordingPointPen()
-	>>> pen = TransformPointPen(rec, (2, 0, 0, 2, -10, 5))
-	>>> v = iter(rec.value)
-	>>> pen.beginPath(identifier="contour-0")
-	>>> next(v)
-	('beginPath', (), {'identifier': 'contour-0'})
-	>>> pen.addPoint((100, 100), "line")
-	>>> next(v)
-	('addPoint', ((190, 205), 'line', False, None), {})
-	>>> pen.endPath()
-	>>> next(v)
-	('endPath', (), {})
-	>>> pen.addComponent("a", (1, 0, 0, 1, -10, 5), identifier="component-0")
-	>>> next(v)
-	('addComponent', ('a', <Transform [2 0 0 2 -30 15]>), {'identifier': 'component-0'})
-	"""
-
-	def __init__(self, outPointPen, transformation):
-		"""The 'outPointPen' argument is another point pen object.
-		It will receive the transformed coordinates.
-		The 'transformation' argument can either be a six-tuple, or a
-		fontTools.misc.transform.Transform object.
-		"""
-		super().__init__(outPointPen)
-		if not hasattr(transformation, "transformPoint"):
-			from fontTools.misc.transform import Transform
-			transformation = Transform(*transformation)
-		self._transformation = transformation
-		self._transformPoint = transformation.transformPoint
-
-	def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs):
-		self._outPen.addPoint(
-			self._transformPoint(pt), segmentType, smooth, name, **kwargs
-		)
-
-	def addComponent(self, baseGlyphName, transformation, **kwargs):
-		transformation = self._transformation.transform(transformation)
-		self._outPen.addComponent(baseGlyphName, transformation, **kwargs)
-
-
 if __name__ == "__main__":
 	from fontTools.pens.basePen import _TestPen
 	pen = TransformPen(_TestPen(None), (2, 0, 0.5, 2, -10, 0))
diff --git a/Lib/fontTools/pens/ttGlyphPen.py b/Lib/fontTools/pens/ttGlyphPen.py
index e7841ef..6e2f0d3 100644
--- a/Lib/fontTools/pens/ttGlyphPen.py
+++ b/Lib/fontTools/pens/ttGlyphPen.py
@@ -1,6 +1,6 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from array import array
-from fontTools.misc.fixedTools import MAX_F2DOT14, otRound, floatToFixedToFloat
-from fontTools.misc.roundTools import otRound
 from fontTools.pens.basePen import LoggingPen
 from fontTools.pens.transformPen import TransformPen
 from fontTools.ttLib.tables import ttProgram
@@ -12,37 +12,30 @@
 __all__ = ["TTGlyphPen"]
 
 
+# the max value that can still fit in an F2Dot14:
+# 1.99993896484375
+MAX_F2DOT14 = 0x7FFF / (1 << 14)
+
+
 class TTGlyphPen(LoggingPen):
     """Pen used for drawing to a TrueType glyph.
 
-    This pen can be used to construct or modify glyphs in a TrueType format
-    font. After using the pen to draw, use the ``.glyph()`` method to retrieve
-    a :py:class:`~._g_l_y_f.Glyph` object representing the glyph.
+    If `handleOverflowingTransforms` is True, the components' transform values
+    are checked that they don't overflow the limits of a F2Dot14 number:
+    -2.0 <= v < +2.0. If any transform value exceeds these, the composite
+    glyph is decomposed.
+    An exception to this rule is done for values that are very close to +2.0
+    (both for consistency with the -2.0 case, and for the relative frequency
+    these occur in real fonts). When almost +2.0 values occur (and all other
+    values are within the range -2.0 <= x <= +2.0), they are clamped to the
+    maximum positive value that can still be encoded as an F2Dot14: i.e.
+    1.99993896484375.
+    If False, no check is done and all components are translated unmodified
+    into the glyf table, followed by an inevitable `struct.error` once an
+    attempt is made to compile them.
     """
 
     def __init__(self, glyphSet, handleOverflowingTransforms=True):
-        """Construct a new pen.
-
-        Args:
-            glyphSet (ttLib._TTGlyphSet): A glyphset object, used to resolve components.
-            handleOverflowingTransforms (bool): See below.
-
-        If ``handleOverflowingTransforms`` is True, the components' transform values
-        are checked that they don't overflow the limits of a F2Dot14 number:
-        -2.0 <= v < +2.0. If any transform value exceeds these, the composite
-        glyph is decomposed.
-
-        An exception to this rule is done for values that are very close to +2.0
-        (both for consistency with the -2.0 case, and for the relative frequency
-        these occur in real fonts). When almost +2.0 values occur (and all other
-        values are within the range -2.0 <= x <= +2.0), they are clamped to the
-        maximum positive value that can still be encoded as an F2Dot14: i.e.
-        1.99993896484375.
-
-        If False, no check is done and all components are translated unmodified
-        into the glyf table, followed by an inevitable ``struct.error`` once an
-        attempt is made to compile them.
-        """
         self.glyphSet = glyphSet
         self.handleOverflowingTransforms = handleOverflowingTransforms
         self.init()
@@ -73,9 +66,6 @@
         assert self._isClosed(), '"move"-type point must begin a new contour.'
         self._addPoint(pt, 1)
 
-    def curveTo(self, *points):
-        raise NotImplementedError
-
     def qCurveTo(self, *points):
         assert len(points) >= 1
         for pt in points[:-1]:
@@ -133,12 +123,8 @@
 
             component = GlyphComponent()
             component.glyphName = glyphName
-            component.x, component.y = (otRound(v) for v in transformation[4:])
-            # quantize floats to F2Dot14 so we get same values as when decompiled
-            # from a binary glyf table
-            transformation = tuple(
-                floatToFixedToFloat(v, 14) for v in transformation[:4]
-            )
+            component.x, component.y = transformation[4:]
+            transformation = transformation[:4]
             if transformation != (1, 0, 0, 1):
                 if (self.handleOverflowingTransforms and
                         any(MAX_F2DOT14 < s <= 2 for s in transformation)):
@@ -151,14 +137,12 @@
         return components
 
     def glyph(self, componentFlags=0x4):
-        """Returns a :py:class:`~._g_l_y_f.Glyph` object representing the glyph."""
         assert self._isClosed(), "Didn't close last contour."
 
         components = self._buildComponents(componentFlags)
 
         glyph = Glyph()
         glyph.coordinates = GlyphCoordinates(self.points)
-        glyph.coordinates.toInt()
         glyph.endPtsOfContours = self.endPts
         glyph.flags = array("B", self.types)
         self.init()
diff --git a/Lib/fontTools/pens/wxPen.py b/Lib/fontTools/pens/wxPen.py
index 1504f08..8e0e463 100644
--- a/Lib/fontTools/pens/wxPen.py
+++ b/Lib/fontTools/pens/wxPen.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.pens.basePen import BasePen
 
 
diff --git a/Lib/fontTools/subset/__init__.py b/Lib/fontTools/subset/__init__.py
index f687b05..aee8a0f 100644
--- a/Lib/fontTools/subset/__init__.py
+++ b/Lib/fontTools/subset/__init__.py
@@ -2,18 +2,21 @@
 #
 # Google Author(s): Behdad Esfahbod
 
-from fontTools.misc.roundTools import otRound
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools.misc.fixedTools import otRound
 from fontTools import ttLib
 from fontTools.ttLib.tables import otTables
 from fontTools.otlLib.maxContextCalc import maxCtxFont
 from fontTools.pens.basePen import NullPen
 from fontTools.misc.loggingTools import Timer
 from fontTools.subset.cff import *
+from fontTools.varLib import varStore
 import sys
 import struct
 import array
 import logging
-from collections import Counter, defaultdict
+from collections import Counter
 from types import MethodType
 
 __usage__ = "pyftsubset font-file [glyph...] [--option=value]..."
@@ -174,9 +177,8 @@
             * Keep default set of features plus 'aalt', but drop 'vrt2'.
   --layout-scripts[+|-]=<script>[,<script>...]
       Specify (=), add to (+=) or exclude from (-=) the comma-separated
-      set of OpenType layout script tags that will be preserved. LangSys tags
-      can be appended to script tag, separated by '.', for example:
-      'arab.dflt,arab.URD,latn.TRK'. By default all scripts are retained ('*').
+      set of OpenType layout script tags that will be preserved.  By
+      default all scripts are retained ('*').
 
 Hinting options:
   --hinting
@@ -427,14 +429,13 @@
 		     if v == klass and g in glyphs)
 
 @_add_method(otTables.ClassDef)
-def subset(self, glyphs, remap=False, useClass0=True):
+def subset(self, glyphs, remap=False):
 	"""Returns ascending list of remaining classes."""
 	self.classDefs = {g:v for g,v in self.classDefs.items() if g in glyphs}
 	# Note: while class 0 has the special meaning of "not matched",
 	# if no glyph will ever /not match/, we can optimize class 0 out too.
-	# Only do this if allowed.
 	indices = _uniq_sort(
-		 ([0] if ((not useClass0) or any(g not in self.classDefs for g in glyphs)) else []) +
+		 ([0] if any(g not in self.classDefs for g in glyphs) else []) +
 			list(self.classDefs.values()))
 	if remap:
 		self.remap(indices)
@@ -546,11 +547,6 @@
 	if not options.hinting:
 		# Drop device tables
 		self.ValueFormat &= ~0x00F0
-	# Downgrade to Format 1 if all ValueRecords are the same
-	if self.Format == 2 and all(v == self.Value[0] for v in self.Value):
-		self.Format = 1
-		self.Value = self.Value[0] if self.ValueFormat != 0 else None
-		del self.ValueCount
 	return True
 
 @_add_method(otTables.PairPos)
@@ -570,16 +566,15 @@
 		self.PairSetCount = len(self.PairSet)
 		return bool(self.PairSetCount)
 	elif self.Format == 2:
-		class1_map = [c for c in self.ClassDef1.subset(s.glyphs.intersection(self.Coverage.glyphs), remap=True) if c < self.Class1Count]
-		class2_map = [c for c in self.ClassDef2.subset(s.glyphs, remap=True, useClass0=False) if c < self.Class2Count]
+		class1_map = [c for c in self.ClassDef1.subset(s.glyphs, remap=True) if c < self.Class1Count]
+		class2_map = [c for c in self.ClassDef2.subset(s.glyphs, remap=True) if c < self.Class2Count]
 		self.Class1Record = [self.Class1Record[i] for i in class1_map]
 		for c in self.Class1Record:
 			c.Class2Record = [c.Class2Record[i] for i in class2_map]
 		self.Class1Count = len(class1_map)
 		self.Class2Count = len(class2_map)
-		# If only Class2 0 left, no need to keep anything.
 		return bool(self.Class1Count and
-					(self.Class2Count > 1) and
+					self.Class2Count and
 					self.Coverage.subset(s.glyphs))
 	else:
 		assert 0, "unknown format: %s" % self.Format
@@ -895,17 +890,15 @@
 				self.ClassDef = 'InputClassDef' if Chain else 'ClassDef'
 				self.ClassDefIndex = 1 if Chain else 0
 				self.Input = 'Input' if Chain else 'Class'
-			elif Format == 3:
-				self.Input = 'InputCoverage' if Chain else 'Coverage'
 
 	if self.Format not in [1, 2, 3]:
 		return None	# Don't shoot the messenger; let it go
-	if not hasattr(self.__class__, "_subset__ContextHelpers"):
-		self.__class__._subset__ContextHelpers = {}
-	if self.Format not in self.__class__._subset__ContextHelpers:
+	if not hasattr(self.__class__, "__ContextHelpers"):
+		self.__class__.__ContextHelpers = {}
+	if self.Format not in self.__class__.__ContextHelpers:
 		helper = ContextHelper(self.__class__, self.Format)
-		self.__class__._subset__ContextHelpers[self.Format] = helper
-	return self.__class__._subset__ContextHelpers[self.Format]
+		self.__class__.__ContextHelpers[self.Format] = helper
+	return self.__class__.__ContextHelpers[self.Format]
 
 @_add_method(otTables.ContextSubst,
 			 otTables.ChainContextSubst)
@@ -979,7 +972,6 @@
 		if not all(x.intersect(s.glyphs) for x in c.RuleData(self)):
 			return []
 		r = self
-		input_coverages = getattr(r, c.Input)
 		chaos = set()
 		for ll in getattr(r, c.LookupRecord):
 			if not ll: continue
@@ -991,11 +983,11 @@
 				if seqi == 0:
 					pos_glyphs = frozenset(cur_glyphs)
 				else:
-					pos_glyphs = frozenset(input_coverages[seqi].intersect_glyphs(s.glyphs))
+					pos_glyphs = frozenset(r.InputCoverage[seqi].intersect_glyphs(s.glyphs))
 			lookup = s.table.LookupList.Lookup[ll.LookupListIndex]
 			chaos.add(seqi)
 			if lookup.may_have_non_1to1():
-				chaos.update(range(seqi, len(input_coverages)+1))
+				chaos.update(range(seqi, len(r.InputCoverage)+1))
 			lookup.closure_glyphs(s, cur_glyphs=pos_glyphs)
 	else:
 		assert 0, "unknown format: %s" % self.Format
@@ -1316,23 +1308,14 @@
 	self.ensureDecompiled()
 	self.SubstitutionRecord = [r for r in self.SubstitutionRecord
 				     if r.FeatureIndex in feature_indices]
-	# remap feature indices
-	for r in self.SubstitutionRecord:
-		r.FeatureIndex = feature_indices.index(r.FeatureIndex)
 	self.SubstitutionCount = len(self.SubstitutionRecord)
 	return bool(self.SubstitutionCount)
 
 @_add_method(otTables.FeatureVariations)
 def subset_features(self, feature_indices):
 	self.ensureDecompiled()
-	for r in self.FeatureVariationRecord:
-		r.FeatureTableSubstitution.subset_features(feature_indices)
-	# Prune empty records at the end only
-	# https://github.com/fonttools/fonttools/issues/1881
-	while (self.FeatureVariationRecord and
-		not self.FeatureVariationRecord[-1]
-			.FeatureTableSubstitution.SubstitutionCount):
-		self.FeatureVariationRecord.pop()
+	self.FeaturVariationRecord = [r for r in self.FeatureVariationRecord
+					if r.FeatureTableSubstitution.subset_features(feature_indices)]
 	self.FeatureVariationCount = len(self.FeatureVariationRecord)
 	return bool(self.FeatureVariationCount)
 
@@ -1404,14 +1387,9 @@
 # CBDT will inherit it
 @_add_method(ttLib.getTableClass('EBDT'))
 def subset_glyphs(self, s):
-	strikeData = [
-		{g: strike[g] for g in s.glyphs if g in strike}
-		for strike in self.strikeData
-	]
-	# Prune empty strikes
-	# https://github.com/fonttools/fonttools/issues/1633
-	self.strikeData = [strike for strike in strikeData if strike]
-	return True
+  self.strikeData = [{g: strike[g] for g in s.glyphs if g in strike}
+					 for strike in self.strikeData]
+  return True
 
 @_add_method(ttLib.getTableClass('sbix'))
 def subset_glyphs(self, s):
@@ -1534,29 +1512,13 @@
 
 @_add_method(ttLib.getTableClass('GSUB'),
 	     ttLib.getTableClass('GPOS'))
-def subset_script_tags(self, tags):
-	langsys = {}
-	script_tags = set()
-	for tag in tags:
-		script_tag, lang_tag = tag.split(".") if "." in tag else (tag, '*')
-		script_tags.add(script_tag.ljust(4))
-		langsys.setdefault(script_tag, set()).add(lang_tag.ljust(4))
-
+def subset_script_tags(self, script_tags):
 	if self.table.ScriptList:
 		self.table.ScriptList.ScriptRecord = \
 			[s for s in self.table.ScriptList.ScriptRecord
 			 if s.ScriptTag in script_tags]
 		self.table.ScriptList.ScriptCount = len(self.table.ScriptList.ScriptRecord)
 
-		for record in self.table.ScriptList.ScriptRecord:
-			if record.ScriptTag in langsys and '*   ' not in langsys[record.ScriptTag]:
-				record.Script.LangSysRecord = \
-					[l for l in record.Script.LangSysRecord
-					 if l.LangSysTag in langsys[record.ScriptTag]]
-				record.Script.LangSysCount = len(record.Script.LangSysRecord)
-				if "dflt" not in langsys[record.ScriptTag]:
-					record.Script.DefaultLangSys = None
-
 @_add_method(ttLib.getTableClass('GSUB'),
 			 ttLib.getTableClass('GPOS'))
 def prune_features(self):
@@ -1651,15 +1613,11 @@
 	#if table.ScriptList and not table.ScriptList.ScriptRecord:
 	#	table.ScriptList = None
 
-	if hasattr(table, 'FeatureVariations'):
-		# drop FeatureVariations if there are no features to substitute
-		if table.FeatureVariations and not (
-			table.FeatureList and table.FeatureVariations.FeatureVariationRecord
-		):
-			table.FeatureVariations = None
+	if not table.FeatureList and hasattr(table, 'FeatureVariations'):
+		table.FeatureVariations = None
 
-		# downgrade table version if there are no FeatureVariations
-		if not table.FeatureVariations and table.Version == 0x00010001:
+	if hasattr(table, 'FeatureVariations') and not table.FeatureVariations:
+		if table.Version == 0x00010001:
 			table.Version = 0x00010000
 
 	return True
@@ -1878,7 +1836,7 @@
 		table.RsbMap.mapping = _dict_subset(table.RsbMap.mapping, s.glyphs)
 		used.update(table.RsbMap.mapping.values())
 
-	varidx_map = table.VarStore.subset_varidxes(used, retainFirstMap=retainAdvMap, advIdxes=advIdxes_)
+	varidx_map = varStore.VarStore_subset_varidxes(table.VarStore, used, retainFirstMap=retainAdvMap, advIdxes=advIdxes_)
 
 	if table.AdvWidthMap:
 		table.AdvWidthMap.mapping = _remap_index_map(s, varidx_map, table.AdvWidthMap)
@@ -1916,7 +1874,7 @@
 		table.VOrgMap.mapping = _dict_subset(table.VOrgMap.mapping, s.glyphs)
 		used.update(table.VOrgMap.mapping.values())
 
-	varidx_map = table.VarStore.subset_varidxes(used, retainFirstMap=retainAdvMap, advIdxes=advIdxes_)
+	varidx_map = varStore.VarStore_subset_varidxes(table.VarStore, used, retainFirstMap=retainAdvMap, advIdxes=advIdxes_)
 
 	if table.AdvHeightMap:
 		table.AdvHeightMap.mapping = _remap_index_map(s, varidx_map, table.AdvHeightMap)
@@ -1984,130 +1942,27 @@
 	else:
 		assert False, "unknown 'prop' format %s" % prop.Format
 
-def _paint_glyph_names(paint, colr):
-	result = set()
-
-	def callback(paint):
-		if paint.Format in {
-			otTables.PaintFormat.PaintGlyph,
-			otTables.PaintFormat.PaintColrGlyph,
-		}:
-			result.add(paint.Glyph)
-
-	paint.traverse(colr, callback)
-	return result
-
 @_add_method(ttLib.getTableClass('COLR'))
 def closure_glyphs(self, s):
-	if self.version > 0:
-		# on decompiling COLRv1, we only keep around the raw otTables
-		# but for subsetting we need dicts with fully decompiled layers;
-		# we store them temporarily in the C_O_L_R_ instance and delete
-		# them after we have finished subsetting.
-		self.ColorLayers = self._decompileColorLayersV0(self.table)
-		self.ColorLayersV1 = {
-			rec.BaseGlyph: rec.Paint
-			for rec in self.table.BaseGlyphV1List.BaseGlyphV1Record
-		}
-
 	decompose = s.glyphs
 	while decompose:
 		layers = set()
 		for g in decompose:
-			for layer in self.ColorLayers.get(g, []):
-				layers.add(layer.name)
-
-			if self.version > 0:
-				paint = self.ColorLayersV1.get(g)
-				if paint is not None:
-					layers.update(_paint_glyph_names(paint, self.table))
-
+			for l in self.ColorLayers.get(g, []):
+				layers.add(l.name)
 		layers -= s.glyphs
 		s.glyphs.update(layers)
 		decompose = layers
 
 @_add_method(ttLib.getTableClass('COLR'))
 def subset_glyphs(self, s):
-	from fontTools.colorLib.unbuilder import unbuildColrV1
-	from fontTools.colorLib.builder import buildColrV1, populateCOLRv0
-
 	self.ColorLayers = {g: self.ColorLayers[g] for g in s.glyphs if g in self.ColorLayers}
-	if self.version == 0:
-		return bool(self.ColorLayers)
+	return bool(self.ColorLayers)
 
-	colorGlyphsV1 = unbuildColrV1(self.table.LayerV1List, self.table.BaseGlyphV1List)
-	self.table.LayerV1List, self.table.BaseGlyphV1List = buildColrV1(
-		{g: colorGlyphsV1[g] for g in colorGlyphsV1 if g in s.glyphs}
-	)
-	del self.ColorLayersV1
-
-	layersV0 = self.ColorLayers
-	if not self.table.BaseGlyphV1List.BaseGlyphV1Record:
-		# no more COLRv1 glyphs: downgrade to version 0
-		self.version = 0
-		del self.table
-		return bool(layersV0)
-
-	if layersV0:
-		populateCOLRv0(
-			self.table,
-			{
-				g: [(layer.name, layer.colorID) for layer in layersV0[g]]
-				for g in layersV0
-			},
-		)
-	del self.ColorLayers
-
-	# TODO: also prune ununsed varIndices in COLR.VarStore
-	return True
-
+# TODO: prune unused palettes
 @_add_method(ttLib.getTableClass('CPAL'))
 def prune_post_subset(self, font, options):
-	colr = font.get("COLR")
-	if not colr:  # drop CPAL if COLR was subsetted to empty
-		return False
-
-	colors_by_index = defaultdict(list)
-
-	def collect_colors_by_index(paint):
-		if hasattr(paint, "Color"):  # either solid colors...
-			colors_by_index[paint.Color.PaletteIndex].append(paint.Color)
-		elif hasattr(paint, "ColorLine"):  # ... or gradient color stops
-			for stop in paint.ColorLine.ColorStop:
-				colors_by_index[stop.Color.PaletteIndex].append(stop.Color)
-
-	if colr.version == 0:
-		for layers in colr.ColorLayers.values():
-			for layer in layers:
-				colors_by_index[layer.colorID].append(layer)
-	else:
-		if colr.table.LayerRecordArray:
-			for layer in colr.table.LayerRecordArray.LayerRecord:
-				colors_by_index[layer.PaletteIndex].append(layer)
-		for record in colr.table.BaseGlyphV1List.BaseGlyphV1Record:
-			record.Paint.traverse(colr.table, collect_colors_by_index)
-
-	retained_palette_indices = set(colors_by_index.keys())
-	for palette in self.palettes:
-		palette[:] = [c for i, c in enumerate(palette) if i in retained_palette_indices]
-		assert len(palette) == len(retained_palette_indices)
-
-	for new_index, old_index in enumerate(sorted(retained_palette_indices)):
-		for record in colors_by_index[old_index]:
-			if hasattr(record, "colorID"):  # v0
-				record.colorID = new_index
-			elif hasattr(record, "PaletteIndex"):  # v1
-				record.PaletteIndex = new_index
-			else:
-				raise AssertionError(record)
-
-	self.numPaletteEntries = len(self.palettes[0])
-
-	if self.version == 1:
-		self.paletteEntryLabels = [
-			label for i, label in self.paletteEntryLabels if i in retained_palette_indices
-		]
-	return bool(self.numPaletteEntries)
+	return True
 
 @_add_method(otTables.MathGlyphConstruction)
 def closure_glyphs(self, glyphs):
@@ -2221,7 +2076,7 @@
 		elif flags & 0x0080: i += 8	# WE_HAVE_A_TWO_BY_TWO
 		more = flags & 0x0020	# MORE_COMPONENTS
 
-	self.data = data.tobytes()
+	self.data = data.tostring()
 
 @_add_method(ttLib.getTableClass('glyf'))
 def closure_glyphs(self, s):
@@ -2311,17 +2166,7 @@
 @_add_method(ttLib.getTableClass('cmap'))
 def subset_glyphs(self, s):
 	s.glyphs = None # We use s.glyphs_requested and s.unicodes_requested only
-
-	tables_format12_bmp = []
-	table_plat0_enc3 = {}  # Unicode platform, Unicode BMP only, keyed by language
-	table_plat3_enc1 = {}  # Windows platform, Unicode BMP, keyed by language
-
 	for t in self.tables:
-		if t.platformID == 0 and t.platEncID == 3:
-			table_plat0_enc3[t.language] = t
-		if t.platformID == 3 and t.platEncID == 1:
-			table_plat3_enc1[t.language] = t
-
 		if t.format == 14:
 			# TODO(behdad) We drop all the default-UVS mappings
 			# for glyphs_requested.  So it's the caller's responsibility to make
@@ -2333,38 +2178,16 @@
 		elif t.isUnicode():
 			t.cmap = {u:g for u,g in t.cmap.items()
 				      if g in s.glyphs_requested or u in s.unicodes_requested}
-			# Collect format 12 tables that hold only basic multilingual plane
-			# codepoints.
-			if t.format == 12 and t.cmap and max(t.cmap.keys()) < 0x10000:
-				tables_format12_bmp.append(t)
 		else:
 			t.cmap = {u:g for u,g in t.cmap.items()
 				      if g in s.glyphs_requested}
-
-	# Fomat 12 tables are redundant if they contain just the same BMP codepoints
-	# their little BMP-only encoding siblings contain.
-	for t in tables_format12_bmp:
-		if (
-			t.platformID == 0  # Unicode platform
-			and t.platEncID == 4  # Unicode full repertoire
-			and t.language in table_plat0_enc3  # Have a BMP-only sibling?
-			and table_plat0_enc3[t.language].cmap == t.cmap
-		):
-			t.cmap.clear()
-		elif (
-			t.platformID == 3  # Windows platform
-			and t.platEncID == 10  # Unicode full repertoire
-			and t.language in table_plat3_enc1  # Have a BMP-only sibling?
-			and table_plat3_enc1[t.language].cmap == t.cmap
-		):
-			t.cmap.clear()
-
 	self.tables = [t for t in self.tables
 			 if (t.cmap if t.format != 14 else t.uvsDict)]
 	self.numSubTables = len(self.tables)
 	# TODO(behdad) Convert formats when needed.
 	# In particular, if we have a format=12 without non-BMP
-	# characters, convert it to format=4 if there's not one.
+	# characters, either drop format=12 one or convert it
+	# to format=4 if there's not one.
 	return True # Required table
 
 @_add_method(ttLib.getTableClass('DSIG'))
@@ -2864,7 +2687,7 @@
 def load_font(fontFile,
 	      options,
 	      allowVID=False,
-	      checkChecksums=0,
+	      checkChecksums=False,
 	      dontLoadGlyphNames=False,
 	      lazy=True):
 
@@ -2937,7 +2760,6 @@
 
 @timer("make one with everything (TOTAL TIME)")
 def main(args=None):
-	"""OpenType font subsetter and optimizer"""
 	from os.path import splitext
 	from fontTools import configLogger
 
diff --git a/Lib/fontTools/subset/__main__.py b/Lib/fontTools/subset/__main__.py
index 2203847..10e470f 100644
--- a/Lib/fontTools/subset/__main__.py
+++ b/Lib/fontTools/subset/__main__.py
@@ -1,6 +1,7 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 import sys
 from fontTools.subset import main
 
-
 if __name__ == '__main__':
     sys.exit(main())
diff --git a/Lib/fontTools/subset/cff.py b/Lib/fontTools/subset/cff.py
index b59c6b9..7db6d88 100644
--- a/Lib/fontTools/subset/cff.py
+++ b/Lib/fontTools/subset/cff.py
@@ -1,7 +1,7 @@
 from fontTools.misc import psCharStrings
 from fontTools import ttLib
 from fontTools.pens.basePen import NullPen
-from fontTools.misc.roundTools import otRound
+from fontTools.misc.fixedTools import otRound
 from fontTools.varLib.varStore import VarStoreInstancer
 
 def _add_method(*clazzes):
diff --git a/Lib/fontTools/svgLib/__init__.py b/Lib/fontTools/svgLib/__init__.py
index c049006..b301a3b 100644
--- a/Lib/fontTools/svgLib/__init__.py
+++ b/Lib/fontTools/svgLib/__init__.py
@@ -1,3 +1,6 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+
 from .path import SVGPath, parse_path
 
 __all__ = ["SVGPath", "parse_path"]
diff --git a/Lib/fontTools/svgLib/path/__init__.py b/Lib/fontTools/svgLib/path/__init__.py
index 9440429..5dd3329 100644
--- a/Lib/fontTools/svgLib/path/__init__.py
+++ b/Lib/fontTools/svgLib/path/__init__.py
@@ -1,4 +1,6 @@
-from fontTools.misc.py23 import tostr
+from __future__ import (
+    print_function, division, absolute_import, unicode_literals)
+from fontTools.misc.py23 import *
 
 from fontTools.pens.transformPen import TransformPen
 from fontTools.misc import etree
diff --git a/Lib/fontTools/svgLib/path/arc.py b/Lib/fontTools/svgLib/path/arc.py
index 3181071..38d1ea9 100644
--- a/Lib/fontTools/svgLib/path/arc.py
+++ b/Lib/fontTools/svgLib/path/arc.py
@@ -4,8 +4,11 @@
 https://github.com/chromium/chromium/blob/93831f2/third_party/
 blink/renderer/core/svg/svg_path_parser.cc#L169-L278
 """
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
+from fontTools.misc.py23 import isfinite
 from fontTools.misc.transform import Identity, Scale
-from math import atan2, ceil, cos, fabs, isfinite, pi, radians, sin, sqrt, tan
+from math import atan2, ceil, cos, fabs, pi, radians, sin, sqrt, tan
 
 
 TWO_PI = 2 * pi
diff --git a/Lib/fontTools/svgLib/path/parser.py b/Lib/fontTools/svgLib/path/parser.py
index 1fcf899..bdf3de0 100644
--- a/Lib/fontTools/svgLib/path/parser.py
+++ b/Lib/fontTools/svgLib/path/parser.py
@@ -7,86 +7,26 @@
 # Copyright (c) 2013-2014 Lennart Regebro
 # License: MIT
 
+from __future__ import (
+    print_function, division, absolute_import, unicode_literals)
+from fontTools.misc.py23 import *
 from .arc import EllipticalArc
 import re
 
 
 COMMANDS = set('MmZzLlHhVvCcSsQqTtAa')
-ARC_COMMANDS = set("Aa")
 UPPERCASE = set('MZLHVCSQTA')
 
 COMMAND_RE = re.compile("([MmZzLlHhVvCcSsQqTtAa])")
-FLOAT_RE = re.compile(
-    r"[-+]?"  # optional sign
-    r"(?:"
-    r"(?:0|[1-9][0-9]*)(?:\.[0-9]+(?:[eE][-+]?[0-9]+)?)?"  # int/float
-    r"|"
-    r"(?:\.[0-9]+(?:[eE][-+]?[0-9]+)?)"  # float with leading dot (e.g. '.42')
-    r")"
-)
-BOOL_RE = re.compile("^[01]")
-SEPARATOR_RE = re.compile(f"[, \t]")
+FLOAT_RE = re.compile(r"[-+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?")
 
 
 def _tokenize_path(pathdef):
-    arc_cmd = None
     for x in COMMAND_RE.split(pathdef):
         if x in COMMANDS:
-            arc_cmd = x if x in ARC_COMMANDS else None
             yield x
-            continue
-
-        if arc_cmd:
-            try:
-                yield from _tokenize_arc_arguments(x)
-            except ValueError as e:
-                raise ValueError(f"Invalid arc command: '{arc_cmd}{x}'") from e
-        else:
-            for token in FLOAT_RE.findall(x):
-                yield token
-
-
-ARC_ARGUMENT_TYPES = (
-    ("rx", FLOAT_RE),
-    ("ry", FLOAT_RE),
-    ("x-axis-rotation", FLOAT_RE),
-    ("large-arc-flag", BOOL_RE),
-    ("sweep-flag", BOOL_RE),
-    ("x", FLOAT_RE),
-    ("y", FLOAT_RE),
-)
-
-
-def _tokenize_arc_arguments(arcdef):
-    raw_args = [s for s in SEPARATOR_RE.split(arcdef) if s]
-    if not raw_args:
-        raise ValueError(f"Not enough arguments: '{arcdef}'")
-    raw_args.reverse()
-
-    i = 0
-    while raw_args:
-        arg = raw_args.pop()
-
-        name, pattern = ARC_ARGUMENT_TYPES[i]
-        match = pattern.search(arg)
-        if not match:
-            raise ValueError(f"Invalid argument for '{name}' parameter: {arg!r}")
-
-        j, k = match.span()
-        yield arg[j:k]
-        arg = arg[k:]
-
-        if arg:
-            raw_args.append(arg)
-
-        # wrap around every 7 consecutive arguments
-        if i == 6:
-            i = 0
-        else:
-            i += 1
-
-    if i != 0:
-        raise ValueError(f"Not enough arguments: '{arcdef}'")
+        for token in FLOAT_RE.findall(x):
+            yield token
 
 
 def parse_path(pathdef, pen, current_pos=(0, 0), arc_class=EllipticalArc):
diff --git a/Lib/fontTools/t1Lib/__init__.py b/Lib/fontTools/t1Lib/__init__.py
index e1d94d3..142cedd 100644
--- a/Lib/fontTools/t1Lib/__init__.py
+++ b/Lib/fontTools/t1Lib/__init__.py
@@ -15,7 +15,8 @@
 	part should be written as hexadecimal or binary, but only if kind
 	is 'OTHER'.
 """
-from fontTools.misc.py23 import bytechr, byteord, bytesjoin
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import eexec
 from fontTools.misc.macCreatorType import getMacCreatorAndType
 import os
diff --git a/Lib/fontTools/ttLib/__init__.py b/Lib/fontTools/ttLib/__init__.py
index 16417e7..a3ab303 100644
--- a/Lib/fontTools/ttLib/__init__.py
+++ b/Lib/fontTools/ttLib/__init__.py
@@ -41,6 +41,8 @@
 
 """
 
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.loggingTools import deprecateFunction
 import logging
 
diff --git a/Lib/fontTools/ttLib/macUtils.py b/Lib/fontTools/ttLib/macUtils.py
index 496fb67..17dd5ef 100644
--- a/Lib/fontTools/ttLib/macUtils.py
+++ b/Lib/fontTools/ttLib/macUtils.py
@@ -1,5 +1,6 @@
 """ttLib.macUtils.py -- Various Mac-specific stuff."""
-from io import BytesIO
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.macRes import ResourceReader, ResourceError
 
 
@@ -40,7 +41,7 @@
 	def __init__(self, path, res_name_or_index):
 		from fontTools import ttLib
 		reader = ResourceReader(path)
-		if isinstance(res_name_or_index, str):
+		if isinstance(res_name_or_index, basestring):
 			rsrc = reader.getNamedResource('sfnt', res_name_or_index)
 		else:
 			rsrc = reader.getIndResource('sfnt', res_name_or_index)
diff --git a/Lib/fontTools/ttLib/removeOverlaps.py b/Lib/fontTools/ttLib/removeOverlaps.py
deleted file mode 100644
index fb5c77a..0000000
--- a/Lib/fontTools/ttLib/removeOverlaps.py
+++ /dev/null
@@ -1,192 +0,0 @@
-""" Simplify TrueType glyphs by merging overlapping contours/components.
-
-Requires https://github.com/fonttools/skia-pathops
-"""
-
-import itertools
-import logging
-from typing import Iterable, Optional, Mapping
-
-from fontTools.ttLib import ttFont
-from fontTools.ttLib.tables import _g_l_y_f
-from fontTools.ttLib.tables import _h_m_t_x
-from fontTools.pens.ttGlyphPen import TTGlyphPen
-
-import pathops
-
-
-__all__ = ["removeOverlaps"]
-
-
-log = logging.getLogger("fontTools.ttLib.removeOverlaps")
-
-_TTGlyphMapping = Mapping[str, ttFont._TTGlyph]
-
-
-def skPathFromGlyph(glyphName: str, glyphSet: _TTGlyphMapping) -> pathops.Path:
-    path = pathops.Path()
-    pathPen = path.getPen(glyphSet=glyphSet)
-    glyphSet[glyphName].draw(pathPen)
-    return path
-
-
-def skPathFromGlyphComponent(
-    component: _g_l_y_f.GlyphComponent, glyphSet: _TTGlyphMapping
-):
-    baseGlyphName, transformation = component.getComponentInfo()
-    path = skPathFromGlyph(baseGlyphName, glyphSet)
-    return path.transform(*transformation)
-
-
-def componentsOverlap(glyph: _g_l_y_f.Glyph, glyphSet: _TTGlyphMapping) -> bool:
-    if not glyph.isComposite():
-        raise ValueError("This method only works with TrueType composite glyphs")
-    if len(glyph.components) < 2:
-        return False  # single component, no overlaps
-
-    component_paths = {}
-
-    def _get_nth_component_path(index: int) -> pathops.Path:
-        if index not in component_paths:
-            component_paths[index] = skPathFromGlyphComponent(
-                glyph.components[index], glyphSet
-            )
-        return component_paths[index]
-
-    return any(
-        pathops.op(
-            _get_nth_component_path(i),
-            _get_nth_component_path(j),
-            pathops.PathOp.INTERSECTION,
-            fix_winding=False,
-            keep_starting_points=False,
-        )
-        for i, j in itertools.combinations(range(len(glyph.components)), 2)
-    )
-
-
-def ttfGlyphFromSkPath(path: pathops.Path) -> _g_l_y_f.Glyph:
-    # Skia paths have no 'components', no need for glyphSet
-    ttPen = TTGlyphPen(glyphSet=None)
-    path.draw(ttPen)
-    glyph = ttPen.glyph()
-    assert not glyph.isComposite()
-    # compute glyph.xMin (glyfTable parameter unused for non composites)
-    glyph.recalcBounds(glyfTable=None)
-    return glyph
-
-
-def removeTTGlyphOverlaps(
-    glyphName: str,
-    glyphSet: _TTGlyphMapping,
-    glyfTable: _g_l_y_f.table__g_l_y_f,
-    hmtxTable: _h_m_t_x.table__h_m_t_x,
-    removeHinting: bool = True,
-) -> bool:
-    glyph = glyfTable[glyphName]
-    # decompose composite glyphs only if components overlap each other
-    if (
-        glyph.numberOfContours > 0
-        or glyph.isComposite()
-        and componentsOverlap(glyph, glyphSet)
-    ):
-        path = skPathFromGlyph(glyphName, glyphSet)
-
-        # remove overlaps
-        path2 = pathops.simplify(path, clockwise=path.clockwise)
-
-        # replace TTGlyph if simplified path is different (ignoring contour order)
-        if {tuple(c) for c in path.contours} != {tuple(c) for c in path2.contours}:
-            glyfTable[glyphName] = glyph = ttfGlyphFromSkPath(path2)
-            # simplified glyph is always unhinted
-            assert not glyph.program
-            # also ensure hmtx LSB == glyph.xMin so glyph origin is at x=0
-            width, lsb = hmtxTable[glyphName]
-            if lsb != glyph.xMin:
-                hmtxTable[glyphName] = (width, glyph.xMin)
-            return True
-
-    if removeHinting:
-        glyph.removeHinting()
-    return False
-
-
-def removeOverlaps(
-    font: ttFont.TTFont,
-    glyphNames: Optional[Iterable[str]] = None,
-    removeHinting: bool = True,
-) -> None:
-    """Simplify glyphs in TTFont by merging overlapping contours.
-
-    Overlapping components are first decomposed to simple contours, then merged.
-
-    Currently this only works with TrueType fonts with 'glyf' table.
-    Raises NotImplementedError if 'glyf' table is absent.
-
-    Note that removing overlaps invalidates the hinting. By default we drop hinting
-    from all glyphs whether or not overlaps are removed from a given one, as it would
-    look weird if only some glyphs are left (un)hinted.
-
-    Args:
-        font: input TTFont object, modified in place.
-        glyphNames: optional iterable of glyph names (str) to remove overlaps from.
-            By default, all glyphs in the font are processed.
-        removeHinting (bool): set to False to keep hinting for unmodified glyphs.
-    """
-    try:
-        glyfTable = font["glyf"]
-    except KeyError:
-        raise NotImplementedError("removeOverlaps currently only works with TTFs")
-
-    hmtxTable = font["hmtx"]
-    # wraps the underlying glyf Glyphs, takes care of interfacing with drawing pens
-    glyphSet = font.getGlyphSet()
-
-    if glyphNames is None:
-        glyphNames = font.getGlyphOrder()
-
-    # process all simple glyphs first, then composites with increasing component depth,
-    # so that by the time we test for component intersections the respective base glyphs
-    # have already been simplified
-    glyphNames = sorted(
-        glyphNames,
-        key=lambda name: (
-            glyfTable[name].getCompositeMaxpValues(glyfTable).maxComponentDepth
-            if glyfTable[name].isComposite()
-            else 0,
-            name,
-        ),
-    )
-    modified = set()
-    for glyphName in glyphNames:
-        if removeTTGlyphOverlaps(
-            glyphName, glyphSet, glyfTable, hmtxTable, removeHinting
-        ):
-            modified.add(glyphName)
-
-    log.debug("Removed overlaps for %s glyphs:\n%s", len(modified), " ".join(modified))
-
-
-def main(args=None):
-    import sys
-
-    if args is None:
-        args = sys.argv[1:]
-
-    if len(args) < 2:
-        print(
-            f"usage: fonttools ttLib.removeOverlaps INPUT.ttf OUTPUT.ttf [GLYPHS ...]"
-        )
-        sys.exit(1)
-
-    src = args[0]
-    dst = args[1]
-    glyphNames = args[2:] or None
-
-    with ttFont.TTFont(src) as f:
-        removeOverlaps(f, glyphNames)
-        f.save(dst)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/Lib/fontTools/ttLib/sfnt.py b/Lib/fontTools/ttLib/sfnt.py
index d609dc5..1c11de7 100644
--- a/Lib/fontTools/ttLib/sfnt.py
+++ b/Lib/fontTools/ttLib/sfnt.py
@@ -12,9 +12,8 @@
 a table's length chages you need to rewrite the whole file anyway.
 """
 
-from io import BytesIO
-from types import SimpleNamespace
-from fontTools.misc.py23 import Tag
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from fontTools.ttLib import TTLibError
 import struct
@@ -43,7 +42,7 @@
 		# return default object
 		return object.__new__(cls)
 
-	def __init__(self, file, checkChecksums=0, fontNumber=-1):
+	def __init__(self, file, checkChecksums=1, fontNumber=-1):
 		self.file = file
 		self.checkChecksums = checkChecksums
 
@@ -124,29 +123,29 @@
 	def close(self):
 		self.file.close()
 
-	# We define custom __getstate__ and __setstate__ to make SFNTReader pickle-able
-	# and deepcopy-able. When a TTFont is loaded as lazy=True, SFNTReader holds a
-	# reference to an external file object which is not pickleable. So in __getstate__
-	# we store the file name and current position, and in __setstate__ we reopen the
-	# same named file after unpickling.
+	def __deepcopy__(self, memo):
+		"""Overrides the default deepcopy of SFNTReader object, to make it work
+		in the case when TTFont is loaded with lazy=True, and thus reader holds a
+		reference to a file object which is not pickleable.
+		We work around it by manually copying the data into a in-memory stream.
+		"""
+		from copy import deepcopy
 
-	def __getstate__(self):
-		if isinstance(self.file, BytesIO):
-			# BytesIO is already pickleable, return the state unmodified
-			return self.__dict__
-
-		# remove unpickleable file attribute, and only store its name and pos
-		state = self.__dict__.copy()
-		del state["file"]
-		state["_filename"] = self.file.name
-		state["_filepos"] = self.file.tell()
-		return state
-
-	def __setstate__(self, state):
-		if "file" not in state:
-			self.file = open(state.pop("_filename"), "rb")
-			self.file.seek(state.pop("_filepos"))
-		self.__dict__.update(state)
+		cls = self.__class__
+		obj = cls.__new__(cls)
+		for k, v in self.__dict__.items():
+			if k == "file":
+				pos = v.tell()
+				v.seek(0)
+				buf = BytesIO(v.read())
+				v.seek(pos)
+				buf.seek(pos)
+				if hasattr(v, "name"):
+					buf.name = v.name
+				obj.file = buf
+			else:
+				obj.__dict__[k] = deepcopy(v, memo)
+		return obj
 
 
 # default compression level for WOFF 1.0 tables and metadata
@@ -555,7 +554,8 @@
 				reader.file.seek(reader.metaOffset)
 				rawData = reader.file.read(reader.metaLength)
 				assert len(rawData) == reader.metaLength
-				data = self._decompress(rawData)
+				import zlib
+				data = zlib.decompress(rawData)
 				assert len(data) == reader.metaOrigLength
 				self.metaData = data
 			if reader.privLength:
@@ -564,10 +564,6 @@
 				assert len(data) == reader.privLength
 				self.privData = data
 
-	def _decompress(self, rawData):
-		import zlib
-		return zlib.decompress(rawData)
-
 
 def calcChecksum(data):
 	"""Calculate the checksum for an arbitrary block of data.
diff --git a/Lib/fontTools/ttLib/standardGlyphOrder.py b/Lib/fontTools/ttLib/standardGlyphOrder.py
index 1f980e4..510773a 100644
--- a/Lib/fontTools/ttLib/standardGlyphOrder.py
+++ b/Lib/fontTools/ttLib/standardGlyphOrder.py
@@ -1,3 +1,6 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+
 #
 # 'post' table formats 1.0 and 2.0 rely on this list of "standard"
 # glyphs.
diff --git a/Lib/fontTools/ttLib/tables/B_A_S_E_.py b/Lib/fontTools/ttLib/tables/B_A_S_E_.py
index 9551e2c..14906b4 100644
--- a/Lib/fontTools/ttLib/tables/B_A_S_E_.py
+++ b/Lib/fontTools/ttLib/tables/B_A_S_E_.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .otBase import BaseTTXConverter
 
 
diff --git a/Lib/fontTools/ttLib/tables/BitmapGlyphMetrics.py b/Lib/fontTools/ttLib/tables/BitmapGlyphMetrics.py
index 9197923..685979a 100644
--- a/Lib/fontTools/ttLib/tables/BitmapGlyphMetrics.py
+++ b/Lib/fontTools/ttLib/tables/BitmapGlyphMetrics.py
@@ -1,5 +1,7 @@
 # Since bitmap glyph metrics are shared between EBLC and EBDT
 # this class gets its own python file.
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from fontTools.misc.textTools import safeEval
 import logging
diff --git a/Lib/fontTools/ttLib/tables/C_B_D_T_.py b/Lib/fontTools/ttLib/tables/C_B_D_T_.py
index 11bb60b..ba02910 100644
--- a/Lib/fontTools/ttLib/tables/C_B_D_T_.py
+++ b/Lib/fontTools/ttLib/tables/C_B_D_T_.py
@@ -3,7 +3,8 @@
 # Google Author(s): Matt Fontaine
 
 
-from fontTools.misc.py23 import bytesjoin
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from . import E_B_D_T_
 from .BitmapGlyphMetrics import BigGlyphMetrics, bigGlyphMetricsFormat, SmallGlyphMetrics, smallGlyphMetricsFormat
diff --git a/Lib/fontTools/ttLib/tables/C_B_L_C_.py b/Lib/fontTools/ttLib/tables/C_B_L_C_.py
index 2f78571..3d67dd0 100644
--- a/Lib/fontTools/ttLib/tables/C_B_L_C_.py
+++ b/Lib/fontTools/ttLib/tables/C_B_L_C_.py
@@ -2,6 +2,8 @@
 #
 # Google Author(s): Matt Fontaine
 
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from . import E_B_L_C_
 
 class table_C_B_L_C_(E_B_L_C_.table_E_B_L_C_):
diff --git a/Lib/fontTools/ttLib/tables/C_F_F_.py b/Lib/fontTools/ttLib/tables/C_F_F_.py
index d12b89d..f175d5c 100644
--- a/Lib/fontTools/ttLib/tables/C_F_F_.py
+++ b/Lib/fontTools/ttLib/tables/C_F_F_.py
@@ -1,4 +1,5 @@
-from io import BytesIO
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools import cffLib
 from . import DefaultTable
 
diff --git a/Lib/fontTools/ttLib/tables/C_F_F__2.py b/Lib/fontTools/ttLib/tables/C_F_F__2.py
index 6217ebb..7e30c8f 100644
--- a/Lib/fontTools/ttLib/tables/C_F_F__2.py
+++ b/Lib/fontTools/ttLib/tables/C_F_F__2.py
@@ -1,4 +1,6 @@
-from io import BytesIO
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools import cffLib
 from fontTools.ttLib.tables.C_F_F_ import table_C_F_F_
 
 
diff --git a/Lib/fontTools/ttLib/tables/C_O_L_R_.py b/Lib/fontTools/ttLib/tables/C_O_L_R_.py
index 4004d41..441242e 100644
--- a/Lib/fontTools/ttLib/tables/C_O_L_R_.py
+++ b/Lib/fontTools/ttLib/tables/C_O_L_R_.py
@@ -2,8 +2,11 @@
 #
 # Google Author(s): Behdad Esfahbod
 
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.textTools import safeEval
 from . import DefaultTable
+import struct
 
 
 class table_C_O_L_R_(DefaultTable.DefaultTable):
@@ -13,132 +16,128 @@
 	ttFont['COLR'][<glyphName>] = <value> will set the color layers for any glyph.
 	"""
 
-	@staticmethod
-	def _decompileColorLayersV0(table):
-		if not table.LayerRecordArray:
-			return {}
-		colorLayerLists = {}
-		layerRecords = table.LayerRecordArray.LayerRecord
-		numLayerRecords = len(layerRecords)
-		for baseRec in table.BaseGlyphRecordArray.BaseGlyphRecord:
-			baseGlyph = baseRec.BaseGlyph
-			firstLayerIndex = baseRec.FirstLayerIndex
-			numLayers = baseRec.NumLayers
-			assert (firstLayerIndex + numLayers <= numLayerRecords)
-			layers = []
-			for i in range(firstLayerIndex, firstLayerIndex+numLayers):
-				layerRec = layerRecords[i]
-				layers.append(
-					LayerRecord(layerRec.LayerGlyph, layerRec.PaletteIndex)
-				)
-			colorLayerLists[baseGlyph] = layers
-		return colorLayerLists
-
-	def _toOTTable(self, ttFont):
-		from . import otTables
-		from fontTools.colorLib.builder import populateCOLRv0
-
-		tableClass = getattr(otTables, self.tableTag)
-		table = tableClass()
-		table.Version = self.version
-
-		populateCOLRv0(
-			table,
-			{
-				baseGlyph: [(layer.name, layer.colorID) for layer in layers]
-				for baseGlyph, layers in self.ColorLayers.items()
-			},
-			glyphMap=ttFont.getReverseGlyphMap(rebuild=True),
-		)
-		return table
-
 	def decompile(self, data, ttFont):
-		from .otBase import OTTableReader
-		from . import otTables
+		self.getGlyphName = ttFont.getGlyphName # for use in get/set item functions, for access by GID
+		self.version, numBaseGlyphRecords, offsetBaseGlyphRecord, offsetLayerRecord, numLayerRecords = struct.unpack(">HHLLH", data[:14])
+		assert (self.version == 0), "Version of COLR table is higher than I know how to handle"
+		glyphOrder = ttFont.getGlyphOrder()
+		gids = []
+		layerLists = []
+		glyphPos = offsetBaseGlyphRecord
+		for i in range(numBaseGlyphRecords):
+			gid, firstLayerIndex, numLayers = struct.unpack(">HHH", data[glyphPos:glyphPos+6])
+			glyphPos += 6
+			gids.append(gid)
+			assert (firstLayerIndex + numLayers <= numLayerRecords)
+			layerPos = offsetLayerRecord + firstLayerIndex * 4
+			layers = []
+			for j in range(numLayers):
+				layerGid, colorID = struct.unpack(">HH", data[layerPos:layerPos+4])
+				try:
+					layerName = glyphOrder[layerGid]
+				except IndexError:
+					layerName = self.getGlyphName(layerGid)
+				layerPos += 4
+				layers.append(LayerRecord(layerName, colorID))
+			layerLists.append(layers)
 
-		# We use otData to decompile, but we adapt the decompiled otTables to the
-		# existing COLR v0 API for backward compatibility.
-		reader = OTTableReader(data, tableTag=self.tableTag)
-		tableClass = getattr(otTables, self.tableTag)
-		table = tableClass()
-		table.decompile(reader, ttFont)
+		self.ColorLayers = colorLayerLists = {}
+		try:
+			names = [glyphOrder[gid] for gid in gids]
+		except IndexError:
+			getGlyphName = self.getGlyphName
+			names = map(getGlyphName, gids)
 
-		self.version = table.Version
-		if self.version == 0:
-			self.ColorLayers = self._decompileColorLayersV0(table)
-		else:
-			# for new versions, keep the raw otTables around
-			self.table = table
+		for name, layerList in zip(names, layerLists):
+			colorLayerLists[name] = layerList
 
 	def compile(self, ttFont):
-		from .otBase import OTTableWriter
+		ordered = []
+		ttFont.getReverseGlyphMap(rebuild=True)
+		glyphNames = self.ColorLayers.keys()
+		for glyphName in glyphNames:
+			try:
+				gid = ttFont.getGlyphID(glyphName)
+			except:
+				assert 0, "COLR table contains a glyph name not in ttFont.getGlyphNames(): " + str(glyphName)
+			ordered.append([gid, glyphName, self.ColorLayers[glyphName]])
+		ordered.sort()
 
-		if hasattr(self, "table"):
-			table = self.table
-		else:
-			table = self._toOTTable(ttFont)
+		glyphMap = []
+		layerMap = []
+		for (gid, glyphName, layers) in ordered:
+			glyphMap.append(struct.pack(">HHH", gid, len(layerMap), len(layers)))
+			for layer in layers:
+				layerMap.append(struct.pack(">HH", ttFont.getGlyphID(layer.name), layer.colorID))
 
-		writer = OTTableWriter(tableTag=self.tableTag)
-		table.compile(writer, ttFont)
-		return writer.getAllData()
+		dataList = [struct.pack(">HHLLH", self.version, len(glyphMap), 14, 14+6*len(glyphMap), len(layerMap))]
+		dataList.extend(glyphMap)
+		dataList.extend(layerMap)
+		data = bytesjoin(dataList)
+		return data
 
 	def toXML(self, writer, ttFont):
-		if hasattr(self, "table"):
-			self.table.toXML2(writer, ttFont)
-		else:
-			writer.simpletag("version", value=self.version)
+		writer.simpletag("version", value=self.version)
+		writer.newline()
+		ordered = []
+		glyphNames = self.ColorLayers.keys()
+		for glyphName in glyphNames:
+			try:
+				gid = ttFont.getGlyphID(glyphName)
+			except:
+				assert 0, "COLR table contains a glyph name not in ttFont.getGlyphNames(): " + str(glyphName)
+			ordered.append([gid, glyphName, self.ColorLayers[glyphName]])
+		ordered.sort()
+		for entry in ordered:
+			writer.begintag("ColorGlyph", name=entry[1])
 			writer.newline()
-			for baseGlyph in sorted(self.ColorLayers.keys(), key=ttFont.getGlyphID):
-				writer.begintag("ColorGlyph", name=baseGlyph)
-				writer.newline()
-				for layer in self.ColorLayers[baseGlyph]:
-					layer.toXML(writer, ttFont)
-				writer.endtag("ColorGlyph")
-				writer.newline()
+			for layer in entry[2]:
+				layer.toXML(writer, ttFont)
+			writer.endtag("ColorGlyph")
+			writer.newline()
 
 	def fromXML(self, name, attrs, content, ttFont):
-		if name == "version":  # old COLR v0 API
-			setattr(self, name, safeEval(attrs["value"]))
-		elif name == "ColorGlyph":
-			if not hasattr(self, "ColorLayers"):
-				self.ColorLayers = {}
+		if not hasattr(self, "ColorLayers"):
+			self.ColorLayers = {}
+		self.getGlyphName = ttFont.getGlyphName # for use in get/set item functions, for access by GID
+		if name == "ColorGlyph":
 			glyphName = attrs["name"]
 			for element in content:
-				if isinstance(element, str):
+				if isinstance(element, basestring):
 					continue
 			layers = []
 			for element in content:
-				if isinstance(element, str):
+				if isinstance(element, basestring):
 					continue
 				layer = LayerRecord()
 				layer.fromXML(element[0], element[1], element[2], ttFont)
 				layers.append (layer)
-			self.ColorLayers[glyphName] = layers
-		else:  # new COLR v1 API
-			from . import otTables
+			self[glyphName] = layers
+		elif "value" in attrs:
+			setattr(self, name, safeEval(attrs["value"]))
 
-			if not hasattr(self, "table"):
-				tableClass = getattr(otTables, self.tableTag)
-				self.table = tableClass()
-			self.table.fromXML(name, attrs, content, ttFont)
-			self.table.populateDefaults()
-			self.version = self.table.Version
+	def __getitem__(self, glyphSelector):
+		if isinstance(glyphSelector, int):
+			# its a gid, convert to glyph name
+			glyphSelector = self.getGlyphName(glyphSelector)
 
-	def __getitem__(self, glyphName):
-		if not isinstance(glyphName, str):
-			raise TypeError(f"expected str, found {type(glyphName).__name__}")
-		return self.ColorLayers[glyphName]
+		if glyphSelector not in self.ColorLayers:
+			return None
 
-	def __setitem__(self, glyphName, value):
-		if not isinstance(glyphName, str):
-			raise TypeError(f"expected str, found {type(glyphName).__name__}")
-		if value is not None:
-			self.ColorLayers[glyphName] = value
-		elif glyphName in self.ColorLayers:
-			del self.ColorLayers[glyphName]
+		return self.ColorLayers[glyphSelector]
 
-	def __delitem__(self, glyphName):
-		del self.ColorLayers[glyphName]
+	def __setitem__(self, glyphSelector, value):
+		if isinstance(glyphSelector, int):
+			# its a gid, convert to glyph name
+			glyphSelector = self.getGlyphName(glyphSelector)
+
+		if  value:
+			self.ColorLayers[glyphSelector] = value
+		elif glyphSelector in self.ColorLayers:
+			del self.ColorLayers[glyphSelector]
+
+	def __delitem__(self, glyphSelector):
+		del self.ColorLayers[glyphSelector]
 
 class LayerRecord(object):
 
@@ -153,6 +152,8 @@
 	def fromXML(self, eltname, attrs, content, ttFont):
 		for (name, value) in attrs.items():
 			if name == "name":
+				if isinstance(value, int):
+					value = ttFont.getGlyphName(value)
 				setattr(self, name, value)
 			else:
 				setattr(self, name, safeEval(value))
diff --git a/Lib/fontTools/ttLib/tables/C_P_A_L_.py b/Lib/fontTools/ttLib/tables/C_P_A_L_.py
index c095095..f9d0c64 100644
--- a/Lib/fontTools/ttLib/tables/C_P_A_L_.py
+++ b/Lib/fontTools/ttLib/tables/C_P_A_L_.py
@@ -2,7 +2,8 @@
 #
 # Google Author(s): Behdad Esfahbod
 
-from fontTools.misc.py23 import bytesjoin
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.textTools import safeEval
 from . import DefaultTable
 import array
@@ -13,9 +14,6 @@
 
 class table_C_P_A_L_(DefaultTable.DefaultTable):
 
-	NO_NAME_ID = 0xFFFF
-	DEFAULT_PALETTE_TYPE = 0
-
 	def __init__(self, tag=None):
 		DefaultTable.DefaultTable.__init__(self, tag)
 		self.palettes = []
@@ -48,25 +46,24 @@
 			offsetToPaletteEntryLabelArray) = (
 				struct.unpack(">LLL", data[pos:pos+12]))
 		self.paletteTypes = self._decompileUInt32Array(
-			data, offsetToPaletteTypeArray, numPalettes,
-			default=self.DEFAULT_PALETTE_TYPE)
+			data, offsetToPaletteTypeArray, numPalettes)
 		self.paletteLabels = self._decompileUInt16Array(
-			data, offsetToPaletteLabelArray, numPalettes, default=self.NO_NAME_ID)
+			data, offsetToPaletteLabelArray, numPalettes)
 		self.paletteEntryLabels = self._decompileUInt16Array(
 			data, offsetToPaletteEntryLabelArray,
-			self.numPaletteEntries, default=self.NO_NAME_ID)
+			self.numPaletteEntries)
 
-	def _decompileUInt16Array(self, data, offset, numElements, default=0):
+	def _decompileUInt16Array(self, data, offset, numElements):
 		if offset == 0:
-			return [default] * numElements
+			return [0] * numElements
 		result = array.array("H", data[offset : offset + 2 * numElements])
 		if sys.byteorder != "big": result.byteswap()
 		assert len(result) == numElements, result
 		return result.tolist()
 
-	def _decompileUInt32Array(self, data, offset, numElements, default=0):
+	def _decompileUInt32Array(self, data, offset, numElements):
 		if offset == 0:
-			return [default] * numElements
+			return [0] * numElements
 		result = array.array("I", data[offset : offset + 4 * numElements])
 		if sys.byteorder != "big": result.byteswap()
 		assert len(result) == numElements, result
@@ -140,7 +137,7 @@
 		return result
 
 	def _compilePaletteLabels(self):
-		if self.version == 0 or all(l == self.NO_NAME_ID for l in self.paletteLabels):
+		if self.version == 0 or not any(self.paletteLabels):
 			return b''
 		assert len(self.paletteLabels) == len(self.palettes)
 		result = bytesjoin([struct.pack(">H", label)
@@ -149,7 +146,7 @@
 		return result
 
 	def _compilePaletteEntryLabels(self):
-		if self.version == 0 or all(l == self.NO_NAME_ID for l in self.paletteEntryLabels):
+		if self.version == 0 or not any(self.paletteEntryLabels):
 			return b''
 		assert len(self.paletteEntryLabels) == self.numPaletteEntries
 		result = bytesjoin([struct.pack(">H", label)
@@ -169,15 +166,15 @@
 		writer.newline()
 		for index, palette in enumerate(self.palettes):
 			attrs = {"index": index}
-			paletteType = paletteTypes.get(index, self.DEFAULT_PALETTE_TYPE)
-			paletteLabel = paletteLabels.get(index, self.NO_NAME_ID)
-			if self.version > 0 and paletteLabel != self.NO_NAME_ID:
+			paletteType = paletteTypes.get(index)
+			paletteLabel = paletteLabels.get(index)
+			if self.version > 0 and paletteLabel is not None:
 				attrs["label"] = paletteLabel
-			if self.version > 0 and paletteType != self.DEFAULT_PALETTE_TYPE:
+			if self.version > 0 and paletteType is not None:
 				attrs["type"] = paletteType
 			writer.begintag("palette", **attrs)
 			writer.newline()
-			if (self.version > 0 and paletteLabel != self.NO_NAME_ID and
+			if (self.version > 0 and paletteLabel and
 			    ttFont and "name" in ttFont):
 				name = ttFont["name"].getDebugName(paletteLabel)
 				if name is not None:
@@ -188,11 +185,11 @@
 				color.toXML(writer, ttFont, cindex)
 			writer.endtag("palette")
 			writer.newline()
-		if self.version > 0 and not all(l == self.NO_NAME_ID for l in self.paletteEntryLabels):
+		if self.version > 0 and any(self.paletteEntryLabels):
 			writer.begintag("paletteEntryLabels")
 			writer.newline()
 			for index, label in enumerate(self.paletteEntryLabels):
-				if label != self.NO_NAME_ID:
+				if label:
 					writer.simpletag("label", index=index, value=label)
 					if (self.version > 0 and label and ttFont and "name" in ttFont):
 						name = ttFont["name"].getDebugName(label)
@@ -204,11 +201,11 @@
 
 	def fromXML(self, name, attrs, content, ttFont):
 		if name == "palette":
-			self.paletteLabels.append(int(attrs.get("label", self.NO_NAME_ID)))
-			self.paletteTypes.append(int(attrs.get("type", self.DEFAULT_PALETTE_TYPE)))
+			self.paletteLabels.append(int(attrs.get("label", "0")))
+			self.paletteTypes.append(int(attrs.get("type", "0")))
 			palette = []
 			for element in content:
-				if isinstance(element, str):
+				if isinstance(element, basestring):
 					continue
 				attrs = element[1]
 				color = Color.fromHex(attrs["value"])
@@ -217,7 +214,7 @@
 		elif name == "paletteEntryLabels":
 			colorLabels = {}
 			for element in content:
-				if isinstance(element, str):
+				if isinstance(element, basestring):
 					continue
 				elementName, elementAttr, _ = element
 				if elementName == "label":
@@ -225,13 +222,13 @@
 					nameID = safeEval(elementAttr["value"])
 					colorLabels[labelIndex] = nameID
 			self.paletteEntryLabels = [
-				colorLabels.get(i, self.NO_NAME_ID)
+				colorLabels.get(i, 0)
 				for i in range(self.numPaletteEntries)]
 		elif "value" in attrs:
 			value = safeEval(attrs["value"])
 			setattr(self, name, value)
 			if name == "numPaletteEntries":
-				self.paletteEntryLabels = [self.NO_NAME_ID] * self.numPaletteEntries
+				self.paletteEntryLabels = [0] * self.numPaletteEntries
 
 
 class Color(namedtuple("Color", "blue green red alpha")):
@@ -255,7 +252,3 @@
 		blue = int(value[4:6], 16)
 		alpha = int(value[6:8], 16) if len (value) >= 8 else 0xFF
 		return cls(red=red, green=green, blue=blue, alpha=alpha)
-
-	@classmethod
-	def fromRGBA(cls, red, green, blue, alpha):
-		return cls(red=red, green=green, blue=blue, alpha=alpha)
diff --git a/Lib/fontTools/ttLib/tables/D_S_I_G_.py b/Lib/fontTools/ttLib/tables/D_S_I_G_.py
index 1a520ca..af802b9 100644
--- a/Lib/fontTools/ttLib/tables/D_S_I_G_.py
+++ b/Lib/fontTools/ttLib/tables/D_S_I_G_.py
@@ -1,4 +1,5 @@
-from fontTools.misc.py23 import bytesjoin, strjoin, tobytes, tostr
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.textTools import safeEval
 from fontTools.misc import sstruct
 from . import DefaultTable
diff --git a/Lib/fontTools/ttLib/tables/D__e_b_g.py b/Lib/fontTools/ttLib/tables/D__e_b_g.py
deleted file mode 100644
index ff64a9b..0000000
--- a/Lib/fontTools/ttLib/tables/D__e_b_g.py
+++ /dev/null
@@ -1,17 +0,0 @@
-import json
-
-from . import DefaultTable
-
-
-class table_D__e_b_g(DefaultTable.DefaultTable):
-    def decompile(self, data, ttFont):
-        self.data = json.loads(data)
-
-    def compile(self, ttFont):
-        return json.dumps(self.data).encode("utf-8")
-
-    def toXML(self, writer, ttFont):
-        writer.writecdata(json.dumps(self.data))
-
-    def fromXML(self, name, attrs, content, ttFont):
-        self.data = json.loads(content)
diff --git a/Lib/fontTools/ttLib/tables/DefaultTable.py b/Lib/fontTools/ttLib/tables/DefaultTable.py
index c70480a..8ad36e1 100644
--- a/Lib/fontTools/ttLib/tables/DefaultTable.py
+++ b/Lib/fontTools/ttLib/tables/DefaultTable.py
@@ -1,4 +1,5 @@
-from fontTools.misc.py23 import Tag
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.ttLib import getClassTag
 
 class DefaultTable(object):
diff --git a/Lib/fontTools/ttLib/tables/E_B_D_T_.py b/Lib/fontTools/ttLib/tables/E_B_D_T_.py
index 5d9e724..3a316e5 100644
--- a/Lib/fontTools/ttLib/tables/E_B_D_T_.py
+++ b/Lib/fontTools/ttLib/tables/E_B_D_T_.py
@@ -1,4 +1,5 @@
-from fontTools.misc.py23 import bytechr, byteord, bytesjoin, strjoin
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from fontTools.misc.textTools import safeEval, readHex, hexStr, deHexStr
 from .BitmapGlyphMetrics import BigGlyphMetrics, bigGlyphMetricsFormat, SmallGlyphMetrics, smallGlyphMetricsFormat
diff --git a/Lib/fontTools/ttLib/tables/E_B_L_C_.py b/Lib/fontTools/ttLib/tables/E_B_L_C_.py
index 94d40d9..8cf6600 100644
--- a/Lib/fontTools/ttLib/tables/E_B_L_C_.py
+++ b/Lib/fontTools/ttLib/tables/E_B_L_C_.py
@@ -1,4 +1,5 @@
-from fontTools.misc.py23 import bytesjoin
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from . import DefaultTable
 from fontTools.misc.textTools import safeEval
@@ -154,7 +155,7 @@
 		# (2) Build each bitmapSizeTable.
 		# (3) Consolidate all the data into the main dataList in the correct order.
 
-		for _ in self.strikes:
+		for curStrike in self.strikes:
 			dataSize += sstruct.calcsize(bitmapSizeTableFormatPart1)
 			dataSize += len(('hori', 'vert')) * sstruct.calcsize(sbitLineMetricsFormat)
 			dataSize += sstruct.calcsize(bitmapSizeTableFormatPart2)
@@ -482,7 +483,7 @@
 			dataList = [EblcIndexSubTable.compile(self, ttFont)]
 			dataList += [struct.pack(dataFormat, offsetValue) for offsetValue in offsetArray]
 			# Take care of any padding issues. Only occurs in format 3.
-			if offsetDataSize * len(offsetArray) % 4 != 0:
+			if offsetDataSize * len(dataList) % 4 != 0:
 				dataList.append(struct.pack(dataFormat, 0))
 			return bytesjoin(dataList)
 
diff --git a/Lib/fontTools/ttLib/tables/F_F_T_M_.py b/Lib/fontTools/ttLib/tables/F_F_T_M_.py
index 2376f2d..3d110bd 100644
--- a/Lib/fontTools/ttLib/tables/F_F_T_M_.py
+++ b/Lib/fontTools/ttLib/tables/F_F_T_M_.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from fontTools.misc.textTools import safeEval
 from fontTools.misc.timeTools import timestampFromString, timestampToString
diff --git a/Lib/fontTools/ttLib/tables/F__e_a_t.py b/Lib/fontTools/ttLib/tables/F__e_a_t.py
index 7e51061..ec497f2 100644
--- a/Lib/fontTools/ttLib/tables/F__e_a_t.py
+++ b/Lib/fontTools/ttLib/tables/F__e_a_t.py
@@ -1,6 +1,8 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
-from fontTools.misc.fixedTools import floatToFixedToStr
 from fontTools.misc.textTools import safeEval
+from .otBase import BaseTTXConverter
 from . import DefaultTable
 from . import grUtils
 import struct
@@ -18,7 +20,6 @@
 
     def decompile(self, data, ttFont):
         (_, data) = sstruct.unpack2(Feat_hdr_format, data, self)
-        self.version = float(floatToFixedToStr(self.version, precisionBits=16))
         numFeats, = struct.unpack('>H', data[:2])
         data = data[8:]
         allfeats = []
diff --git a/Lib/fontTools/ttLib/tables/G_D_E_F_.py b/Lib/fontTools/ttLib/tables/G_D_E_F_.py
index d4a5741..08faf62 100644
--- a/Lib/fontTools/ttLib/tables/G_D_E_F_.py
+++ b/Lib/fontTools/ttLib/tables/G_D_E_F_.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .otBase import BaseTTXConverter
 
 
diff --git a/Lib/fontTools/ttLib/tables/G_M_A_P_.py b/Lib/fontTools/ttLib/tables/G_M_A_P_.py
index 5b30dcf..afa8c4d 100644
--- a/Lib/fontTools/ttLib/tables/G_M_A_P_.py
+++ b/Lib/fontTools/ttLib/tables/G_M_A_P_.py
@@ -1,4 +1,5 @@
-from fontTools.misc.py23 import tobytes, tostr
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from fontTools.misc.textTools import safeEval
 from . import DefaultTable
@@ -115,7 +116,7 @@
 			gmapRecord = GMAPRecord()
 			self.gmapRecords.append(gmapRecord)
 			for element in content:
-				if isinstance(element, str):
+				if isinstance(element, basestring):
 					continue
 				name, attrs, content = element
 				gmapRecord.fromXML(name, attrs, content, ttFont)
diff --git a/Lib/fontTools/ttLib/tables/G_P_K_G_.py b/Lib/fontTools/ttLib/tables/G_P_K_G_.py
index 7598a62..b835f4a 100644
--- a/Lib/fontTools/ttLib/tables/G_P_K_G_.py
+++ b/Lib/fontTools/ttLib/tables/G_P_K_G_.py
@@ -1,4 +1,5 @@
-from fontTools.misc.py23 import bytesjoin
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from fontTools.misc.textTools import safeEval, readHex
 from . import DefaultTable
@@ -23,7 +24,7 @@
 
 		GMAPoffsets = array.array("I")
 		endPos = (self.numGMAPs+1) * 4
-		GMAPoffsets.frombytes(newData[:endPos])
+		GMAPoffsets.fromstring(newData[:endPos])
 		if sys.byteorder != "big": GMAPoffsets.byteswap()
 		self.GMAPs = []
 		for i in range(self.numGMAPs):
@@ -33,7 +34,7 @@
 		pos = endPos
 		endPos = pos + (self.numGlyplets + 1)*4
 		glyphletOffsets = array.array("I")
-		glyphletOffsets.frombytes(newData[pos:endPos])
+		glyphletOffsets.fromstring(newData[pos:endPos])
 		if sys.byteorder != "big": glyphletOffsets.byteswap()
 		self.glyphlets = []
 		for i in range(self.numGlyplets):
@@ -56,7 +57,7 @@
 			GMAPoffsets[i] = pos
 		gmapArray = array.array("I", GMAPoffsets)
 		if sys.byteorder != "big": gmapArray.byteswap()
-		dataList.append(gmapArray.tobytes())
+		dataList.append(gmapArray.tostring())
 
 		glyphletOffsets[0] = pos
 		for i in range(1, self.numGlyplets +1):
@@ -64,7 +65,7 @@
 			glyphletOffsets[i] = pos
 		glyphletArray = array.array("I", glyphletOffsets)
 		if sys.byteorder != "big": glyphletArray.byteswap()
-		dataList.append(glyphletArray.tobytes())
+		dataList.append(glyphletArray.tostring())
 		dataList += self.GMAPs
 		dataList += self.glyphlets
 		data = bytesjoin(dataList)
@@ -106,7 +107,7 @@
 			if not hasattr(self, "GMAPs"):
 				self.GMAPs = []
 			for element in content:
-				if isinstance(element, str):
+				if isinstance(element, basestring):
 					continue
 				itemName, itemAttrs, itemContent = element
 				if itemName == "hexdata":
@@ -115,7 +116,7 @@
 			if not hasattr(self, "glyphlets"):
 				self.glyphlets = []
 			for element in content:
-				if isinstance(element, str):
+				if isinstance(element, basestring):
 					continue
 				itemName, itemAttrs, itemContent = element
 				if itemName == "hexdata":
diff --git a/Lib/fontTools/ttLib/tables/G_P_O_S_.py b/Lib/fontTools/ttLib/tables/G_P_O_S_.py
index 013c820..1c36061 100644
--- a/Lib/fontTools/ttLib/tables/G_P_O_S_.py
+++ b/Lib/fontTools/ttLib/tables/G_P_O_S_.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .otBase import BaseTTXConverter
 
 
diff --git a/Lib/fontTools/ttLib/tables/G_S_U_B_.py b/Lib/fontTools/ttLib/tables/G_S_U_B_.py
index 4403649..d23e8ba 100644
--- a/Lib/fontTools/ttLib/tables/G_S_U_B_.py
+++ b/Lib/fontTools/ttLib/tables/G_S_U_B_.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .otBase import BaseTTXConverter
 
 
diff --git a/Lib/fontTools/ttLib/tables/G__l_a_t.py b/Lib/fontTools/ttLib/tables/G__l_a_t.py
index a4e8e38..b7e8281 100644
--- a/Lib/fontTools/ttLib/tables/G__l_a_t.py
+++ b/Lib/fontTools/ttLib/tables/G__l_a_t.py
@@ -1,11 +1,12 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
-from fontTools.misc.fixedTools import floatToFixedToStr
 from fontTools.misc.textTools import safeEval
-# from itertools import *
+from itertools import *
 from functools import partial
 from . import DefaultTable
 from . import grUtils
-import struct
+import struct, operator, warnings
 
 
 Glat_format_0 = """
@@ -68,7 +69,6 @@
 
     def decompile(self, data, ttFont):
         sstruct.unpack2(Glat_format_0, data, self)
-        self.version = float(floatToFixedToStr(self.version, precisionBits=16))
         if self.version <= 1.9:
             decoder = partial(self.decompileAttributes12,fmt=Glat_format_1_entry)
         elif self.version <= 2.9:   
diff --git a/Lib/fontTools/ttLib/tables/G__l_o_c.py b/Lib/fontTools/ttLib/tables/G__l_o_c.py
index fa114a3..188637d 100644
--- a/Lib/fontTools/ttLib/tables/G__l_o_c.py
+++ b/Lib/fontTools/ttLib/tables/G__l_o_c.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from fontTools.misc.textTools import safeEval
 from . import DefaultTable
@@ -29,11 +31,11 @@
         flags = self.flags
         del self.flags
         self.locations = array.array('I' if flags & 1 else 'H')
-        self.locations.frombytes(data[:len(data) - self.numAttribs * (flags & 2)])
+        self.locations.fromstring(data[:len(data) - self.numAttribs * (flags & 2)])
         if sys.byteorder != "big": self.locations.byteswap()
         self.attribIds = array.array('H')
         if flags & 2:
-            self.attribIds.frombytes(data[-self.numAttribs * 2:])
+            self.attribIds.fromstring(data[-self.numAttribs * 2:])
             if sys.byteorder != "big": self.attribIds.byteswap()
 
     def compile(self, ttFont):
@@ -41,11 +43,11 @@
                 flags=(bool(self.attribIds) << 1) + (self.locations.typecode == 'I'),
                 numAttribs=self.numAttribs))
         if sys.byteorder != "big": self.locations.byteswap()
-        data += self.locations.tobytes()
+        data += self.locations.tostring()
         if sys.byteorder != "big": self.locations.byteswap()
         if self.attribIds:
             if sys.byteorder != "big": self.attribIds.byteswap()
-            data += self.attribIds.tobytes()
+            data += self.attribIds.tostring()
             if sys.byteorder != "big": self.attribIds.byteswap()
         return data
 
diff --git a/Lib/fontTools/ttLib/tables/H_V_A_R_.py b/Lib/fontTools/ttLib/tables/H_V_A_R_.py
index 56992ad..efab4e7 100644
--- a/Lib/fontTools/ttLib/tables/H_V_A_R_.py
+++ b/Lib/fontTools/ttLib/tables/H_V_A_R_.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .otBase import BaseTTXConverter
 
 
diff --git a/Lib/fontTools/ttLib/tables/J_S_T_F_.py b/Lib/fontTools/ttLib/tables/J_S_T_F_.py
index ddf5405..dffd08b 100644
--- a/Lib/fontTools/ttLib/tables/J_S_T_F_.py
+++ b/Lib/fontTools/ttLib/tables/J_S_T_F_.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .otBase import BaseTTXConverter
 
 
diff --git a/Lib/fontTools/ttLib/tables/L_T_S_H_.py b/Lib/fontTools/ttLib/tables/L_T_S_H_.py
index 94c2c22..dd0f195 100644
--- a/Lib/fontTools/ttLib/tables/L_T_S_H_.py
+++ b/Lib/fontTools/ttLib/tables/L_T_S_H_.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.textTools import safeEval
 from . import DefaultTable
 import struct
@@ -17,7 +19,7 @@
 		# ouch: the assertion is not true in Chicago!
 		#assert numGlyphs == ttFont['maxp'].numGlyphs
 		yPels = array.array("B")
-		yPels.frombytes(data)
+		yPels.fromstring(data)
 		self.yPels = {}
 		for i in range(numGlyphs):
 			self.yPels[ttFont.getGlyphName(i)] = yPels[i]
@@ -32,7 +34,7 @@
 		for name in names:
 			yPels[ttFont.getGlyphID(name)] = self.yPels[name]
 		yPels = array.array("B", yPels)
-		return struct.pack(">HH", version, numGlyphs) + yPels.tobytes()
+		return struct.pack(">HH", version, numGlyphs) + yPels.tostring()
 
 	def toXML(self, writer, ttFont):
 		names = sorted(self.yPels.keys())
diff --git a/Lib/fontTools/ttLib/tables/M_A_T_H_.py b/Lib/fontTools/ttLib/tables/M_A_T_H_.py
index d894c08..8c329ba 100644
--- a/Lib/fontTools/ttLib/tables/M_A_T_H_.py
+++ b/Lib/fontTools/ttLib/tables/M_A_T_H_.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .otBase import BaseTTXConverter
 
 
diff --git a/Lib/fontTools/ttLib/tables/M_E_T_A_.py b/Lib/fontTools/ttLib/tables/M_E_T_A_.py
index d4f6bc8..3eb6550 100644
--- a/Lib/fontTools/ttLib/tables/M_E_T_A_.py
+++ b/Lib/fontTools/ttLib/tables/M_E_T_A_.py
@@ -1,4 +1,5 @@
-from fontTools.misc.py23 import byteord
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from fontTools.misc.textTools import safeEval
 from . import DefaultTable
@@ -173,7 +174,7 @@
 			glyphRec = GlyphRecord()
 			self.glyphRecords.append(glyphRec)
 			for element in content:
-				if isinstance(element, str):
+				if isinstance(element, basestring):
 					continue
 				name, attrs, content = element
 				glyphRec.fromXML(name, attrs, content, ttFont)
@@ -207,7 +208,7 @@
 			stringRec = StringRecord()
 			self.stringRecs.append(stringRec)
 			for element in content:
-				if isinstance(element, str):
+				if isinstance(element, basestring):
 					continue
 				stringRec.fromXML(name, attrs, content, ttFont)
 			stringRec.stringLen = len(stringRec.string)
@@ -229,7 +230,7 @@
 # XXX The following two functions are really broken around UTF-8 vs Unicode
 
 def mapXMLToUTF8(string):
-	uString = str()
+	uString = unicode()
 	strLen = len(string)
 	i = 0
 	while i < strLen:
@@ -245,9 +246,9 @@
 				i = i+1
 			valStr = string[j:i]
 
-			uString = uString + chr(eval('0x' + valStr))
+			uString = uString + unichr(eval('0x' + valStr))
 		else:
-			uString = uString + chr(byteord(string[i]))
+			uString = uString + unichr(byteord(string[i]))
 		i = i +1
 
 	return uString.encode('utf_8')
@@ -281,7 +282,7 @@
 
 	def fromXML(self, name, attrs, content, ttFont):
 		for element in content:
-			if isinstance(element, str):
+			if isinstance(element, basestring):
 				continue
 			name, attrs, content = element
 			value = attrs["value"]
diff --git a/Lib/fontTools/ttLib/tables/M_V_A_R_.py b/Lib/fontTools/ttLib/tables/M_V_A_R_.py
index 34ab20f..8659ae8 100644
--- a/Lib/fontTools/ttLib/tables/M_V_A_R_.py
+++ b/Lib/fontTools/ttLib/tables/M_V_A_R_.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .otBase import BaseTTXConverter
 
 
diff --git a/Lib/fontTools/ttLib/tables/O_S_2f_2.py b/Lib/fontTools/ttLib/tables/O_S_2f_2.py
index a576522..107d859 100644
--- a/Lib/fontTools/ttLib/tables/O_S_2f_2.py
+++ b/Lib/fontTools/ttLib/tables/O_S_2f_2.py
@@ -1,7 +1,8 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from fontTools.misc.textTools import safeEval, num2binary, binary2num
 from fontTools.ttLib.tables import DefaultTable
-import bisect
 import logging
 
 
@@ -475,19 +476,22 @@
 )
 
 
-_unicodeStarts = []
-_unicodeValues = [None]
+_unicodeRangeSets = []
 
-def _getUnicodeRanges():
-	# build the ranges of codepoints for each unicode range bit, and cache result
-	if not _unicodeStarts:
-		unicodeRanges = [
-			(start, (stop, bit)) for bit, blocks in enumerate(OS2_UNICODE_RANGES)
-			for _, (start, stop) in blocks]
-		for start, (stop, bit) in sorted(unicodeRanges):
-			_unicodeStarts.append(start)
-			_unicodeValues.append((stop, bit))
-	return _unicodeStarts, _unicodeValues
+def _getUnicodeRangeSets():
+	# build the sets of codepoints for each unicode range bit, and cache result
+	if not _unicodeRangeSets:
+		for bit, blocks in enumerate(OS2_UNICODE_RANGES):
+			rangeset = set()
+			for _, (start, stop) in blocks:
+				rangeset.update(set(range(start, stop+1)))
+			if bit == 57:
+				# The spec says that bit 57 ("Non Plane 0") implies that there's
+				# at least one codepoint beyond the BMP; so I also include all
+				# the non-BMP codepoints here
+				rangeset.update(set(range(0x10000, 0x110000)))
+			_unicodeRangeSets.append(rangeset)
+	return _unicodeRangeSets
 
 
 def intersectUnicodeRanges(unicodes, inverse=False):
@@ -501,22 +505,15 @@
 	>>> intersectUnicodeRanges([0x0410, 0x1F000]) == {9, 57, 122}
 	True
 	>>> intersectUnicodeRanges([0x0410, 0x1F000], inverse=True) == (
-	...     set(range(len(OS2_UNICODE_RANGES))) - {9, 57, 122})
+	...     set(range(123)) - {9, 57, 122})
 	True
 	"""
 	unicodes = set(unicodes)
-	unicodestarts, unicodevalues = _getUnicodeRanges()
-	bits = set()
-	for code in unicodes:
-		stop, bit = unicodevalues[bisect.bisect(unicodestarts, code)]
-		if code <= stop:
-			bits.add(bit)
-	# The spec says that bit 57 ("Non Plane 0") implies that there's
-	# at least one codepoint beyond the BMP; so I also include all
-	# the non-BMP codepoints here
-	if any(0x10000 <= code < 0x110000 for code in unicodes):
-		bits.add(57)
-	return set(range(len(OS2_UNICODE_RANGES))) - bits if inverse else bits
+	uniranges = _getUnicodeRangeSets()
+	bits = set([
+		bit for bit, unirange in enumerate(uniranges)
+		if not unirange.isdisjoint(unicodes) ^ inverse])
+	return bits
 
 
 if __name__ == "__main__":
diff --git a/Lib/fontTools/ttLib/tables/S_I_N_G_.py b/Lib/fontTools/ttLib/tables/S_I_N_G_.py
index dd9b63c..413ae48 100644
--- a/Lib/fontTools/ttLib/tables/S_I_N_G_.py
+++ b/Lib/fontTools/ttLib/tables/S_I_N_G_.py
@@ -1,4 +1,5 @@
-from fontTools.misc.py23 import bytechr, byteord, tobytes, tostr
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from fontTools.misc.textTools import safeEval
 from . import DefaultTable
diff --git a/Lib/fontTools/ttLib/tables/S_T_A_T_.py b/Lib/fontTools/ttLib/tables/S_T_A_T_.py
index 1769de9..1e044cf 100644
--- a/Lib/fontTools/ttLib/tables/S_T_A_T_.py
+++ b/Lib/fontTools/ttLib/tables/S_T_A_T_.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .otBase import BaseTTXConverter
 
 
diff --git a/Lib/fontTools/ttLib/tables/S_V_G_.py b/Lib/fontTools/ttLib/tables/S_V_G_.py
index 135f271..b061153 100644
--- a/Lib/fontTools/ttLib/tables/S_V_G_.py
+++ b/Lib/fontTools/ttLib/tables/S_V_G_.py
@@ -1,12 +1,13 @@
-from fontTools.misc.py23 import bytesjoin, strjoin, tobytes, tostr
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from . import DefaultTable
 try:
 	import xml.etree.cElementTree as ET
 except ImportError:
 	import xml.etree.ElementTree as ET
-from io import BytesIO
 import struct
+import re
 import logging
 
 
diff --git a/Lib/fontTools/ttLib/tables/S__i_l_f.py b/Lib/fontTools/ttLib/tables/S__i_l_f.py
index 95880b0..00d5f61 100644
--- a/Lib/fontTools/ttLib/tables/S__i_l_f.py
+++ b/Lib/fontTools/ttLib/tables/S__i_l_f.py
@@ -1,13 +1,13 @@
-from fontTools.misc.py23 import byteord
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
-from fontTools.misc.fixedTools import floatToFixedToStr
 from fontTools.misc.textTools import safeEval
-# from itertools import *
+from itertools import *
 from . import DefaultTable
 from . import grUtils
 from array import array
 from functools import reduce
-import struct, re, sys
+import struct, operator, warnings, re, sys
 
 Silf_hdr_format = '''
     >
@@ -313,7 +313,6 @@
 
     def decompile(self, data, ttFont):
         sstruct.unpack2(Silf_hdr_format, data, self)
-        self.version = float(floatToFixedToStr(self.version, precisionBits=16))
         if self.version >= 5.0:
             (data, self.scheme) = grUtils.decompress(data)
             sstruct.unpack2(Silf_hdr_format_3, data, self)
@@ -392,7 +391,6 @@
     def decompile(self, data, ttFont, version=2.0):
         if version >= 3.0 :
             _, data = sstruct.unpack2(Silf_part1_format_v3, data, self)
-            self.ruleVersion = float(floatToFixedToStr(self.ruleVersion, precisionBits=16))
         _, data = sstruct.unpack2(Silf_part1_format, data, self)
         for jlevel in range(self.numJLevels):
             j, data = sstruct.unpack2(Silf_justify_format, data, _Object())
@@ -403,7 +401,7 @@
         data = data[self.numCritFeatures * 2 + 1:]
         (numScriptTag,) = struct.unpack_from('B', data)
         if numScriptTag:
-            self.scriptTags = [struct.unpack("4s", data[x:x+4])[0].decode("ascii") for x in range(1, 1 + 4 * numScriptTag, 4)]
+            self.scriptTags = [struct.unpack("4s", data[x:x+4])[0] for x in range(1, 1 + 4 * numScriptTag, 4)]
         data = data[1 + 4 * numScriptTag:]
         (self.lbGID,) = struct.unpack('>H', data[:2])
         if self.numPasses:
@@ -449,8 +447,8 @@
             data += struct.pack((">%dH" % self.numCritFeaturs), *self.critFeatures)
         data += struct.pack("BB", 0, len(self.scriptTags))
         if len(self.scriptTags):
-            tdata = [struct.pack("4s", x.encode("ascii")) for x in self.scriptTags]
-            data += b"".join(tdata)
+            tdata = [struct.pack("4s", x) for x in self.scriptTags]
+            data += "".join(tdata)
         data += struct.pack(">H", self.lbGID)
         self.passOffset = len(data)
 
@@ -748,7 +746,7 @@
         transes = []
         for t in self.stateTrans:
             if sys.byteorder != "big": t.byteswap()
-            transes.append(t.tobytes())
+            transes.append(t.tostring())
             if sys.byteorder != "big": t.byteswap()
         if not len(transes):
             self.startStates = [0]
diff --git a/Lib/fontTools/ttLib/tables/S__i_l_l.py b/Lib/fontTools/ttLib/tables/S__i_l_l.py
index 5ab9ee3..bf9d83f 100644
--- a/Lib/fontTools/ttLib/tables/S__i_l_l.py
+++ b/Lib/fontTools/ttLib/tables/S__i_l_l.py
@@ -1,5 +1,6 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
-from fontTools.misc.fixedTools import floatToFixedToStr
 from fontTools.misc.textTools import safeEval
 from . import DefaultTable
 from . import grUtils
@@ -18,7 +19,6 @@
 
     def decompile(self, data, ttFont):
         (_, data) = sstruct.unpack2(Sill_hdr, data, self)
-        self.version = float(floatToFixedToStr(self.version, precisionBits=16))
         numLangs, = struct.unpack('>H', data[:2])
         data = data[8:]
         maxsetting = 0
@@ -44,13 +44,12 @@
     def compile(self, ttFont):
         ldat = b""
         fdat = b""
-        offset = len(self.langs)
+        offset = 0
         for c, inf in sorted(self.langs.items()):
-            ldat += struct.pack(">4sHH", c.encode('utf8'), len(inf), 8 * offset + 20)
+            ldat += struct.pack(">4sHH", c.encode('utf8'), len(inf), 8 * (offset + len(self.langs) + 1))
             for fid, val in inf:
                 fdat += struct.pack(">LHH", fid, val, 0)
             offset += len(inf)
-        ldat += struct.pack(">LHH", 0x80808080, 0, 8 * offset + 20)
         return sstruct.pack(Sill_hdr, self) + grUtils.bininfo(len(self.langs)) + \
                 ldat + fdat
 
diff --git a/Lib/fontTools/ttLib/tables/T_S_I_B_.py b/Lib/fontTools/ttLib/tables/T_S_I_B_.py
index 25d4310..7d47e3a 100644
--- a/Lib/fontTools/ttLib/tables/T_S_I_B_.py
+++ b/Lib/fontTools/ttLib/tables/T_S_I_B_.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .T_S_I_V_ import table_T_S_I_V_
 
 class table_T_S_I_B_(table_T_S_I_V_):
diff --git a/Lib/fontTools/ttLib/tables/T_S_I_C_.py b/Lib/fontTools/ttLib/tables/T_S_I_C_.py
index 573b3f9..b4684a4 100644
--- a/Lib/fontTools/ttLib/tables/T_S_I_C_.py
+++ b/Lib/fontTools/ttLib/tables/T_S_I_C_.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .otBase import BaseTTXConverter
 
 
diff --git a/Lib/fontTools/ttLib/tables/T_S_I_D_.py b/Lib/fontTools/ttLib/tables/T_S_I_D_.py
index 310eb17..f989c9e 100644
--- a/Lib/fontTools/ttLib/tables/T_S_I_D_.py
+++ b/Lib/fontTools/ttLib/tables/T_S_I_D_.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .T_S_I_V_ import table_T_S_I_V_
 
 class table_T_S_I_D_(table_T_S_I_V_):
diff --git a/Lib/fontTools/ttLib/tables/T_S_I_J_.py b/Lib/fontTools/ttLib/tables/T_S_I_J_.py
index c1a46ba..ca538ba 100644
--- a/Lib/fontTools/ttLib/tables/T_S_I_J_.py
+++ b/Lib/fontTools/ttLib/tables/T_S_I_J_.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .T_S_I_V_ import table_T_S_I_V_
 
 class table_T_S_I_J_(table_T_S_I_V_):
diff --git a/Lib/fontTools/ttLib/tables/T_S_I_P_.py b/Lib/fontTools/ttLib/tables/T_S_I_P_.py
index 778974c..062d332 100644
--- a/Lib/fontTools/ttLib/tables/T_S_I_P_.py
+++ b/Lib/fontTools/ttLib/tables/T_S_I_P_.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .T_S_I_V_ import table_T_S_I_V_
 
 class table_T_S_I_P_(table_T_S_I_V_):
diff --git a/Lib/fontTools/ttLib/tables/T_S_I_S_.py b/Lib/fontTools/ttLib/tables/T_S_I_S_.py
index 61c9f76..68e22ce 100644
--- a/Lib/fontTools/ttLib/tables/T_S_I_S_.py
+++ b/Lib/fontTools/ttLib/tables/T_S_I_S_.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .T_S_I_V_ import table_T_S_I_V_
 
 class table_T_S_I_S_(table_T_S_I_V_):
diff --git a/Lib/fontTools/ttLib/tables/T_S_I_V_.py b/Lib/fontTools/ttLib/tables/T_S_I_V_.py
index 8021445..46b2182 100644
--- a/Lib/fontTools/ttLib/tables/T_S_I_V_.py
+++ b/Lib/fontTools/ttLib/tables/T_S_I_V_.py
@@ -1,4 +1,5 @@
-from fontTools.misc.py23 import strjoin, tobytes, tostr
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from . import asciiTable
 
 class table_T_S_I_V_(asciiTable.asciiTable):
diff --git a/Lib/fontTools/ttLib/tables/T_S_I__0.py b/Lib/fontTools/ttLib/tables/T_S_I__0.py
index b187f42..81808ee 100644
--- a/Lib/fontTools/ttLib/tables/T_S_I__0.py
+++ b/Lib/fontTools/ttLib/tables/T_S_I__0.py
@@ -5,6 +5,8 @@
 programs and 'extra' programs ('fpgm', 'prep', and 'cvt') that are contained
 in the TSI1 table.
 """
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from . import DefaultTable
 import struct
 
diff --git a/Lib/fontTools/ttLib/tables/T_S_I__1.py b/Lib/fontTools/ttLib/tables/T_S_I__1.py
index 9ae7acd..5ef944a 100644
--- a/Lib/fontTools/ttLib/tables/T_S_I__1.py
+++ b/Lib/fontTools/ttLib/tables/T_S_I__1.py
@@ -4,7 +4,8 @@
 TSI1 contains the text of the glyph programs in the form of low-level assembly
 code, as well as the 'extra' programs 'fpgm', 'ppgm' (i.e. 'prep'), and 'cvt'.
 """
-from fontTools.misc.py23 import strjoin, tobytes, tostr
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from . import DefaultTable
 from fontTools.misc.loggingTools import LogMixin
 
@@ -68,7 +69,7 @@
 						"%r textLength (%d) must not be > 32768" % (name, textLength))
 				text = data[textOffset:textOffset+textLength]
 				assert len(text) == textLength
-				text = tostr(text, encoding='utf-8')
+				text = tounicode(text, encoding='utf-8')
 				if text:
 					programs[name] = text
 			if isExtra:
diff --git a/Lib/fontTools/ttLib/tables/T_S_I__2.py b/Lib/fontTools/ttLib/tables/T_S_I__2.py
index 036c981..7d41ee8 100644
--- a/Lib/fontTools/ttLib/tables/T_S_I__2.py
+++ b/Lib/fontTools/ttLib/tables/T_S_I__2.py
@@ -5,6 +5,8 @@
 programs that are contained in the TSI3 table. It uses the same format as
 the TSI0 table.
 """
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools import ttLib
 
 superclass = ttLib.getTableClass("TSI0")
diff --git a/Lib/fontTools/ttLib/tables/T_S_I__3.py b/Lib/fontTools/ttLib/tables/T_S_I__3.py
index a249014..ee95d06 100644
--- a/Lib/fontTools/ttLib/tables/T_S_I__3.py
+++ b/Lib/fontTools/ttLib/tables/T_S_I__3.py
@@ -3,6 +3,8 @@
 
 TSI3 contains the text of the glyph programs in the form of 'VTTTalk' code.
 """
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools import ttLib
 
 superclass = ttLib.getTableClass("TSI1")
diff --git a/Lib/fontTools/ttLib/tables/T_S_I__5.py b/Lib/fontTools/ttLib/tables/T_S_I__5.py
index 7be09f9..61b7604 100644
--- a/Lib/fontTools/ttLib/tables/T_S_I__5.py
+++ b/Lib/fontTools/ttLib/tables/T_S_I__5.py
@@ -3,6 +3,8 @@
 
 TSI5 contains the VTT character groups.
 """
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.textTools import safeEval
 from . import DefaultTable
 import sys
@@ -15,7 +17,7 @@
 		numGlyphs = ttFont['maxp'].numGlyphs
 		assert len(data) == 2 * numGlyphs
 		a = array.array("H")
-		a.frombytes(data)
+		a.fromstring(data)
 		if sys.byteorder != "big": a.byteswap()
 		self.glyphGrouping = {}
 		for i in range(numGlyphs):
@@ -27,7 +29,7 @@
 		for i in range(len(glyphNames)):
 			a.append(self.glyphGrouping.get(glyphNames[i], 0))
 		if sys.byteorder != "big": a.byteswap()
-		return a.tobytes()
+		return a.tostring()
 
 	def toXML(self, writer, ttFont):
 		names = sorted(self.glyphGrouping.keys())
diff --git a/Lib/fontTools/ttLib/tables/T_T_F_A_.py b/Lib/fontTools/ttLib/tables/T_T_F_A_.py
index 8446dfc..8ff8d1b 100644
--- a/Lib/fontTools/ttLib/tables/T_T_F_A_.py
+++ b/Lib/fontTools/ttLib/tables/T_T_F_A_.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from . import asciiTable
 
 class table_T_T_F_A_(asciiTable.asciiTable):
diff --git a/Lib/fontTools/ttLib/tables/TupleVariation.py b/Lib/fontTools/ttLib/tables/TupleVariation.py
index a63fb6c..fb2131b 100644
--- a/Lib/fontTools/ttLib/tables/TupleVariation.py
+++ b/Lib/fontTools/ttLib/tables/TupleVariation.py
@@ -1,11 +1,6 @@
-from fontTools.misc.py23 import bytechr, byteord, bytesjoin
-from fontTools.misc.fixedTools import (
-    fixedToFloat as fi2fl,
-    floatToFixed as fl2fi,
-    floatToFixedToStr as fl2str,
-    strToFixedToFloat as str2fl,
-    otRound,
-)
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools.misc.fixedTools import fixedToFloat, floatToFixed, otRound
 from fontTools.misc.textTools import safeEval
 import array
 import io
@@ -68,17 +63,17 @@
 		for axis in axisTags:
 			value = self.axes.get(axis)
 			if value is not None:
-				minValue, value, maxValue = value
+				minValue, value, maxValue = (float(v) for v in value)
 				defaultMinValue = min(value, 0.0)  # -0.3 --> -0.3; 0.7 --> 0.0
 				defaultMaxValue = max(value, 0.0)  # -0.3 -->  0.0; 0.7 --> 0.7
 				if minValue == defaultMinValue and maxValue == defaultMaxValue:
-					writer.simpletag("coord", axis=axis, value=fl2str(value, 14))
+					writer.simpletag("coord", axis=axis, value=value)
 				else:
 					attrs = [
 						("axis", axis),
-						("min", fl2str(minValue, 14)),
-						("value", fl2str(value, 14)),
-						("max", fl2str(maxValue, 14)),
+						("min", minValue),
+						("value", value),
+						("max", maxValue),
 				        ]
 					writer.simpletag("coord", attrs)
 				writer.newline()
@@ -106,11 +101,11 @@
 	def fromXML(self, name, attrs, _content):
 		if name == "coord":
 			axis = attrs["axis"]
-			value = str2fl(attrs["value"], 14)
+			value = float(attrs["value"])
 			defaultMinValue = min(value, 0.0)  # -0.3 --> -0.3; 0.7 --> 0.0
 			defaultMaxValue = max(value, 0.0)  # -0.3 -->  0.0; 0.7 --> 0.7
-			minValue = str2fl(attrs.get("min", defaultMinValue), 14)
-			maxValue = str2fl(attrs.get("max", defaultMaxValue), 14)
+			minValue = float(attrs.get("min", defaultMinValue))
+			maxValue = float(attrs.get("max", defaultMaxValue))
 			self.axes[axis] = (minValue, value, maxValue)
 		elif name == "delta":
 			if "pt" in attrs:
@@ -161,7 +156,7 @@
 		result = []
 		for axis in axisTags:
 			_minValue, value, _maxValue = self.axes.get(axis, (0.0, 0.0, 0.0))
-			result.append(struct.pack(">h", fl2fi(value, 14)))
+			result.append(struct.pack(">h", floatToFixed(value, 14)))
 		return bytesjoin(result)
 
 	def compileIntermediateCoord(self, axisTags):
@@ -179,8 +174,8 @@
 		maxCoords = []
 		for axis in axisTags:
 			minValue, value, maxValue = self.axes.get(axis, (0.0, 0.0, 0.0))
-			minCoords.append(struct.pack(">h", fl2fi(minValue, 14)))
-			maxCoords.append(struct.pack(">h", fl2fi(maxValue, 14)))
+			minCoords.append(struct.pack(">h", floatToFixed(minValue, 14)))
+			maxCoords.append(struct.pack(">h", floatToFixed(maxValue, 14)))
 		return bytesjoin(minCoords + maxCoords)
 
 	@staticmethod
@@ -188,7 +183,7 @@
 		coord = {}
 		pos = offset
 		for axis in axisTags:
-			coord[axis] = fi2fl(struct.unpack(">h", data[pos:pos+2])[0], 14)
+			coord[axis] = fixedToFloat(struct.unpack(">h", data[pos:pos+2])[0], 14)
 			pos += 2
 		return coord, pos
 
@@ -275,7 +270,7 @@
 			else:
 				points = array.array("B")
 				pointsSize = numPointsInRun
-			points.frombytes(data[pos:pos+pointsSize])
+			points.fromstring(data[pos:pos+pointsSize])
 			if sys.byteorder != "big": points.byteswap()
 
 			assert len(points) == numPointsInRun
@@ -432,7 +427,7 @@
 				else:
 					deltas = array.array("b")
 					deltasSize = numDeltasInRun
-				deltas.frombytes(data[pos:pos+deltasSize])
+				deltas.fromstring(data[pos:pos+deltasSize])
 				if sys.byteorder != "big": deltas.byteswap()
 				assert len(deltas) == numDeltasInRun
 				pos += deltasSize
diff --git a/Lib/fontTools/ttLib/tables/V_D_M_X_.py b/Lib/fontTools/ttLib/tables/V_D_M_X_.py
index ba8593f..abca3bf 100644
--- a/Lib/fontTools/ttLib/tables/V_D_M_X_.py
+++ b/Lib/fontTools/ttLib/tables/V_D_M_X_.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from . import DefaultTable
 from fontTools.misc import sstruct
 from fontTools.misc.textTools import safeEval
diff --git a/Lib/fontTools/ttLib/tables/V_O_R_G_.py b/Lib/fontTools/ttLib/tables/V_O_R_G_.py
index 0b7fe95..1b75294 100644
--- a/Lib/fontTools/ttLib/tables/V_O_R_G_.py
+++ b/Lib/fontTools/ttLib/tables/V_O_R_G_.py
@@ -1,6 +1,8 @@
-from fontTools.misc.py23 import bytesjoin
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.textTools import safeEval
 from . import DefaultTable
+import operator
 import struct
 
 
@@ -83,7 +85,7 @@
 		if name == "VOriginRecord":
 			vOriginRec = VOriginRecord()
 			for element in content:
-				if isinstance(element, str):
+				if isinstance(element, basestring):
 					continue
 				name, attrs, content = element
 				vOriginRec.fromXML(name, attrs, content, ttFont)
diff --git a/Lib/fontTools/ttLib/tables/V_V_A_R_.py b/Lib/fontTools/ttLib/tables/V_V_A_R_.py
index 88f3055..530f0e3 100644
--- a/Lib/fontTools/ttLib/tables/V_V_A_R_.py
+++ b/Lib/fontTools/ttLib/tables/V_V_A_R_.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .otBase import BaseTTXConverter
 
 
diff --git a/Lib/fontTools/ttLib/tables/__init__.py b/Lib/fontTools/ttLib/tables/__init__.py
index bbfb8b7..79a50fd 100644
--- a/Lib/fontTools/ttLib/tables/__init__.py
+++ b/Lib/fontTools/ttLib/tables/__init__.py
@@ -1,4 +1,7 @@
 
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+
 # DON'T EDIT! This file is generated by MetaTools/buildTableList.py.
 def _moduleFinderHint():
 	"""Dummy function to let modulefinder know what tables may be
@@ -14,7 +17,6 @@
 	from . import C_O_L_R_
 	from . import C_P_A_L_
 	from . import D_S_I_G_
-	from . import D__e_b_g
 	from . import E_B_D_T_
 	from . import E_B_L_C_
 	from . import F_F_T_M_
@@ -39,7 +41,6 @@
 	from . import S__i_l_f
 	from . import S__i_l_l
 	from . import T_S_I_B_
-	from . import T_S_I_C_
 	from . import T_S_I_D_
 	from . import T_S_I_J_
 	from . import T_S_I_P_
diff --git a/Lib/fontTools/ttLib/tables/_a_n_k_r.py b/Lib/fontTools/ttLib/tables/_a_n_k_r.py
index 1f2946c..3a1aa08 100644
--- a/Lib/fontTools/ttLib/tables/_a_n_k_r.py
+++ b/Lib/fontTools/ttLib/tables/_a_n_k_r.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .otBase import BaseTTXConverter
 
 
diff --git a/Lib/fontTools/ttLib/tables/_a_v_a_r.py b/Lib/fontTools/ttLib/tables/_a_v_a_r.py
index 2b6a40e..57601c5 100644
--- a/Lib/fontTools/ttLib/tables/_a_v_a_r.py
+++ b/Lib/fontTools/ttLib/tables/_a_v_a_r.py
@@ -1,13 +1,12 @@
-from fontTools.misc.py23 import bytesjoin
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools import ttLib
 from fontTools.misc import sstruct
-from fontTools.misc.fixedTools import (
-    fixedToFloat as fi2fl,
-    floatToFixed as fl2fi,
-    floatToFixedToStr as fl2str,
-    strToFixedToFloat as str2fl,
-)
+from fontTools.misc.fixedTools import fixedToFloat, floatToFixed
+from fontTools.misc.textTools import safeEval
 from fontTools.ttLib import TTLibError
 from . import DefaultTable
+import array
 import struct
 import logging
 
@@ -48,8 +47,8 @@
             mappings = sorted(self.segments[axis].items())
             result.append(struct.pack(">H", len(mappings)))
             for key, value in mappings:
-                fixedKey = fl2fi(key, 14)
-                fixedValue = fl2fi(value, 14)
+                fixedKey = floatToFixed(key, 14)
+                fixedValue = floatToFixed(value, 14)
                 result.append(struct.pack(">hh", fixedKey, fixedValue))
         return bytesjoin(result)
 
@@ -68,7 +67,7 @@
             pos = pos + 2
             for _ in range(numPairs):
                 fromValue, toValue = struct.unpack(">hh", data[pos:pos+4])
-                segments[fi2fl(fromValue, 14)] = fi2fl(toValue, 14)
+                segments[fixedToFloat(fromValue, 14)] = fixedToFloat(toValue, 14)
                 pos = pos + 4
 
     def toXML(self, writer, ttFont):
@@ -77,8 +76,10 @@
             writer.begintag("segment", axis=axis)
             writer.newline()
             for key, value in sorted(self.segments[axis].items()):
-                key = fl2str(key, 14)
-                value = fl2str(value, 14)
+                # roundtrip float -> fixed -> float to normalize TTX output
+                # as dumped after decompiling or straight from varLib
+                key = fixedToFloat(floatToFixed(key, 14), 14)
+                value = fixedToFloat(floatToFixed(value, 14), 14)
                 writer.simpletag("mapping", **{"from": key, "to": value})
                 writer.newline()
             writer.endtag("segment")
@@ -92,8 +93,8 @@
                 if isinstance(element, tuple):
                     elementName, elementAttrs, _ = element
                     if elementName == "mapping":
-                        fromValue = str2fl(elementAttrs["from"], 14)
-                        toValue = str2fl(elementAttrs["to"], 14)
+                        fromValue = safeEval(elementAttrs["from"])
+                        toValue = safeEval(elementAttrs["to"])
                         if fromValue in segment:
                             log.warning("duplicate entry for %s in axis '%s'",
                                         fromValue, axis)
diff --git a/Lib/fontTools/ttLib/tables/_b_s_l_n.py b/Lib/fontTools/ttLib/tables/_b_s_l_n.py
index 8e266fa..31d8399 100644
--- a/Lib/fontTools/ttLib/tables/_b_s_l_n.py
+++ b/Lib/fontTools/ttLib/tables/_b_s_l_n.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .otBase import BaseTTXConverter
 
 
diff --git a/Lib/fontTools/ttLib/tables/_c_i_d_g.py b/Lib/fontTools/ttLib/tables/_c_i_d_g.py
index de83d4d..1d6c502 100644
--- a/Lib/fontTools/ttLib/tables/_c_i_d_g.py
+++ b/Lib/fontTools/ttLib/tables/_c_i_d_g.py
@@ -1,4 +1,6 @@
 # coding: utf-8
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .otBase import BaseTTXConverter
 
 
diff --git a/Lib/fontTools/ttLib/tables/_c_m_a_p.py b/Lib/fontTools/ttLib/tables/_c_m_a_p.py
index a65a0c2..971a316 100644
--- a/Lib/fontTools/ttLib/tables/_c_m_a_p.py
+++ b/Lib/fontTools/ttLib/tables/_c_m_a_p.py
@@ -1,4 +1,5 @@
-from fontTools.misc.py23 import bytesjoin
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.textTools import safeEval, readHex
 from fontTools.misc.encodingTools import getEncoding
 from fontTools.ttLib import getSearchRange
@@ -18,7 +19,7 @@
 	cmap = {}
 	glyphOrder = font.getGlyphOrder()
 	for char,gid in zip(chars,gids):
-		if gid == 0:
+		if gid is 0:
 			continue
 		try:
 			name = glyphOrder[gid]
@@ -252,7 +253,7 @@
 		data = self.data # decompileHeader assigns the data after the header to self.data
 		assert 262 == self.length, "Format 0 cmap subtable not 262 bytes"
 		gids = array.array("B")
-		gids.frombytes(self.data)
+		gids.fromstring(self.data)
 		charCodes = list(range(len(gids)))
 		self.cmap = _make_map(self.ttFont, charCodes, gids)
 
@@ -266,7 +267,7 @@
 		valueList = [getGlyphID(cmap[i]) if i in cmap else 0 for i in range(256)]
 
 		gids = array.array("B", valueList)
-		data = struct.pack(">HHH", 0, 262, self.language) + gids.tobytes()
+		data = struct.pack(">HHH", 0, 262, self.language) + gids.tostring()
 		assert len(data) == 262
 		return data
 
@@ -336,7 +337,7 @@
 		maxSubHeaderindex = 0
 		# get the key array, and determine the number of subHeaders.
 		allKeys = array.array("H")
-		allKeys.frombytes(data[:512])
+		allKeys.fromstring(data[:512])
 		data = data[512:]
 		if sys.byteorder != "big": allKeys.byteswap()
 		subHeaderKeys = [ key//8 for key in allKeys]
@@ -352,7 +353,7 @@
 			pos += 8
 			giDataPos = pos + subHeader.idRangeOffset-2
 			giList = array.array("H")
-			giList.frombytes(data[giDataPos:giDataPos + subHeader.entryCount*2])
+			giList.fromstring(data[giDataPos:giDataPos + subHeader.entryCount*2])
 			if sys.byteorder != "big": giList.byteswap()
 			subHeader.glyphIndexArray = giList
 			subHeaderList.append(subHeader)
@@ -694,7 +695,7 @@
 		segCount = segCountX2 // 2
 
 		allCodes = array.array("H")
-		allCodes.frombytes(data)
+		allCodes.fromstring(data)
 		self.data = data = None
 
 		if sys.byteorder != "big": allCodes.byteswap()
@@ -826,7 +827,7 @@
 		if sys.byteorder != "big": charCodeArray.byteswap()
 		if sys.byteorder != "big": idDeltaArray.byteswap()
 		if sys.byteorder != "big": restArray.byteswap()
-		data = charCodeArray.tobytes() + idDeltaArray.tobytes() + restArray.tobytes()
+		data = charCodeArray.tostring() + idDeltaArray.tostring() + restArray.tostring()
 
 		length = struct.calcsize(cmap_format_4_format) + len(data)
 		header = struct.pack(cmap_format_4_format, self.format, length, self.language,
@@ -864,7 +865,7 @@
 		data = data[4:]
 		#assert len(data) == 2 * entryCount  # XXX not true in Apple's Helvetica!!!
 		gids = array.array("H")
-		gids.frombytes(data[:2 * int(entryCount)])
+		gids.fromstring(data[:2 * int(entryCount)])
 		if sys.byteorder != "big": gids.byteswap()
 		self.data = data = None
 
@@ -885,7 +886,7 @@
 			]
 			gids = array.array("H", valueList)
 			if sys.byteorder != "big": gids.byteswap()
-			data = gids.tobytes()
+			data = gids.tostring()
 		else:
 			data = b""
 			firstCode = 0
diff --git a/Lib/fontTools/ttLib/tables/_c_v_a_r.py b/Lib/fontTools/ttLib/tables/_c_v_a_r.py
index 09b2c16..c4ebbc9 100644
--- a/Lib/fontTools/ttLib/tables/_c_v_a_r.py
+++ b/Lib/fontTools/ttLib/tables/_c_v_a_r.py
@@ -1,4 +1,6 @@
-from fontTools.misc.py23 import bytesjoin
+from __future__ import \
+    print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from . import DefaultTable
 from fontTools.misc import sstruct
 from fontTools.ttLib.tables.TupleVariation import \
diff --git a/Lib/fontTools/ttLib/tables/_c_v_t.py b/Lib/fontTools/ttLib/tables/_c_v_t.py
index 26395c9..21df0ba 100644
--- a/Lib/fontTools/ttLib/tables/_c_v_t.py
+++ b/Lib/fontTools/ttLib/tables/_c_v_t.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.textTools import safeEval
 from . import DefaultTable
 import sys
@@ -7,14 +9,14 @@
 
 	def decompile(self, data, ttFont):
 		values = array.array("h")
-		values.frombytes(data)
+		values.fromstring(data)
 		if sys.byteorder != "big": values.byteswap()
 		self.values = values
 
 	def compile(self, ttFont):
 		values = self.values[:]
 		if sys.byteorder != "big": values.byteswap()
-		return values.tobytes()
+		return values.tostring()
 
 	def toXML(self, writer, ttFont):
 		for i in range(len(self.values)):
diff --git a/Lib/fontTools/ttLib/tables/_f_e_a_t.py b/Lib/fontTools/ttLib/tables/_f_e_a_t.py
index eb03f8b..3715271 100644
--- a/Lib/fontTools/ttLib/tables/_f_e_a_t.py
+++ b/Lib/fontTools/ttLib/tables/_f_e_a_t.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .otBase import BaseTTXConverter
 
 
diff --git a/Lib/fontTools/ttLib/tables/_f_p_g_m.py b/Lib/fontTools/ttLib/tables/_f_p_g_m.py
index ec3576c..6536dba 100644
--- a/Lib/fontTools/ttLib/tables/_f_p_g_m.py
+++ b/Lib/fontTools/ttLib/tables/_f_p_g_m.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from . import DefaultTable
 from . import ttProgram
 
diff --git a/Lib/fontTools/ttLib/tables/_f_v_a_r.py b/Lib/fontTools/ttLib/tables/_f_v_a_r.py
index 7487da6..3bc46e2 100644
--- a/Lib/fontTools/ttLib/tables/_f_v_a_r.py
+++ b/Lib/fontTools/ttLib/tables/_f_v_a_r.py
@@ -1,12 +1,8 @@
-from fontTools.misc.py23 import Tag, bytesjoin
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
-from fontTools.misc.fixedTools import (
-    fixedToFloat as fi2fl,
-    floatToFixed as fl2fi,
-    floatToFixedToStr as fl2str,
-    strToFixedToFloat as str2fl,
-)
-from fontTools.misc.textTools import safeEval
+from fontTools.misc.fixedTools import fixedToFloat, floatToFixed
+from fontTools.misc.textTools import safeEval, num2binary, binary2num
 from fontTools.ttLib import TTLibError
 from . import DefaultTable
 import struct
@@ -134,9 +130,9 @@
         writer.newline()
         for tag, value in [("AxisTag", self.axisTag),
                            ("Flags", "0x%X" % self.flags),
-                           ("MinValue", fl2str(self.minValue, 16)),
-                           ("DefaultValue", fl2str(self.defaultValue, 16)),
-                           ("MaxValue", fl2str(self.maxValue, 16)),
+                           ("MinValue", str(self.minValue)),
+                           ("DefaultValue", str(self.defaultValue)),
+                           ("MaxValue", str(self.maxValue)),
                            ("AxisNameID", str(self.axisNameID))]:
             writer.begintag(tag)
             writer.write(value)
@@ -153,11 +149,7 @@
                 self.axisTag = Tag(value)
             elif tag in {"Flags", "MinValue", "DefaultValue", "MaxValue",
                          "AxisNameID"}:
-                setattr(
-                    self,
-                    tag[0].lower() + tag[1:],
-                    str2fl(value, 16) if tag.endswith("Value") else safeEval(value)
-                )
+                setattr(self, tag[0].lower() + tag[1:], safeEval(value))
 
 
 class NamedInstance(object):
@@ -170,7 +162,7 @@
     def compile(self, axisTags, includePostScriptName):
         result = [sstruct.pack(FVAR_INSTANCE_FORMAT, self)]
         for axis in axisTags:
-            fixedCoord = fl2fi(self.coordinates[axis], 16)
+            fixedCoord = floatToFixed(self.coordinates[axis], 16)
             result.append(struct.pack(">l", fixedCoord))
         if includePostScriptName:
             result.append(struct.pack(">H", self.postscriptNameID))
@@ -181,7 +173,7 @@
         pos = sstruct.calcsize(FVAR_INSTANCE_FORMAT)
         for axis in axisTags:
             value = struct.unpack(">l", data[pos : pos + 4])[0]
-            self.coordinates[axis] = fi2fl(value, 16)
+            self.coordinates[axis] = fixedToFloat(value, 16)
             pos += 4
         if pos + 2 <= len(data):
           self.postscriptNameID = struct.unpack(">H", data[pos : pos + 2])[0]
@@ -208,7 +200,7 @@
         writer.newline()
         for axis in ttFont["fvar"].axes:
             writer.simpletag("coord", axis=axis.axisTag,
-                             value=fl2str(self.coordinates[axis.axisTag], 16))
+                             value=self.coordinates[axis.axisTag])
             writer.newline()
         writer.endtag("NamedInstance")
         writer.newline()
@@ -224,5 +216,4 @@
 
         for tag, elementAttrs, _ in filter(lambda t: type(t) is tuple, content):
             if tag == "coord":
-                value = str2fl(elementAttrs["value"], 16)
-                self.coordinates[elementAttrs["axis"]] = value
+                self.coordinates[elementAttrs["axis"]] = safeEval(elementAttrs["value"])
diff --git a/Lib/fontTools/ttLib/tables/_g_a_s_p.py b/Lib/fontTools/ttLib/tables/_g_a_s_p.py
index 2c80913..dce3569 100644
--- a/Lib/fontTools/ttLib/tables/_g_a_s_p.py
+++ b/Lib/fontTools/ttLib/tables/_g_a_s_p.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.textTools import safeEval
 from . import DefaultTable
 import struct
diff --git a/Lib/fontTools/ttLib/tables/_g_c_i_d.py b/Lib/fontTools/ttLib/tables/_g_c_i_d.py
index 2e746c8..f8b57e2 100644
--- a/Lib/fontTools/ttLib/tables/_g_c_i_d.py
+++ b/Lib/fontTools/ttLib/tables/_g_c_i_d.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .otBase import BaseTTXConverter
 
 
diff --git a/Lib/fontTools/ttLib/tables/_g_l_y_f.py b/Lib/fontTools/ttLib/tables/_g_l_y_f.py
index 4680ddb..7d2c16e 100644
--- a/Lib/fontTools/ttLib/tables/_g_l_y_f.py
+++ b/Lib/fontTools/ttLib/tables/_g_l_y_f.py
@@ -1,7 +1,8 @@
 """_g_l_y_f.py -- Converter classes for the 'glyf' table."""
 
+from __future__ import print_function, division, absolute_import
 from collections import namedtuple
-from fontTools.misc.py23 import bytechr, byteord, bytesjoin, tostr
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from fontTools import ttLib
 from fontTools import version
@@ -11,8 +12,6 @@
 from fontTools.misc.fixedTools import (
 	fixedToFloat as fi2fl,
 	floatToFixed as fl2fi,
-	floatToFixedToStr as fl2str,
-	strToFixedToFloat as str2fl,
 	otRound,
 )
 from numbers import Number
@@ -56,8 +55,7 @@
 
 	def decompile(self, data, ttFont):
 		loca = ttFont['loca']
-		pos = int(loca[0])
-		nextPos = 0
+		last = int(loca[0])
 		noname = 0
 		self.glyphs = {}
 		self.glyphOrder = glyphOrder = ttFont.getGlyphOrder()
@@ -67,17 +65,17 @@
 			except IndexError:
 				noname = noname + 1
 				glyphName = 'ttxautoglyph%s' % i
-			nextPos = int(loca[i+1])
-			glyphdata = data[pos:nextPos]
-			if len(glyphdata) != (nextPos - pos):
+			next = int(loca[i+1])
+			glyphdata = data[last:next]
+			if len(glyphdata) != (next - last):
 				raise ttLib.TTLibError("not enough 'glyf' table data")
 			glyph = Glyph(glyphdata)
 			self.glyphs[glyphName] = glyph
-			pos = nextPos
-		if len(data) - nextPos >= 4:
+			last = next
+		if len(data) - next >= 4:
 			log.warning(
 				"too much 'glyf' table data: expected %d, received %d bytes",
-				nextPos, len(data))
+				next, len(data))
 		if noname:
 			log.warning('%s glyphs have no name', noname)
 		if ttFont.lazy is False: # Be lazy for None and True
@@ -122,12 +120,6 @@
 			ttFont['loca'].set(locations)
 		if 'maxp' in ttFont:
 			ttFont['maxp'].numGlyphs = len(self.glyphs)
-		if not data:
-		# As a special case when all glyph in the font are empty, add a zero byte
-		# to the table, so that OTS doesn’t reject it, and to make the table work
-		# on Windows as well.
-		# See https://github.com/khaledhosny/ots/issues/52
-			data = b"\0"
 		return data
 
 	def toXML(self, writer, ttFont, splitGlyphs=False):
@@ -145,14 +137,11 @@
 			path, ext = os.path.splitext(writer.file.name)
 			existingGlyphFiles = set()
 		for glyphName in glyphNames:
-			if glyphName not in self:
-				log.warning("glyph '%s' does not exist in glyf table", glyphName)
-				continue
 			glyph = self[glyphName]
 			if glyph.numberOfContours:
 				if splitGlyphs:
 					glyphPath = userNameToFileName(
-						tostr(glyphName, 'utf-8'),
+						tounicode(glyphName, 'utf-8'),
 						existingGlyphFiles,
 						prefix=path + ".",
 						suffix=ext)
@@ -650,7 +639,6 @@
 		assert self.isComposite()
 		nContours = 0
 		nPoints = 0
-		initialMaxComponentDepth = maxComponentDepth
 		for compo in self.components:
 			baseGlyph = glyfTable[compo.glyphName]
 			if baseGlyph.numberOfContours == 0:
@@ -658,9 +646,8 @@
 			elif baseGlyph.numberOfContours > 0:
 				nP, nC = baseGlyph.getMaxpValues()
 			else:
-				nP, nC, componentDepth = baseGlyph.getCompositeMaxpValues(
-						glyfTable, initialMaxComponentDepth + 1)
-				maxComponentDepth = max(maxComponentDepth, componentDepth)
+				nP, nC, maxComponentDepth = baseGlyph.getCompositeMaxpValues(
+						glyfTable, maxComponentDepth + 1)
 			nPoints = nPoints + nP
 			nContours = nContours + nC
 		return CompositeMaxpValues(nPoints, nContours, maxComponentDepth)
@@ -691,7 +678,7 @@
 
 	def decompileCoordinates(self, data):
 		endPtsOfContours = array.array("h")
-		endPtsOfContours.frombytes(data[:2*self.numberOfContours])
+		endPtsOfContours.fromstring(data[:2*self.numberOfContours])
 		if sys.byteorder != "big": endPtsOfContours.byteswap()
 		self.endPtsOfContours = endPtsOfContours.tolist()
 
@@ -805,7 +792,7 @@
 		data = []
 		endPtsOfContours = array.array("h", self.endPtsOfContours)
 		if sys.byteorder != "big": endPtsOfContours.byteswap()
-		data.append(endPtsOfContours.tobytes())
+		data.append(endPtsOfContours.tostring())
 		instructions = self.program.getBytecode()
 		data.append(struct.pack(">h", len(instructions)))
 		data.append(instructions)
@@ -869,7 +856,7 @@
 				repeat = 0
 				compressedflags.append(flag)
 			lastflag = flag
-		compressedFlags = array.array("B", compressedflags).tobytes()
+		compressedFlags = array.array("B", compressedflags).tostring()
 		compressedXs = bytesjoin(xPoints)
 		compressedYs = bytesjoin(yPoints)
 		return (compressedFlags, compressedXs, compressedYs)
@@ -924,9 +911,9 @@
 			raise Exception("internal error")
 		except StopIteration:
 			pass
-		compressedFlags = compressedFlags.tobytes()
-		compressedXs = compressedXs.tobytes()
-		compressedYs = compressedYs.tobytes()
+		compressedFlags = compressedFlags.tostring()
+		compressedXs = compressedXs.tostring()
+		compressedYs = compressedYs.tostring()
 
 		return (compressedFlags, compressedXs, compressedYs)
 
@@ -1014,37 +1001,33 @@
 					coordinates, endPts, flags = g.getCoordinates(glyfTable)
 				except RecursionError:
 					raise ttLib.TTLibError("glyph '%s' contains a recursive component reference" % compo.glyphName)
-				coordinates = GlyphCoordinates(coordinates)
 				if hasattr(compo, "firstPt"):
-					# component uses two reference points: we apply the transform _before_
-					# computing the offset between the points
-					if hasattr(compo, "transform"):
-						coordinates.transform(compo.transform)
+					# move according to two reference points
 					x1,y1 = allCoords[compo.firstPt]
 					x2,y2 = coordinates[compo.secondPt]
 					move = x1-x2, y1-y2
+				else:
+					move = compo.x, compo.y
+
+				coordinates = GlyphCoordinates(coordinates)
+				if not hasattr(compo, "transform"):
 					coordinates.translate(move)
 				else:
-					# component uses XY offsets
-					move = compo.x, compo.y
-					if not hasattr(compo, "transform"):
-						coordinates.translate(move)
+					apple_way = compo.flags & SCALED_COMPONENT_OFFSET
+					ms_way = compo.flags & UNSCALED_COMPONENT_OFFSET
+					assert not (apple_way and ms_way)
+					if not (apple_way or ms_way):
+						scale_component_offset = SCALE_COMPONENT_OFFSET_DEFAULT  # see top of this file
 					else:
-						apple_way = compo.flags & SCALED_COMPONENT_OFFSET
-						ms_way = compo.flags & UNSCALED_COMPONENT_OFFSET
-						assert not (apple_way and ms_way)
-						if not (apple_way or ms_way):
-							scale_component_offset = SCALE_COMPONENT_OFFSET_DEFAULT  # see top of this file
-						else:
-							scale_component_offset = apple_way
-						if scale_component_offset:
-							# the Apple way: first move, then scale (ie. scale the component offset)
-							coordinates.translate(move)
-							coordinates.transform(compo.transform)
-						else:
-							# the MS way: first scale, then move
-							coordinates.transform(compo.transform)
-							coordinates.translate(move)
+						scale_component_offset = apple_way
+					if scale_component_offset:
+						# the Apple way: first move, then scale (ie. scale the component offset)
+						coordinates.translate(move)
+						coordinates.transform(compo.transform)
+					else:
+						# the MS way: first scale, then move
+						coordinates.transform(compo.transform)
+						coordinates.translate(move)
 				offset = len(allCoords)
 				allEndPts.extend(e + offset for e in endPts)
 				allCoords.extend(coordinates)
@@ -1170,7 +1153,7 @@
 			# Remove padding
 			data = data[:i]
 
-		self.data = data.tobytes()
+		self.data = data.tostring()
 
 	def removeHinting(self):
 		self.trim (remove_hinting=True)
@@ -1191,7 +1174,7 @@
 		for end in endPts:
 			end = end + 1
 			contour = coordinates[start:end]
-			cFlags = [flagOnCurve & f for f in flags[start:end]]
+			cFlags = flags[start:end]
 			start = end
 			if 1 not in cFlags:
 				# There is not a single on-curve point on the curve,
@@ -1210,10 +1193,7 @@
 				while contour:
 					nextOnCurve = cFlags.index(1) + 1
 					if nextOnCurve == 1:
-						# Skip a final lineTo(), as it is implied by
-						# pen.closePath()
-						if len(contour) > 1:
-							pen.lineTo(contour[0])
+						pen.lineTo(contour[0])
 					else:
 						pen.qCurveTo(*contour[:nextOnCurve])
 					contour = contour[nextOnCurve:]
@@ -1245,7 +1225,7 @@
 			# Start with the appropriate segment type based on the final segment
 			segmentType = "line" if cFlags[-1] == 1 else "qcurve"
 			for i, pt in enumerate(contour):
-				if cFlags[i] & flagOnCurve == 1:
+				if cFlags[i] == 1:
 					pen.addPoint(pt, segmentType=segmentType)
 					segmentType = "line"
 				else:
@@ -1382,18 +1362,15 @@
 			transform = self.transform
 			if transform[0][1] or transform[1][0]:
 				attrs = attrs + [
-					("scalex", fl2str(transform[0][0], 14)),
-					("scale01", fl2str(transform[0][1], 14)),
-					("scale10", fl2str(transform[1][0], 14)),
-					("scaley", fl2str(transform[1][1], 14)),
-				]
+						("scalex", transform[0][0]), ("scale01", transform[0][1]),
+						("scale10", transform[1][0]), ("scaley", transform[1][1]),
+						]
 			elif transform[0][0] != transform[1][1]:
 				attrs = attrs + [
-					("scalex", fl2str(transform[0][0], 14)),
-					("scaley", fl2str(transform[1][1], 14)),
-				]
+						("scalex", transform[0][0]), ("scaley", transform[1][1]),
+						]
 			else:
-				attrs = attrs + [("scale", fl2str(transform[0][0], 14))]
+				attrs = attrs + [("scale", transform[0][0])]
 		attrs = attrs + [("flags", hex(self.flags))]
 		writer.simpletag("component", attrs)
 		writer.newline()
@@ -1407,17 +1384,17 @@
 			self.x = safeEval(attrs["x"])
 			self.y = safeEval(attrs["y"])
 		if "scale01" in attrs:
-			scalex = str2fl(attrs["scalex"], 14)
-			scale01 = str2fl(attrs["scale01"], 14)
-			scale10 = str2fl(attrs["scale10"], 14)
-			scaley = str2fl(attrs["scaley"], 14)
+			scalex = safeEval(attrs["scalex"])
+			scale01 = safeEval(attrs["scale01"])
+			scale10 = safeEval(attrs["scale10"])
+			scaley = safeEval(attrs["scaley"])
 			self.transform = [[scalex, scale01], [scale10, scaley]]
 		elif "scalex" in attrs:
-			scalex = str2fl(attrs["scalex"], 14)
-			scaley = str2fl(attrs["scaley"], 14)
+			scalex = safeEval(attrs["scalex"])
+			scaley = safeEval(attrs["scaley"])
 			self.transform = [[scalex, 0], [0, scaley]]
 		elif "scale" in attrs:
-			scale = str2fl(attrs["scale"], 14)
+			scale = safeEval(attrs["scale"])
 			self.transform = [[scale, 0], [0, scale]]
 		self.flags = safeEval(attrs["flags"])
 
@@ -1506,12 +1483,12 @@
 			p = self._checkFloat(p)
 			self._a.extend(p)
 
-	def toInt(self, *, round=otRound):
+	def toInt(self):
 		if not self.isFloat():
 			return
 		a = array.array("h")
 		for n in self._a:
-			a.append(round(n))
+			a.append(otRound(n))
 		self._a = a
 
 	def relativeToAbsolute(self):
@@ -1626,9 +1603,13 @@
 		for i in range(len(a)):
 			a[i] = -a[i]
 		return r
-	def __round__(self, *, round=otRound):
+	def __round__(self):
+		"""
+		Note: This is Python 3 only.  Python 2 does not call __round__.
+		As such, we cannot test this method either. :(
+		"""
 		r = self.copy()
-		r.toInt(round=round)
+		r.toInt()
 		return r
 
 	def __add__(self, other): return self.copy().__iadd__(other)
diff --git a/Lib/fontTools/ttLib/tables/_g_v_a_r.py b/Lib/fontTools/ttLib/tables/_g_v_a_r.py
index 8c9b530..7a02f8f 100644
--- a/Lib/fontTools/ttLib/tables/_g_v_a_r.py
+++ b/Lib/fontTools/ttLib/tables/_g_v_a_r.py
@@ -1,6 +1,9 @@
-from fontTools.misc.py23 import bytesjoin
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools import ttLib
 from fontTools.misc import sstruct
 from fontTools.misc.textTools import safeEval
+from fontTools.ttLib import TTLibError
 from . import DefaultTable
 import array
 import itertools
@@ -124,7 +127,7 @@
 			# Long format: array of UInt32
 			offsets = array.array("I")
 			offsetsSize = (glyphCount + 1) * 4
-		offsets.frombytes(data[0 : offsetsSize])
+		offsets.fromstring(data[0 : offsetsSize])
 		if sys.byteorder != "big": offsets.byteswap()
 
 		# In the short format, offsets need to be multiplied by 2.
@@ -156,7 +159,7 @@
 			packed = array.array("I", offsets)
 			tableFormat = 1
 		if sys.byteorder != "big": packed.byteswap()
-		return (packed.tobytes(), tableFormat)
+		return (packed.tostring(), tableFormat)
 
 	def toXML(self, writer, ttFont):
 		writer.simpletag("version", value=self.version)
@@ -164,7 +167,7 @@
 		writer.simpletag("reserved", value=self.reserved)
 		writer.newline()
 		axisTags = [axis.axisTag for axis in ttFont["fvar"].axes]
-		for glyphName in ttFont.getGlyphNames():
+		for glyphName in ttFont.getGlyphOrder():
 			variations = self.variations.get(glyphName)
 			if not variations:
 				continue
diff --git a/Lib/fontTools/ttLib/tables/_h_d_m_x.py b/Lib/fontTools/ttLib/tables/_h_d_m_x.py
index 954d1bc..e073325 100644
--- a/Lib/fontTools/ttLib/tables/_h_d_m_x.py
+++ b/Lib/fontTools/ttLib/tables/_h_d_m_x.py
@@ -1,8 +1,8 @@
-from fontTools.misc.py23 import bytechr, byteord, strjoin
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from . import DefaultTable
 import array
-from collections.abc import Mapping
 
 hdmxHeaderFormat = """
 	>   # big endian!
@@ -11,6 +11,11 @@
 	recordSize:	l
 """
 
+try:
+	from collections.abc import Mapping
+except:
+	from UserDict import DictMixin as Mapping
+
 class _GlyphnamedList(Mapping):
 
 	def __init__(self, reverseGlyphOrder, data):
diff --git a/Lib/fontTools/ttLib/tables/_h_e_a_d.py b/Lib/fontTools/ttLib/tables/_h_e_a_d.py
index 4d19da0..42fbb1d 100644
--- a/Lib/fontTools/ttLib/tables/_h_e_a_d.py
+++ b/Lib/fontTools/ttLib/tables/_h_e_a_d.py
@@ -1,9 +1,10 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
-from fontTools.misc.fixedTools import floatToFixedToStr, strToFixedToFloat
 from fontTools.misc.textTools import safeEval, num2binary, binary2num
 from fontTools.misc.timeTools import timestampFromString, timestampToString, timestampNow
 from fontTools.misc.timeTools import epoch_diff as mac_epoch_diff # For backward compat
-from fontTools.misc.arrayTools import intRect, unionRect
+from fontTools.misc.arrayTools import intRect
 from . import DefaultTable
 import logging
 
@@ -33,14 +34,14 @@
 
 class table__h_e_a_d(DefaultTable.DefaultTable):
 
-	dependencies = ['maxp', 'loca', 'CFF ', 'CFF2']
+	dependencies = ['maxp', 'loca', 'CFF ']
 
 	def decompile(self, data, ttFont):
 		dummy, rest = sstruct.unpack2(headFormat, data, self)
 		if rest:
 			# this is quite illegal, but there seem to be fonts out there that do this
 			log.warning("extra bytes at the end of 'head' table")
-			assert rest == b"\0\0"
+			assert rest == "\0\0"
 
 		# For timestamp fields, ignore the top four bytes.  Some fonts have
 		# bogus values there.  Since till 2038 those bytes only can be zero,
@@ -64,19 +65,6 @@
 			if 'CFF ' in ttFont:
 				topDict = ttFont['CFF '].cff.topDictIndex[0]
 				self.xMin, self.yMin, self.xMax, self.yMax = intRect(topDict.FontBBox)
-			elif 'CFF2' in ttFont:
-				topDict = ttFont['CFF2'].cff.topDictIndex[0]
-				charStrings = topDict.CharStrings
-				fontBBox = None
-				for charString in charStrings.values():
-					bounds = charString.calcBounds(charStrings)
-					if bounds is not None:
-						if fontBBox is not None:
-							fontBBox = unionRect(fontBBox, bounds)
-						else:
-							fontBBox = bounds
-				if fontBBox is not None:
-					self.xMin, self.yMin, self.xMax, self.yMax = intRect(fontBBox)
 		if ttFont.recalcTimestamp:
 			self.modified = timestampNow()
 		data = sstruct.pack(headFormat, self)
@@ -85,14 +73,12 @@
 	def toXML(self, writer, ttFont):
 		writer.comment("Most of this table will be recalculated by the compiler")
 		writer.newline()
-		_, names, fixes = sstruct.getformat(headFormat)
+		formatstring, names, fixes = sstruct.getformat(headFormat)
 		for name in names:
 			value = getattr(self, name)
-			if name in fixes:
-				value = floatToFixedToStr(value, precisionBits=fixes[name])
-			elif name in ("created", "modified"):
+			if name in ("created", "modified"):
 				value = timestampToString(value)
-			elif name in ("magicNumber", "checkSumAdjustment"):
+			if name in ("magicNumber", "checkSumAdjustment"):
 				if value < 0:
 					value = value + 0x100000000
 				value = hex(value)
@@ -105,10 +91,7 @@
 
 	def fromXML(self, name, attrs, content, ttFont):
 		value = attrs["value"]
-		fixes = sstruct.getformat(headFormat)[2]
-		if name in fixes:
-			value = strToFixedToFloat(value, precisionBits=fixes[name])
-		elif name in ("created", "modified"):
+		if name in ("created", "modified"):
 			value = timestampFromString(value)
 		elif name in ("macStyle", "flags"):
 			value = binary2num(value)
diff --git a/Lib/fontTools/ttLib/tables/_h_h_e_a.py b/Lib/fontTools/ttLib/tables/_h_h_e_a.py
index 9b8baaa..bde9073 100644
--- a/Lib/fontTools/ttLib/tables/_h_h_e_a.py
+++ b/Lib/fontTools/ttLib/tables/_h_h_e_a.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from fontTools.misc.textTools import safeEval
 from fontTools.misc.fixedTools import (
@@ -32,26 +34,13 @@
 
 	# Note: Keep in sync with table__v_h_e_a
 
-	dependencies = ['hmtx', 'glyf', 'CFF ', 'CFF2']
-
-	# OpenType spec renamed these, add aliases for compatibility
-	@property
-	def ascender(self): return self.ascent
-
-	@ascender.setter
-	def ascender(self,value): self.ascent = value
-
-	@property
-	def descender(self): return self.descent
-
-	@descender.setter
-	def descender(self,value): self.descent = value
+	dependencies = ['hmtx', 'glyf', 'CFF ']
 
 	def decompile(self, data, ttFont):
 		sstruct.unpack(hheaFormat, data, self)
 
 	def compile(self, ttFont):
-		if ttFont.recalcBBoxes and (ttFont.isLoaded('glyf') or ttFont.isLoaded('CFF ') or ttFont.isLoaded('CFF2')):
+		if ttFont.recalcBBoxes and (ttFont.isLoaded('glyf') or ttFont.isLoaded('CFF ')):
 			self.recalc(ttFont)
 		self.tableVersion = fi2ve(self.tableVersion)
 		return sstruct.pack(hheaFormat, self)
@@ -73,11 +62,8 @@
 					# Calculate those.
 					g.recalcBounds(glyfTable)
 				boundsWidthDict[name] = g.xMax - g.xMin
-		elif 'CFF ' in ttFont or 'CFF2' in ttFont:
-			if 'CFF ' in ttFont:
-				topDict = ttFont['CFF '].cff.topDictIndex[0]
-			else:
-				topDict = ttFont['CFF2'].cff.topDictIndex[0]
+		elif 'CFF ' in ttFont:
+			topDict = ttFont['CFF '].cff.topDictIndex[0]
 			charStrings = topDict.CharStrings
 			for name in ttFont.getGlyphOrder():
 				cs = charStrings[name]
diff --git a/Lib/fontTools/ttLib/tables/_h_m_t_x.py b/Lib/fontTools/ttLib/tables/_h_m_t_x.py
index 6980b8d..24cad4f 100644
--- a/Lib/fontTools/ttLib/tables/_h_m_t_x.py
+++ b/Lib/fontTools/ttLib/tables/_h_m_t_x.py
@@ -1,4 +1,6 @@
-from fontTools.misc.roundTools import otRound
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools.misc.fixedTools import otRound
 from fontTools import ttLib
 from fontTools.misc.textTools import safeEval
 from . import DefaultTable
@@ -107,7 +109,7 @@
 				raise
 		additionalMetrics = array.array("h", additionalMetrics)
 		if sys.byteorder != "big": additionalMetrics.byteswap()
-		data = data + additionalMetrics.tobytes()
+		data = data + additionalMetrics.tostring()
 		return data
 
 	def toXML(self, writer, ttFont):
diff --git a/Lib/fontTools/ttLib/tables/_k_e_r_n.py b/Lib/fontTools/ttLib/tables/_k_e_r_n.py
index f3f714b..1e5140b 100644
--- a/Lib/fontTools/ttLib/tables/_k_e_r_n.py
+++ b/Lib/fontTools/ttLib/tables/_k_e_r_n.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.ttLib import getSearchRange
 from fontTools.misc.textTools import safeEval, readHex
 from fontTools.misc.fixedTools import (
diff --git a/Lib/fontTools/ttLib/tables/_l_c_a_r.py b/Lib/fontTools/ttLib/tables/_l_c_a_r.py
index e63310e..4b9c854 100644
--- a/Lib/fontTools/ttLib/tables/_l_c_a_r.py
+++ b/Lib/fontTools/ttLib/tables/_l_c_a_r.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .otBase import BaseTTXConverter
 
 
diff --git a/Lib/fontTools/ttLib/tables/_l_o_c_a.py b/Lib/fontTools/ttLib/tables/_l_o_c_a.py
index 6a8693e..6aa5303 100644
--- a/Lib/fontTools/ttLib/tables/_l_o_c_a.py
+++ b/Lib/fontTools/ttLib/tables/_l_o_c_a.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from . import DefaultTable
 import sys
 import array
@@ -18,7 +20,7 @@
 		else:
 			format = "H"
 		locations = array.array(format)
-		locations.frombytes(data)
+		locations.fromstring(data)
 		if sys.byteorder != "big": locations.byteswap()
 		if not longFormat:
 			l = array.array("I")
@@ -45,7 +47,7 @@
 			locations = array.array("I", self.locations)
 			ttFont['head'].indexToLocFormat = 1
 		if sys.byteorder != "big": locations.byteswap()
-		return locations.tobytes()
+		return locations.tostring()
 
 	def set(self, locations):
 		self.locations = array.array("I", locations)
diff --git a/Lib/fontTools/ttLib/tables/_l_t_a_g.py b/Lib/fontTools/ttLib/tables/_l_t_a_g.py
index caec72a..59f8e72 100644
--- a/Lib/fontTools/ttLib/tables/_l_t_a_g.py
+++ b/Lib/fontTools/ttLib/tables/_l_t_a_g.py
@@ -1,4 +1,5 @@
-from fontTools.misc.py23 import bytesjoin, tobytes
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.textTools import safeEval
 from . import DefaultTable
 import struct
diff --git a/Lib/fontTools/ttLib/tables/_m_a_x_p.py b/Lib/fontTools/ttLib/tables/_m_a_x_p.py
index e810806..7da30b4 100644
--- a/Lib/fontTools/ttLib/tables/_m_a_x_p.py
+++ b/Lib/fontTools/ttLib/tables/_m_a_x_p.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from fontTools.misc.textTools import safeEval
 from . import DefaultTable
diff --git a/Lib/fontTools/ttLib/tables/_m_e_t_a.py b/Lib/fontTools/ttLib/tables/_m_e_t_a.py
index 1a125f8..cc19fe6 100644
--- a/Lib/fontTools/ttLib/tables/_m_e_t_a.py
+++ b/Lib/fontTools/ttLib/tables/_m_e_t_a.py
@@ -1,4 +1,5 @@
-from fontTools.misc.py23 import bytesjoin, strjoin
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from fontTools.misc.textTools import readHex
 from fontTools.ttLib import TTLibError
@@ -85,11 +86,7 @@
             else:
                 writer.begintag("hexdata", tag=tag)
                 writer.newline()
-                data = self.data[tag]
-                if min(data) >= 0x20 and max(data) <= 0x7E:
-                    writer.comment("ascii: " + data.decode("ascii"))
-                    writer.newline()
-                writer.dumphex(data)
+                writer.dumphex(self.data[tag])
                 writer.endtag("hexdata")
                 writer.newline()
 
diff --git a/Lib/fontTools/ttLib/tables/_m_o_r_t.py b/Lib/fontTools/ttLib/tables/_m_o_r_t.py
index 261e593..b87b425 100644
--- a/Lib/fontTools/ttLib/tables/_m_o_r_t.py
+++ b/Lib/fontTools/ttLib/tables/_m_o_r_t.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .otBase import BaseTTXConverter
 
 
diff --git a/Lib/fontTools/ttLib/tables/_m_o_r_x.py b/Lib/fontTools/ttLib/tables/_m_o_r_x.py
index da299c6..1619d8d 100644
--- a/Lib/fontTools/ttLib/tables/_m_o_r_x.py
+++ b/Lib/fontTools/ttLib/tables/_m_o_r_x.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .otBase import BaseTTXConverter
 
 
diff --git a/Lib/fontTools/ttLib/tables/_n_a_m_e.py b/Lib/fontTools/ttLib/tables/_n_a_m_e.py
index 206469d..488c4ea 100644
--- a/Lib/fontTools/ttLib/tables/_n_a_m_e.py
+++ b/Lib/fontTools/ttLib/tables/_n_a_m_e.py
@@ -1,5 +1,7 @@
 # -*- coding: utf-8 -*-
-from fontTools.misc.py23 import bytechr, byteord, bytesjoin, strjoin, tobytes, tostr
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from fontTools.misc.textTools import safeEval
 from fontTools.misc.encodingTools import getEncoding
@@ -133,7 +135,7 @@
 		"""
 		if not hasattr(self, 'names'):
 			self.names = []
-		if not isinstance(string, str):
+		if not isinstance(string, unicode):
 			if isinstance(string, bytes):
 				log.warning(
 					"name string is bytes, ensure it's correctly encoded: %r", string)
@@ -147,31 +149,6 @@
 		else:
 			self.names.append(makeName(string, nameID, platformID, platEncID, langID))
 
-	def removeNames(self, nameID=None, platformID=None, platEncID=None, langID=None):
-		"""Remove any name records identified by the given combination of 'nameID',
-		'platformID', 'platEncID' and 'langID'.
-		"""
-		args = {
-			argName: argValue
-			for argName, argValue in (
-				("nameID", nameID),
-				("platformID", platformID),
-				("platEncID", platEncID),
-				("langID", langID),
-			)
-			if argValue is not None
-		}
-		if not args:
-			# no arguments, nothing to do
-			return
-		self.names = [
-			rec for rec in self.names
-			if any(
-				argValue != getattr(rec, argName)
-				for argName, argValue in args.items()
-			)
-		]
-
 	def _findUnusedNameID(self, minNameID=256):
 		"""Finds an unused name id.
 
@@ -184,65 +161,8 @@
 			raise ValueError("nameID must be less than 32768")
 		return nameID
 
-	def findMultilingualName(self, names, windows=True, mac=True, minNameID=0):
-		"""Return the name ID of an existing multilingual name that
-		matches the 'names' dictionary, or None if not found.
-
-		'names' is a dictionary with the name in multiple languages,
-		such as {'en': 'Pale', 'de': 'Blaß', 'de-CH': 'Blass'}.
-		The keys can be arbitrary IETF BCP 47 language codes;
-		the values are Unicode strings.
-
-		If 'windows' is True, the returned name ID is guaranteed
-		exist for all requested languages for platformID=3 and
-		platEncID=1.
-		If 'mac' is True, the returned name ID is guaranteed to exist
-		for all requested languages for platformID=1 and platEncID=0.
-
-		The returned name ID will not be less than the 'minNameID'
-		argument.
-		"""
-		# Gather the set of requested
-		#   (string, platformID, platEncID, langID)
-		# tuples
-		reqNameSet = set()
-		for lang, name in sorted(names.items()):
-			if windows:
-				windowsName = _makeWindowsName(name, None, lang)
-				if windowsName is not None:
-					reqNameSet.add((windowsName.string,
-					                windowsName.platformID,
-					                windowsName.platEncID,
-					                windowsName.langID))
-			if mac:
-				macName = _makeMacName(name, None, lang)
-				if macName is not None:
-					reqNameSet.add((macName.string,
-				                    macName.platformID,
-				                    macName.platEncID,
-				                    macName.langID))
-
-		# Collect matching name IDs
-		matchingNames = dict()
-		for name in self.names:
-			try:
-				key = (name.toUnicode(), name.platformID,
-				       name.platEncID, name.langID)
-			except UnicodeDecodeError:
-				continue
-			if key in reqNameSet and name.nameID >= minNameID:
-				nameSet = matchingNames.setdefault(name.nameID, set())
-				nameSet.add(key)
-
-		# Return the first name ID that defines all requested strings
-		for nameID, nameSet in sorted(matchingNames.items()):
-			if nameSet == reqNameSet:
-				return nameID
-
-		return None  # not found
-
 	def addMultilingualName(self, names, ttFont=None, nameID=None,
-	                        windows=True, mac=True, minNameID=0):
+	                        windows=True, mac=True):
 		"""Add a multilingual name, returning its name ID
 
 		'names' is a dictionary with the name in multiple languages,
@@ -256,23 +176,14 @@
 		names that otherwise cannot get encoded at all.
 
 		'nameID' is the name ID to be used, or None to let the library
-		find an existing set of name records that match, or pick an
-		unused name ID.
+		pick an unused name ID.
 
 		If 'windows' is True, a platformID=3 name record will be added.
 		If 'mac' is True, a platformID=1 name record will be added.
-
-		If the 'nameID' argument is None, the created nameID will not
-		be less than the 'minNameID' argument.
 		"""
 		if not hasattr(self, 'names'):
 			self.names = []
 		if nameID is None:
-			# Reuse nameID if possible
-			nameID = self.findMultilingualName(
-				names, windows=windows, mac=mac, minNameID=minNameID)
-			if nameID is not None:
-				return nameID
 			nameID = self._findUnusedNameID()
 		# TODO: Should minimize BCP 47 language codes.
 		# https://github.com/fonttools/fonttools/issues/930
@@ -310,9 +221,10 @@
 			"'platforms' must contain at least one (platformID, platEncID, langID) tuple"
 		if not hasattr(self, 'names'):
 			self.names = []
-		if not isinstance(string, str):
+		if not isinstance(string, unicode):
 			raise TypeError(
-				"expected str, found %s: %r" % (type(string).__name__, string))
+				"expected %s, found %s: %r" % (
+					unicode.__name__, type(string).__name__,string ))
 		nameID = self._findUnusedNameID(minNameID + 1)
 		for platformID, platEncID, langID in platforms:
 			self.names.append(makeName(string, nameID, platformID, platEncID, langID))
@@ -440,7 +352,7 @@
 		encoding = self.getEncoding()
 		string = self.string
 
-		if isinstance(string, bytes) and encoding == 'utf_16_be' and len(string) % 2 == 1:
+		if encoding == 'utf_16_be' and len(string) % 2 == 1:
 			# Recover badly encoded UTF-16 strings that have an odd number of bytes:
 			# - If the last byte is zero, drop it.  Otherwise,
 			# - If all the odd bytes are zero and all the even bytes are ASCII,
@@ -456,7 +368,7 @@
 			elif byteord(string[0]) == 0 and all(isascii(byteord(b)) for b in string[1:]):
 				string = bytesjoin(b'\0'+bytechr(byteord(b)) for b in string[1:])
 
-		string = tostr(string, encoding=encoding, errors=errors)
+		string = tounicode(string, encoding=encoding, errors=errors)
 
 		# If decoded strings still looks like UTF-16BE, it suggests a double-encoding.
 		# Fix it up.
@@ -480,7 +392,13 @@
 		"""
 		return tobytes(self.string, encoding=self.getEncoding(), errors=errors)
 
-	toStr = toUnicode
+	def toStr(self, errors='strict'):
+		if str == bytes:
+			# python 2
+			return self.toBytes(errors)
+		else:
+			# python 3
+			return self.toUnicode(errors)
 
 	def toXML(self, writer, ttFont):
 		try:
@@ -524,32 +442,22 @@
 		if type(self) != type(other):
 			return NotImplemented
 
-		try:
-			# implemented so that list.sort() sorts according to the spec.
-			selfTuple = (
-				self.platformID,
-				self.platEncID,
-				self.langID,
-				self.nameID,
-				self.toBytes(),
-			)
-			otherTuple = (
-				other.platformID,
-				other.platEncID,
-				other.langID,
-				other.nameID,
-				other.toBytes(),
-			)
-			return selfTuple < otherTuple
-		except (UnicodeEncodeError, AttributeError):
-			# This can only happen for
-			# 1) an object that is not a NameRecord, or
-			# 2) an unlikely incomplete NameRecord object which has not been
-			#    fully populated, or
-			# 3) when all IDs are identical but the strings can't be encoded
-			#    for their platform encoding.
-			# In all cases it is best to return NotImplemented.
-			return NotImplemented
+		# implemented so that list.sort() sorts according to the spec.
+		selfTuple = (
+			getattr(self, "platformID", None),
+			getattr(self, "platEncID", None),
+			getattr(self, "langID", None),
+			getattr(self, "nameID", None),
+			getattr(self, "string", None),
+		)
+		otherTuple = (
+			getattr(other, "platformID", None),
+			getattr(other, "platEncID", None),
+			getattr(other, "langID", None),
+			getattr(other, "nameID", None),
+			getattr(other, "string", None),
+		)
+		return selfTuple < otherTuple
 
 	def __repr__(self):
 		return "<NameRecord NameID=%d; PlatformID=%d; LanguageID=%d>" % (
diff --git a/Lib/fontTools/ttLib/tables/_o_p_b_d.py b/Lib/fontTools/ttLib/tables/_o_p_b_d.py
index b22af21..60bb6c5 100644
--- a/Lib/fontTools/ttLib/tables/_o_p_b_d.py
+++ b/Lib/fontTools/ttLib/tables/_o_p_b_d.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .otBase import BaseTTXConverter
 
 
diff --git a/Lib/fontTools/ttLib/tables/_p_o_s_t.py b/Lib/fontTools/ttLib/tables/_p_o_s_t.py
index e26e81f..4874ecd 100644
--- a/Lib/fontTools/ttLib/tables/_p_o_s_t.py
+++ b/Lib/fontTools/ttLib/tables/_p_o_s_t.py
@@ -1,4 +1,5 @@
-from fontTools.misc.py23 import bytechr, byteord, tobytes, tostr
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools import ttLib
 from fontTools.ttLib.standardGlyphOrder import standardGlyphOrder
 from fontTools.misc import sstruct
@@ -82,7 +83,7 @@
 			numGlyphs = ttFont['maxp'].numGlyphs
 		data = data[2:]
 		indices = array.array("H")
-		indices.frombytes(data[:2*numGlyphs])
+		indices.fromstring(data[:2*numGlyphs])
 		if sys.byteorder != "big": indices.byteswap()
 		data = data[2*numGlyphs:]
 		self.extraNames = extraNames = unpackPStrings(data)
@@ -131,7 +132,7 @@
 		from fontTools import agl
 		numGlyphs = ttFont['maxp'].numGlyphs
 		indices = array.array("H")
-		indices.frombytes(data)
+		indices.fromstring(data)
 		if sys.byteorder != "big": indices.byteswap()
 		# In some older fonts, the size of the post table doesn't match
 		# the number of glyphs. Sometimes it's bigger, sometimes smaller.
@@ -171,7 +172,7 @@
 				extraNames.append(psName)
 			indices.append(index)
 		if sys.byteorder != "big": indices.byteswap()
-		return struct.pack(">H", numGlyphs) + indices.tobytes() + packPStrings(extraNames)
+		return struct.pack(">H", numGlyphs) + indices.tostring() + packPStrings(extraNames)
 
 	def encode_format_4_0(self, ttFont):
 		from fontTools import agl
@@ -188,7 +189,7 @@
 			else:
 				indices.append(0xFFFF)
 		if sys.byteorder != "big": indices.byteswap()
-		return indices.tobytes()
+		return indices.tostring()
 
 	def toXML(self, writer, ttFont):
 		formatstring, names, fixes = sstruct.getformat(postFormat)
diff --git a/Lib/fontTools/ttLib/tables/_p_r_e_p.py b/Lib/fontTools/ttLib/tables/_p_r_e_p.py
index 7f517fb..f4e8925 100644
--- a/Lib/fontTools/ttLib/tables/_p_r_e_p.py
+++ b/Lib/fontTools/ttLib/tables/_p_r_e_p.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools import ttLib
 
 superclass = ttLib.getTableClass("fpgm")
diff --git a/Lib/fontTools/ttLib/tables/_p_r_o_p.py b/Lib/fontTools/ttLib/tables/_p_r_o_p.py
index aead9d7..7da18ea 100644
--- a/Lib/fontTools/ttLib/tables/_p_r_o_p.py
+++ b/Lib/fontTools/ttLib/tables/_p_r_o_p.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .otBase import BaseTTXConverter
 
 
diff --git a/Lib/fontTools/ttLib/tables/_s_b_i_x.py b/Lib/fontTools/ttLib/tables/_s_b_i_x.py
index c4b2ad3..6efd1f2 100644
--- a/Lib/fontTools/ttLib/tables/_s_b_i_x.py
+++ b/Lib/fontTools/ttLib/tables/_s_b_i_x.py
@@ -1,7 +1,10 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from fontTools.misc.textTools import safeEval, num2binary, binary2num
 from . import DefaultTable
-from .sbixStrike import Strike
+from .sbixGlyph import *
+from .sbixStrike import *
 
 
 sbixHeaderFormat = """
diff --git a/Lib/fontTools/ttLib/tables/_t_r_a_k.py b/Lib/fontTools/ttLib/tables/_t_r_a_k.py
index 7f3227d..b5820b2 100644
--- a/Lib/fontTools/ttLib/tables/_t_r_a_k.py
+++ b/Lib/fontTools/ttLib/tables/_t_r_a_k.py
@@ -1,16 +1,15 @@
-from fontTools.misc.py23 import bytesjoin
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
-from fontTools.misc.fixedTools import (
-	fixedToFloat as fi2fl,
-	floatToFixed as fl2fi,
-	floatToFixedToStr as fl2str,
-	strToFixedToFloat as str2fl,
-)
+from fontTools.misc.fixedTools import fixedToFloat as fi2fl, floatToFixed as fl2fi
 from fontTools.misc.textTools import safeEval
 from fontTools.ttLib import TTLibError
 from . import DefaultTable
 import struct
-from collections.abc import MutableMapping
+try:
+	from collections.abc import MutableMapping
+except ImportError:
+	from UserDict import DictMixin as MutableMapping
 
 
 # Apple's documentation of 'trak':
@@ -259,19 +258,19 @@
 		name = ttFont["name"].getDebugName(self.nameIndex)
 		writer.begintag(
 			"trackEntry",
-			(('value', fl2str(self.track, 16)), ('nameIndex', self.nameIndex)))
+			(('value', self.track), ('nameIndex', self.nameIndex)))
 		writer.newline()
 		if name:
 			writer.comment(name)
 			writer.newline()
 		for size, perSizeValue in sorted(self.items()):
-			writer.simpletag("track", size=fl2str(size, 16), value=perSizeValue)
+			writer.simpletag("track", size=size, value=perSizeValue)
 			writer.newline()
 		writer.endtag("trackEntry")
 		writer.newline()
 
 	def fromXML(self, name, attrs, content, ttFont):
-		self.track = str2fl(attrs['value'], 16)
+		self.track = safeEval(attrs['value'])
 		self.nameIndex = safeEval(attrs['nameIndex'])
 		for element in content:
 			if not isinstance(element, tuple):
@@ -279,7 +278,7 @@
 			name, attrs, _ = element
 			if name != 'track':
 				continue
-			size = str2fl(attrs['size'], 16)
+			size = safeEval(attrs['size'])
 			self[size] = safeEval(attrs['value'])
 
 	def __getitem__(self, size):
diff --git a/Lib/fontTools/ttLib/tables/_v_h_e_a.py b/Lib/fontTools/ttLib/tables/_v_h_e_a.py
index 2bb2466..312c5ec 100644
--- a/Lib/fontTools/ttLib/tables/_v_h_e_a.py
+++ b/Lib/fontTools/ttLib/tables/_v_h_e_a.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from fontTools.misc.textTools import safeEval
 from fontTools.misc.fixedTools import (
@@ -31,13 +33,13 @@
 
 	# Note: Keep in sync with table__h_h_e_a
 
-	dependencies = ['vmtx', 'glyf', 'CFF ', 'CFF2']
+	dependencies = ['vmtx', 'glyf', 'CFF ']
 
 	def decompile(self, data, ttFont):
 		sstruct.unpack(vheaFormat, data, self)
 
 	def compile(self, ttFont):
-		if ttFont.recalcBBoxes and (ttFont.isLoaded('glyf') or ttFont.isLoaded('CFF ') or ttFont.isLoaded('CFF2')):
+		if ttFont.recalcBBoxes and (ttFont.isLoaded('glyf') or ttFont.isLoaded('CFF ')):
 			self.recalc(ttFont)
 		self.tableVersion = fi2ve(self.tableVersion)
 		return sstruct.pack(vheaFormat, self)
@@ -59,11 +61,8 @@
 					# Calculate those.
 					g.recalcBounds(glyfTable)
 				boundsHeightDict[name] = g.yMax - g.yMin
-		elif 'CFF ' in ttFont or 'CFF2' in ttFont:
-			if 'CFF ' in ttFont:
-				topDict = ttFont['CFF '].cff.topDictIndex[0]
-			else:
-				topDict = ttFont['CFF2'].cff.topDictIndex[0]
+		elif 'CFF ' in ttFont:
+			topDict = ttFont['CFF '].cff.topDictIndex[0]
 			charStrings = topDict.CharStrings
 			for name in ttFont.getGlyphOrder():
 				cs = charStrings[name]
diff --git a/Lib/fontTools/ttLib/tables/_v_m_t_x.py b/Lib/fontTools/ttLib/tables/_v_m_t_x.py
index fc818d8..5573225 100644
--- a/Lib/fontTools/ttLib/tables/_v_m_t_x.py
+++ b/Lib/fontTools/ttLib/tables/_v_m_t_x.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools import ttLib
 
 superclass = ttLib.getTableClass("hmtx")
diff --git a/Lib/fontTools/ttLib/tables/asciiTable.py b/Lib/fontTools/ttLib/tables/asciiTable.py
index 7b036c8..87266a0 100644
--- a/Lib/fontTools/ttLib/tables/asciiTable.py
+++ b/Lib/fontTools/ttLib/tables/asciiTable.py
@@ -1,4 +1,5 @@
-from fontTools.misc.py23 import strjoin, tobytes, tostr
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from . import DefaultTable
 
 
diff --git a/Lib/fontTools/ttLib/tables/otBase.py b/Lib/fontTools/ttLib/tables/otBase.py
index 3c07f9e..816f1cd 100644
--- a/Lib/fontTools/ttLib/tables/otBase.py
+++ b/Lib/fontTools/ttLib/tables/otBase.py
@@ -1,4 +1,5 @@
-from fontTools.misc.py23 import Tag, bytesjoin
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from .DefaultTable import DefaultTable
 import sys
 import array
@@ -134,38 +135,48 @@
 		offset = self.offset + offset
 		return self.__class__(self.data, self.localState, offset, self.tableTag)
 
-	def readValue(self, typecode, staticSize):
-		pos = self.pos
-		newpos = pos + staticSize
-		value, = struct.unpack(f">{typecode}", self.data[pos:newpos])
-		self.pos = newpos
-		return value
-
 	def readUShort(self):
-		return self.readValue("H", staticSize=2)
-
-	def readArray(self, typecode, staticSize, count):
 		pos = self.pos
-		newpos = pos + count * staticSize
-		value = array.array(typecode, self.data[pos:newpos])
-		if sys.byteorder != "big": value.byteswap()
+		newpos = pos + 2
+		value, = struct.unpack(">H", self.data[pos:newpos])
 		self.pos = newpos
 		return value
 
 	def readUShortArray(self, count):
-		return self.readArray("H", staticSize=2, count=count)
+		pos = self.pos
+		newpos = pos + count * 2
+		value = array.array("H", self.data[pos:newpos])
+		if sys.byteorder != "big": value.byteswap()
+		self.pos = newpos
+		return value
 
 	def readInt8(self):
-		return self.readValue("b", staticSize=1)
+		pos = self.pos
+		newpos = pos + 1
+		value, = struct.unpack(">b", self.data[pos:newpos])
+		self.pos = newpos
+		return value
 
 	def readShort(self):
-		return self.readValue("h", staticSize=2)
+		pos = self.pos
+		newpos = pos + 2
+		value, = struct.unpack(">h", self.data[pos:newpos])
+		self.pos = newpos
+		return value
 
 	def readLong(self):
-		return self.readValue("l", staticSize=4)
+		pos = self.pos
+		newpos = pos + 4
+		value, = struct.unpack(">l", self.data[pos:newpos])
+		self.pos = newpos
+		return value
 
 	def readUInt8(self):
-		return self.readValue("B", staticSize=1)
+		pos = self.pos
+		newpos = pos + 1
+		value, = struct.unpack(">B", self.data[pos:newpos])
+		self.pos = newpos
+		return value
 
 	def readUInt24(self):
 		pos = self.pos
@@ -175,7 +186,11 @@
 		return value
 
 	def readULong(self):
-		return self.readValue("L", staticSize=4)
+		pos = self.pos
+		newpos = pos + 4
+		value, = struct.unpack(">L", self.data[pos:newpos])
+		self.pos = newpos
+		return value
 
 	def readTag(self):
 		pos = self.pos
@@ -208,24 +223,14 @@
 
 	"""Helper class to gather and assemble data for OpenType tables."""
 
-	def __init__(self, localState=None, tableTag=None, offsetSize=2):
+	def __init__(self, localState=None, tableTag=None):
 		self.items = []
 		self.pos = None
 		self.localState = localState
 		self.tableTag = tableTag
-		self.offsetSize = offsetSize
+		self.longOffset = False
 		self.parent = None
 
-	# DEPRECATED: 'longOffset' is kept as a property for backward compat with old code.
-	# You should use 'offsetSize' instead (2, 3 or 4 bytes).
-	@property
-	def longOffset(self):
-		return self.offsetSize == 4
-
-	@longOffset.setter
-	def longOffset(self, value):
-		self.offsetSize = 4 if value else 2
-
 	def __setitem__(self, name, value):
 		state = self.localState.copy() if self.localState else dict()
 		state[name] = value
@@ -246,7 +251,7 @@
 			if hasattr(item, "getCountData"):
 				l += item.size
 			elif hasattr(item, "getData"):
-				l += item.offsetSize
+				l += 4 if item.longOffset else 2
 			else:
 				l = l + len(item)
 		return l
@@ -260,9 +265,9 @@
 			item = items[i]
 
 			if hasattr(item, "getData"):
-				if item.offsetSize == 4:
+				if item.longOffset:
 					items[i] = packULong(item.pos - pos)
-				elif item.offsetSize == 2:
+				else:
 					try:
 						items[i] = packUShort(item.pos - pos)
 					except struct.error:
@@ -270,10 +275,6 @@
 						overflowErrorRecord = self.getOverflowErrorRecord(item)
 
 						raise OTLOffsetOverflowError(overflowErrorRecord)
-				elif item.offsetSize == 3:
-					items[i] = packUInt24(item.pos - pos)
-				else:
-					raise ValueError(item.offsetSize)
 
 		return bytesjoin(items)
 
@@ -288,7 +289,7 @@
 	def __eq__(self, other):
 		if type(self) != type(other):
 			return NotImplemented
-		return self.offsetSize == other.offsetSize and self.items == other.items
+		return self.longOffset == other.longOffset and self.items == other.items
 
 	def _doneWriting(self, internedTables):
 		# Convert CountData references to data string items
@@ -409,17 +410,14 @@
 
 	# interface for gathering data, as used by table.compile()
 
-	def getSubWriter(self, offsetSize=2):
-		subwriter = self.__class__(self.localState, self.tableTag, offsetSize=offsetSize)
+	def getSubWriter(self):
+		subwriter = self.__class__(self.localState, self.tableTag)
 		subwriter.parent = self # because some subtables have idential values, we discard
 					# the duplicates under the getAllData method. Hence some
 					# subtable writers can have more than one parent writer.
 					# But we just care about first one right now.
 		return subwriter
 
-	def writeValue(self, typecode, value):
-		self.items.append(struct.pack(f">{typecode}", value))
-
 	def writeUShort(self, value):
 		assert 0 <= value < 0x10000, value
 		self.items.append(struct.pack(">H", value))
@@ -516,8 +514,6 @@
 			table[name] = value
 		else:
 			assert table[name] == value, (name, table[name], value)
-	def getValue(self):
-		return self.table[self.name]
 	def getCountData(self):
 		v = self.table[self.name]
 		if v is None: v = 0
@@ -534,10 +530,6 @@
 	assert 0 <= value < 0x100000000, value
 	return struct.pack(">L", value)
 
-def packUInt24(value):
-	assert 0 <= value < 0x1000000, value
-	return struct.pack(">L", value)[1:]
-
 
 class BaseTable(object):
 
@@ -654,26 +646,11 @@
 
 	def compile(self, writer, font):
 		self.ensureDecompiled()
-		# TODO Following hack to be removed by rewriting how FormatSwitching tables
-		# are handled.
-		# https://github.com/fonttools/fonttools/pull/2238#issuecomment-805192631
 		if hasattr(self, 'preWrite'):
-			deleteFormat = not hasattr(self, 'Format')
 			table = self.preWrite(font)
-			deleteFormat = deleteFormat and hasattr(self, 'Format')
 		else:
-			deleteFormat = False
 			table = self.__dict__.copy()
 
-		# some count references may have been initialized in a custom preWrite; we set
-		# these in the writer's state beforehand (instead of sequentially) so they will
-		# be propagated to all nested subtables even if the count appears in the current
-		# table only *after* the offset to the subtable that it is counting.
-		for conv in self.getConverters():
-			if conv.isCount and conv.isPropagated:
-				value = table.get(conv.name)
-				if isinstance(value, CountReference):
-					writer[conv.name] = value
 
 		if hasattr(self, 'sortCoverageLast'):
 			writer.sortCoverageLast = 1
@@ -714,16 +691,8 @@
 				# table. We will later store it here.
 				# We add a reference: by the time the data is assembled
 				# the Count value will be filled in.
-				# We ignore the current count value since it will be recomputed,
-				# unless it's a CountReference that was already initialized in a custom preWrite.
-				if isinstance(value, CountReference):
-					ref = value
-					ref.size = conv.staticSize
-					writer.writeData(ref)
-					table[conv.name] = ref.getValue()
-				else:
-					ref = writer.writeCountReference(table, conv.name, conv.staticSize)
-					table[conv.name] = None
+				ref = writer.writeCountReference(table, conv.name, conv.staticSize)
+				table[conv.name] = None
 				if conv.isPropagated:
 					writer[conv.name] = ref
 			elif conv.isLookupType:
@@ -746,9 +715,6 @@
 				if conv.isPropagated:
 					writer[conv.name] = value
 
-		if deleteFormat:
-			del self.Format
-
 	def readFormat(self, reader):
 		pass
 
@@ -838,26 +804,6 @@
 		BaseTable.toXML(self, xmlWriter, font, attrs, name)
 
 
-class UInt8FormatSwitchingBaseTable(FormatSwitchingBaseTable):
-	def readFormat(self, reader):
-		self.Format = reader.readUInt8()
-
-	def writeFormat(self, writer):
-		writer.writeUInt8(self.Format)
-
-
-formatSwitchingBaseTables = {
-	"uint16": FormatSwitchingBaseTable,
-	"uint8": UInt8FormatSwitchingBaseTable,
-}
-
-def getFormatSwitchingBaseTableClass(formatType):
-	try:
-		return formatSwitchingBaseTables[formatType]
-	except KeyError:
-		raise TypeError(f"Unsupported format type: {formatType!r}")
-
-
 #
 # Support for ValueRecords
 #
diff --git a/Lib/fontTools/ttLib/tables/otConverters.py b/Lib/fontTools/ttLib/tables/otConverters.py
index 4af38ac..d1712db 100644
--- a/Lib/fontTools/ttLib/tables/otConverters.py
+++ b/Lib/fontTools/ttLib/tables/otConverters.py
@@ -1,22 +1,15 @@
-from fontTools.misc.py23 import bytesjoin, tobytes, tostr
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.fixedTools import (
-	fixedToFloat as fi2fl,
-	floatToFixed as fl2fi,
-	floatToFixedToStr as fl2str,
-	strToFixedToFloat as str2fl,
-	ensureVersionIsLong as fi2ve,
-	versionToFixed as ve2fi,
-)
+	fixedToFloat as fi2fl, floatToFixed as fl2fi, ensureVersionIsLong as fi2ve,
+	versionToFixed as ve2fi)
 from fontTools.misc.textTools import pad, safeEval
 from fontTools.ttLib import getSearchRange
 from .otBase import (CountReference, FormatSwitchingBaseTable,
                      OTTableReader, OTTableWriter, ValueRecordFactory)
 from .otTables import (lookupTypes, AATStateTable, AATState, AATAction,
                        ContextualMorphAction, LigatureMorphAction,
-                       InsertionMorphAction, MorxSubtable, VariableFloat,
-                       VariableInt, ExtendMode as _ExtendMode,
-                       CompositeMode as _CompositeMode)
-from itertools import zip_longest
+                       InsertionMorphAction, MorxSubtable)
 from functools import partial
 import struct
 import logging
@@ -59,20 +52,14 @@
 				converterClass = Struct
 			else:
 				converterClass = eval(tp, tableNamespace, converterMapping)
-
-		conv = converterClass(name, repeat, aux)
-
-		if conv.tableClass:
-			# A "template" such as OffsetTo(AType) knowss the table class already
-			tableClass = conv.tableClass
-		elif tp in ('MortChain', 'MortSubtable', 'MorxChain'):
+		if tp in ('MortChain', 'MortSubtable', 'MorxChain'):
 			tableClass = tableNamespace.get(tp)
 		else:
 			tableClass = tableNamespace.get(tableName)
-
-		if not conv.tableClass:
-			conv.tableClass = tableClass
-
+		if tableClass is not None:
+			conv = converterClass(name, repeat, aux, tableClass=tableClass)
+		else:
+			conv = converterClass(name, repeat, aux)
 		if name in ["SubTable", "ExtSubTable", "SubStruct"]:
 			conv.lookupTypes = tableNamespace['lookupTypes']
 			# also create reverse mapping
@@ -143,22 +130,7 @@
 		self.tableClass = tableClass
 		self.isCount = name.endswith("Count") or name in ['DesignAxisRecordSize', 'ValueRecordSize']
 		self.isLookupType = name.endswith("LookupType") or name == "MorphType"
-		self.isPropagated = name in [
-			"ClassCount",
-			"Class2Count",
-			"FeatureTag",
-			"SettingsCount",
-			"VarRegionCount",
-			"MappingCount",
-			"RegionAxisCount",
-			"DesignAxisCount",
-			"DesignAxisRecordSize",
-			"AxisValueCount",
-			"ValueRecordSize",
-			"AxisCount",
-			"BaseGlyphRecordCount",
-			"LayerRecordCount",
-		]
+		self.isPropagated = name in ["ClassCount", "Class2Count", "FeatureTag", "SettingsCount", "VarRegionCount", "MappingCount", "RegionAxisCount", 'DesignAxisCount', 'DesignAxisRecordSize', 'AxisValueCount', 'ValueRecordSize', 'AxisCount']
 
 	def readArray(self, reader, font, tableDict, count):
 		"""Read an array of values from the reader."""
@@ -209,22 +181,15 @@
 
 
 class SimpleValue(BaseConverter):
-	@staticmethod
-	def toString(value):
-		return value
-	@staticmethod
-	def fromString(value):
-		return value
 	def xmlWrite(self, xmlWriter, font, value, name, attrs):
-		xmlWriter.simpletag(name, attrs + [("value", self.toString(value))])
+		xmlWriter.simpletag(name, attrs + [("value", value)])
 		xmlWriter.newline()
 	def xmlRead(self, attrs, content, font):
-		return self.fromString(attrs["value"])
+		return attrs["value"]
 
 class IntValue(SimpleValue):
-	@staticmethod
-	def fromString(value):
-		return int(value, 0)
+	def xmlRead(self, attrs, content, font):
+		return int(attrs["value"], 0)
 
 class Long(IntValue):
 	staticSize = 4
@@ -241,9 +206,9 @@
 		writer.writeULong(value)
 
 class Flags32(ULong):
-	@staticmethod
-	def toString(value):
-		return "0x%08X" % value
+	def xmlWrite(self, xmlWriter, font, value, name, attrs):
+		xmlWriter.simpletag(name, attrs + [("value", "0x%08X" % value)])
+		xmlWriter.newline()
 
 class Short(IntValue):
 	staticSize = 2
@@ -302,10 +267,9 @@
 
 class GlyphID(SimpleValue):
 	staticSize = 2
-	typecode = "H"
 	def readArray(self, reader, font, tableDict, count):
 		glyphOrder = font.getGlyphOrder()
-		gids = reader.readArray(self.typecode, self.staticSize, count)
+		gids = reader.readUShortArray(count)
 		try:
 			l = [glyphOrder[gid] for gid in gids]
 		except IndexError:
@@ -313,14 +277,9 @@
 			l = [font.getGlyphName(gid) for gid in gids]
 		return l
 	def read(self, reader, font, tableDict):
-		return font.getGlyphName(reader.readValue(self.typecode, self.staticSize))
+		return font.getGlyphName(reader.readUShort())
 	def write(self, writer, font, tableDict, value, repeatIndex=None):
-		writer.writeValue(self.typecode, font.getGlyphID(value))
-
-
-class GlyphID32(GlyphID):
-	staticSize = 4
-	typecode = "L"
+		writer.writeUShort(font.getGlyphID(value))
 
 
 class NameID(UShort):
@@ -338,23 +297,10 @@
 					log.warning("name id %d missing from name table" % value)
 		xmlWriter.newline()
 
-class STATFlags(UShort):
-	def xmlWrite(self, xmlWriter, font, value, name, attrs):
-		xmlWriter.simpletag(name, attrs + [("value", value)])
-		flags = []
-		if value & 0x01:
-			flags.append("OlderSiblingFontAttribute")
-		if value & 0x02:
-			flags.append("ElidableAxisValueName")
-		if flags:
-			xmlWriter.write("  ")
-			xmlWriter.comment(" ".join(flags))
-		xmlWriter.newline()
 
 class FloatValue(SimpleValue):
-	@staticmethod
-	def fromString(value):
-		return float(value)
+	def xmlRead(self, attrs, content, font):
+		return float(attrs["value"])
 
 class DeciPoints(FloatValue):
 	staticSize = 2
@@ -370,12 +316,6 @@
 		return  fi2fl(reader.readLong(), 16)
 	def write(self, writer, font, tableDict, value, repeatIndex=None):
 		writer.writeLong(fl2fi(value, 16))
-	@staticmethod
-	def fromString(value):
-		return str2fl(value, 16)
-	@staticmethod
-	def toString(value):
-		return fl2str(value, 16)
 
 class F2Dot14(FloatValue):
 	staticSize = 2
@@ -383,14 +323,8 @@
 		return  fi2fl(reader.readShort(), 14)
 	def write(self, writer, font, tableDict, value, repeatIndex=None):
 		writer.writeShort(fl2fi(value, 14))
-	@staticmethod
-	def fromString(value):
-		return str2fl(value, 14)
-	@staticmethod
-	def toString(value):
-		return fl2str(value, 14)
 
-class Version(SimpleValue):
+class Version(BaseConverter):
 	staticSize = 4
 	def read(self, reader, font, tableDict):
 		value = reader.readLong()
@@ -400,12 +334,16 @@
 		value = fi2ve(value)
 		assert (value >> 16) == 1, "Unsupported version 0x%08x" % value
 		writer.writeLong(value)
-	@staticmethod
-	def fromString(value):
-		return ve2fi(value)
-	@staticmethod
-	def toString(value):
-		return "0x%08x" % value
+	def xmlRead(self, attrs, content, font):
+		value = attrs["value"]
+		value = ve2fi(value)
+		return value
+	def xmlWrite(self, xmlWriter, font, value, name, attrs):
+		value = fi2ve(value)
+		value = "0x%08x" % value
+		xmlWriter.simpletag(name, attrs + [("value", value)])
+		xmlWriter.newline()
+
 	@staticmethod
 	def fromFloat(v):
 		return fl2fi(v, 16)
@@ -424,8 +362,8 @@
 		zeroPos = data.find(b"\0")
 		if zeroPos >= 0:
 			data = data[:zeroPos]
-		s = tostr(data, encoding="ascii", errors="replace")
-		if s != tostr(data, encoding="ascii", errors="ignore"):
+		s = tounicode(data, encoding="ascii", errors="replace")
+		if s != tounicode(data, encoding="ascii", errors="ignore"):
 			log.warning('replaced non-ASCII characters in "%s"' %
 			            s)
 		return s
@@ -544,13 +482,17 @@
 
 class Table(Struct):
 
+	longOffset = False
 	staticSize = 2
 
 	def readOffset(self, reader):
 		return reader.readUShort()
 
 	def writeNullOffset(self, writer):
-		writer.writeUShort(0)
+		if self.longOffset:
+			writer.writeULong(0)
+		else:
+			writer.writeUShort(0)
 
 	def read(self, reader, font, tableDict):
 		offset = self.readOffset(reader)
@@ -569,7 +511,8 @@
 		if value is None:
 			self.writeNullOffset(writer)
 		else:
-			subWriter = writer.getSubWriter(offsetSize=self.staticSize)
+			subWriter = writer.getSubWriter()
+			subWriter.longOffset = self.longOffset
 			subWriter.name = self.name
 			if repeatIndex is not None:
 				subWriter.repeatIndex = repeatIndex
@@ -578,26 +521,12 @@
 
 class LTable(Table):
 
+	longOffset = True
 	staticSize = 4
 
 	def readOffset(self, reader):
 		return reader.readULong()
 
-	def writeNullOffset(self, writer):
-		writer.writeULong(0)
-
-
-# Table pointed to by a 24-bit, 3-byte long offset
-class Table24(Table):
-
-	staticSize = 3
-
-	def readOffset(self, reader):
-		return reader.readUInt24()
-
-	def writeNullOffset(self, writer):
-		writer.writeUInt24(0)
-
 
 # TODO Clean / merge the SubTable and SubStruct
 
@@ -933,11 +862,13 @@
 			offsetByGlyph[glyph] = offset
 		# For calculating the offsets to our AATLookup and data table,
 		# we can use the regular OTTableWriter infrastructure.
-		lookupWriter = writer.getSubWriter(offsetSize=4)
+		lookupWriter = writer.getSubWriter()
+		lookupWriter.longOffset = True
 		lookup = AATLookup('DataOffsets', None, None, UShort)
 		lookup.write(lookupWriter, font, tableDict, offsetByGlyph, None)
 
-		dataWriter = writer.getSubWriter(offsetSize=4)
+		dataWriter = writer.getSubWriter()
+		dataWriter.longOffset = True
 		writer.writeSubTable(lookupWriter)
 		writer.writeSubTable(dataWriter)
 		for d in compiledData:
@@ -1278,7 +1209,8 @@
 				(len(table.PerGlyphLookups), numLookups))
 		writer = OTTableWriter()
 		for lookup in table.PerGlyphLookups:
-			lookupWriter = writer.getSubWriter(offsetSize=4)
+			lookupWriter = writer.getSubWriter()
+			lookupWriter.longOffset = True
 			self.perGlyphLookup.write(lookupWriter, font,
 			                          {}, lookup, None)
 			writer.writeSubTable(lookupWriter)
@@ -1623,140 +1555,13 @@
 	def xmlRead(self, attrs, content, font):
 		return safeEval(attrs["value"])
 
-class LookupFlag(UShort):
-	def xmlWrite(self, xmlWriter, font, value, name, attrs):
-		xmlWriter.simpletag(name, attrs + [("value", value)])
-		flags = []
-		if value & 0x01: flags.append("rightToLeft")
-		if value & 0x02: flags.append("ignoreBaseGlyphs")
-		if value & 0x04: flags.append("ignoreLigatures")
-		if value & 0x08: flags.append("ignoreMarks")
-		if value & 0x10: flags.append("useMarkFilteringSet")
-		if value & 0xff00: flags.append("markAttachmentType[%i]" % (value >> 8))
-		if flags:
-			xmlWriter.comment(" ".join(flags))
-		xmlWriter.newline()
-
-def _issubclass_namedtuple(x):
-	return (
-		issubclass(x, tuple)
-		and getattr(x, "_fields", None) is not None
-	)
-
-
-class _NamedTupleConverter(BaseConverter):
-	# subclasses must override this
-	tupleClass = NotImplemented
-	# List[SimpleValue]
-	converterClasses = NotImplemented
-
-	def __init__(self, name, repeat, aux, tableClass=None):
-		# we expect all converters to be subclasses of SimpleValue
-		assert all(issubclass(klass, SimpleValue) for klass in self.converterClasses)
-		assert _issubclass_namedtuple(self.tupleClass), repr(self.tupleClass)
-		assert len(self.tupleClass._fields) == len(self.converterClasses)
-		assert tableClass is None  # tableClass is unused by SimplValues
-		BaseConverter.__init__(self, name, repeat, aux)
-		self.converters = [
-			klass(name=name, repeat=None, aux=None)
-			for name, klass in zip(self.tupleClass._fields, self.converterClasses)
-		]
-		self.convertersByName = {conv.name: conv for conv in self.converters}
-		# returned by getRecordSize method
-		self.staticSize = sum(c.staticSize for c in self.converters)
-
-	def read(self, reader, font, tableDict):
-		kwargs = {
-			conv.name: conv.read(reader, font, tableDict)
-			for conv in self.converters
-		}
-		return self.tupleClass(**kwargs)
-
-	def write(self, writer, font, tableDict, value, repeatIndex=None):
-		for conv in self.converters:
-			v = getattr(value, conv.name)
-			# repeatIndex is unused for SimpleValues
-			conv.write(writer, font, tableDict, v, repeatIndex=None)
-
-	def xmlWrite(self, xmlWriter, font, value, name, attrs):
-		assert value is not None
-		defaults = value.__new__.__defaults__ or ()
-		assert len(self.converters) >= len(defaults)
-		values = {}
-		required = object()
-		for conv, default in zip_longest(
-			reversed(self.converters),
-			reversed(defaults),
-			fillvalue=required,
-		):
-			v = getattr(value, conv.name)
-			if default is required or v != default:
-				values[conv.name] = conv.toString(v)
-		if attrs is None:
-			attrs = []
-		attrs.extend(
-			(conv.name, values[conv.name])
-			for conv in self.converters
-			if conv.name in values
-		)
-		xmlWriter.simpletag(name, attrs)
-		xmlWriter.newline()
-
-	def xmlRead(self, attrs, content, font):
-		converters = self.convertersByName
-		kwargs = {
-			k: converters[k].fromString(v)
-			for k, v in attrs.items()
-		}
-		return self.tupleClass(**kwargs)
-
-
-class VarFixed(_NamedTupleConverter):
-	tupleClass = VariableFloat
-	converterClasses = [Fixed, ULong]
-
-
-class VarF2Dot14(_NamedTupleConverter):
-	tupleClass = VariableFloat
-	converterClasses = [F2Dot14, ULong]
-
-
-class VarInt16(_NamedTupleConverter):
-	tupleClass = VariableInt
-	converterClasses = [Short, ULong]
-
-
-class VarUInt16(_NamedTupleConverter):
-	tupleClass = VariableInt
-	converterClasses = [UShort, ULong]
-
-
-class _UInt8Enum(UInt8):
-	enumClass = NotImplemented
-
-	def read(self, reader, font, tableDict):
-		return self.enumClass(super().read(reader, font, tableDict))
-	@classmethod
-	def fromString(cls, value):
-		return getattr(cls.enumClass, value.upper())
-	@classmethod
-	def toString(cls, value):
-		return cls.enumClass(value).name.lower()
-
-
-class ExtendMode(_UInt8Enum):
-	enumClass = _ExtendMode
-
-
-class CompositeMode(_UInt8Enum):
-	enumClass = _CompositeMode
-
 
 converterMapping = {
 	# type		class
 	"int8":		Int8,
 	"int16":	Short,
 	"uint8":	UInt8,
+	"uint8":	UInt8,
 	"uint16":	UShort,
 	"uint24":	UInt24,
 	"uint32":	ULong,
@@ -1765,7 +1570,6 @@
 	"Version":	Version,
 	"Tag":		Tag,
 	"GlyphID":	GlyphID,
-	"GlyphID32":	GlyphID32,
 	"NameID":	NameID,
 	"DeciPoints":	DeciPoints,
 	"Fixed":	Fixed,
@@ -1773,15 +1577,10 @@
 	"struct":	Struct,
 	"Offset":	Table,
 	"LOffset":	LTable,
-	"Offset24":	Table24,
 	"ValueRecord":	ValueRecord,
 	"DeltaValue":	DeltaValue,
 	"VarIdxMapValue":	VarIdxMapValue,
 	"VarDataValue":	VarDataValue,
-	"LookupFlag": LookupFlag,
-	"ExtendMode": ExtendMode,
-	"CompositeMode": CompositeMode,
-	"STATFlags": STATFlags,
 
 	# AAT
 	"CIDGlyphMap":	CIDGlyphMap,
@@ -1797,11 +1596,4 @@
 	"STXHeader":	lambda C: partial(STXHeader, tableClass=C),
 	"OffsetTo":	lambda C: partial(Table, tableClass=C),
 	"LOffsetTo":	lambda C: partial(LTable, tableClass=C),
-	"LOffset24To":	lambda C: partial(Table24, tableClass=C),
-
-	# Variable types
-	"VarFixed": VarFixed,
-	"VarF2Dot14": VarF2Dot14,
-	"VarInt16": VarInt16,
-	"VarUInt16": VarUInt16,
 }
diff --git a/Lib/fontTools/ttLib/tables/otData.py b/Lib/fontTools/ttLib/tables/otData.py
index c429416..d08bcc5 100755
--- a/Lib/fontTools/ttLib/tables/otData.py
+++ b/Lib/fontTools/ttLib/tables/otData.py
@@ -1,3 +1,7 @@
+# coding: utf-8
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+
 otData = [
 
 	#
@@ -84,7 +88,7 @@
 
 	('Lookup', [
 		('uint16', 'LookupType', None, None, 'Different enumerations for GSUB and GPOS'),
-		('LookupFlag', 'LookupFlag', None, None, 'Lookup qualifiers'),
+		('uint16', 'LookupFlag', None, None, 'Lookup qualifiers'),
 		('uint16', 'SubTableCount', None, None, 'Number of SubTables for this lookup'),
 		('Offset', 'SubTable', 'SubTableCount', 0, 'Array of offsets to SubTables-from beginning of Lookup table'),
 		('uint16', 'MarkFilteringSet', None, 'LookupFlag & 0x0010', 'If set, indicates that the lookup table structure is followed by a MarkFilteringSet field. The layout engine skips over all mark glyphs not in the mark filtering set indicated.'),
@@ -699,7 +703,6 @@
 		('Version', 'Version', None, None, 'Version of the BASE table-initially 0x00010000'),
 		('Offset', 'HorizAxis', None, None, 'Offset to horizontal Axis table-from beginning of BASE table-may be NULL'),
 		('Offset', 'VertAxis', None, None, 'Offset to vertical Axis table-from beginning of BASE table-may be NULL'),
-		('LOffset', 'VarStore', None, 'Version >= 0x00010001', 'Offset to variation store (may be NULL)'),
 	]),
 
 	('Axis', [
@@ -869,7 +872,7 @@
 	('AxisValueFormat1', [
 		('uint16', 'Format', None, None, 'Format, = 1'),
 		('uint16', 'AxisIndex', None, None, 'Index into the axis record array identifying the axis of design variation to which the axis value record applies.'),
-		('STATFlags', 'Flags', None, None, 'Flags.'),
+		('uint16', 'Flags', None, None, 'Flags.'),
 		('NameID', 'ValueNameID', None, None, ''),
 		('Fixed', 'Value', None, None, ''),
 	]),
@@ -877,7 +880,7 @@
 	('AxisValueFormat2', [
 		('uint16', 'Format', None, None, 'Format, = 2'),
 		('uint16', 'AxisIndex', None, None, 'Index into the axis record array identifying the axis of design variation to which the axis value record applies.'),
-		('STATFlags', 'Flags', None, None, 'Flags.'),
+		('uint16', 'Flags', None, None, 'Flags.'),
 		('NameID', 'ValueNameID', None, None, ''),
 		('Fixed', 'NominalValue', None, None, ''),
 		('Fixed', 'RangeMinValue', None, None, ''),
@@ -887,7 +890,7 @@
 	('AxisValueFormat3', [
 		('uint16', 'Format', None, None, 'Format, = 3'),
 		('uint16', 'AxisIndex', None, None, 'Index into the axis record array identifying the axis of design variation to which the axis value record applies.'),
-		('STATFlags', 'Flags', None, None, 'Flags.'),
+		('uint16', 'Flags', None, None, 'Flags.'),
 		('NameID', 'ValueNameID', None, None, ''),
 		('Fixed', 'Value', None, None, ''),
 		('Fixed', 'LinkedValue', None, None, ''),
@@ -896,7 +899,7 @@
 	('AxisValueFormat4', [
 		('uint16', 'Format', None, None, 'Format, = 4'),
 		('uint16', 'AxisCount', None, None, 'The total number of axes contributing to this axis-values combination.'),
-		('STATFlags', 'Flags', None, None, 'Flags.'),
+		('uint16', 'Flags', None, None, 'Flags.'),
 		('NameID', 'ValueNameID', None, None, ''),
 		('struct', 'AxisValueRecord', 'AxisCount', 0, 'Array of AxisValue records that provide the combination of axis values, one for each contributing axis. '),
 	]),
@@ -1536,275 +1539,4 @@
 		('int16', 'CVTValueArray', 'NumCVTEntries', 0, 'CVT value'),
 	]),
 
-	#
-	# COLR
-	#
-
-	('COLR', [
-		('uint16', 'Version', None, None, 'Table version number (starts at 0).'),
-		('uint16', 'BaseGlyphRecordCount', None, None, 'Number of Base Glyph Records.'),
-		('LOffset', 'BaseGlyphRecordArray', None, None, 'Offset (from beginning of COLR table) to Base Glyph records.'),
-		('LOffset', 'LayerRecordArray', None, None, 'Offset (from beginning of COLR table) to Layer Records.'),
-		('uint16', 'LayerRecordCount', None, None, 'Number of Layer Records.'),
-		('LOffset', 'BaseGlyphV1List', None, 'Version >= 1', 'Offset (from beginning of COLR table) to array of Version-1 Base Glyph records.'),
-		('LOffset', 'LayerV1List', None, 'Version >= 1', 'Offset (from beginning of COLR table) to LayerV1List.'),
-		('LOffset', 'VarStore', None, 'Version >= 1', 'Offset to variation store (may be NULL)'),
-	]),
-
-	('BaseGlyphRecordArray', [
-		('BaseGlyphRecord', 'BaseGlyphRecord', 'BaseGlyphRecordCount', 0, 'Base Glyph records.'),
-	]),
-
-	('BaseGlyphRecord', [
-		('GlyphID', 'BaseGlyph', None, None, 'Glyph ID of reference glyph. This glyph is for reference only and is not rendered for color.'),
-		('uint16', 'FirstLayerIndex', None, None, 'Index (from beginning of the Layer Records) to the layer record. There will be numLayers consecutive entries for this base glyph.'),
-		('uint16', 'NumLayers', None, None, 'Number of color layers associated with this glyph.'),
-	]),
-
-	('LayerRecordArray', [
-		('LayerRecord', 'LayerRecord', 'LayerRecordCount', 0, 'Layer records.'),
-	]),
-
-	('LayerRecord', [
-		('GlyphID', 'LayerGlyph', None, None, 'Glyph ID of layer glyph (must be in z-order from bottom to top).'),
-		('uint16', 'PaletteIndex', None, None, 'Index value to use with a selected color palette.'),
-	]),
-
-	('BaseGlyphV1List', [
-		('uint32', 'BaseGlyphCount', None, None, 'Number of Version-1 Base Glyph records'),
-		('struct', 'BaseGlyphV1Record', 'BaseGlyphCount', 0, 'Array of Version-1 Base Glyph records'),
-	]),
-
-	('BaseGlyphV1Record', [
-		('GlyphID', 'BaseGlyph', None, None, 'Glyph ID of reference glyph.'),
-		('LOffset', 'Paint', None, None, 'Offset (from beginning of BaseGlyphV1Record) to Paint, typically a PaintColrLayers.'),
-	]),
-
-	('LayerV1List', [
-		('uint32', 'LayerCount', None, None, 'Number of Version-1 Layers'),
-		('LOffset', 'Paint', 'LayerCount', 0, 'Array of offsets to Paint tables, from the start of the LayerV1List table.'),
-	]),
-
-	# COLRv1 Affine2x3 uses the same column-major order to serialize a 2D
-	# Affine Transformation as the one used by fontTools.misc.transform.
-	# However, for historical reasons, the labels 'xy' and 'yx' are swapped.
-	# Their fundamental meaning is the same though.
-	# COLRv1 Affine2x3 follows the names found in FreeType and Cairo.
-	# In all case, the second element in the 6-tuple correspond to the
-	# y-part of the x basis vector, and the third to the x-part of the y
-	# basis vector.
-	# See https://github.com/googlefonts/colr-gradients-spec/pull/85
-	('Affine2x3', [
-		('Fixed', 'xx', None, None, 'x-part of x basis vector'),
-		('Fixed', 'yx', None, None, 'y-part of x basis vector'),
-		('Fixed', 'xy', None, None, 'x-part of y basis vector'),
-		('Fixed', 'yy', None, None, 'y-part of y basis vector'),
-		('Fixed', 'dx', None, None, 'Translation in x direction'),
-		('Fixed', 'dy', None, None, 'Translation in y direction'),
-	]),
-	('VarAffine2x3', [
-		('VarFixed', 'xx', None, None, 'x-part of x basis vector'),
-		('VarFixed', 'yx', None, None, 'y-part of x basis vector'),
-		('VarFixed', 'xy', None, None, 'x-part of y basis vector'),
-		('VarFixed', 'yy', None, None, 'y-part of y basis vector'),
-		('VarFixed', 'dx', None, None, 'Translation in x direction'),
-		('VarFixed', 'dy', None, None, 'Translation in y direction'),
-	]),
-
-	('ColorIndex', [
-		('uint16', 'PaletteIndex', None, None, 'Index value to use with a selected color palette.'),
-		('F2Dot14', 'Alpha', None, None, 'Values outsided [0.,1.] reserved'),
-	]),
-	('VarColorIndex', [
-		('uint16', 'PaletteIndex', None, None, 'Index value to use with a selected color palette.'),
-		('VarF2Dot14', 'Alpha', None, None, 'Values outsided [0.,1.] reserved'),
-	]),
-
-	('ColorStop', [
-		('F2Dot14', 'StopOffset', None, None, ''),
-		('ColorIndex', 'Color', None, None, ''),
-	]),
-	('VarColorStop', [
-		('VarF2Dot14', 'StopOffset', None, None, ''),
-		('VarColorIndex', 'Color', None, None, ''),
-	]),
-
-	('ColorLine', [
-		('ExtendMode', 'Extend', None, None, 'Enum {PAD = 0, REPEAT = 1, REFLECT = 2}'),
-		('uint16', 'StopCount', None, None, 'Number of Color stops.'),
-		('ColorStop', 'ColorStop', 'StopCount', 0, 'Array of Color stops.'),
-	]),
-	('VarColorLine', [
-		('ExtendMode', 'Extend', None, None, 'Enum {PAD = 0, REPEAT = 1, REFLECT = 2}'),
-		('uint16', 'StopCount', None, None, 'Number of Color stops.'),
-		('VarColorStop', 'ColorStop', 'StopCount', 0, 'Array of Color stops.'),
-	]),
-
-	# PaintColrLayers
-	('PaintFormat1', [
-		('uint8', 'PaintFormat', None, None, 'Format identifier-format = 1'),
-		('uint8', 'NumLayers', None, None, 'Number of offsets to Paint to read from LayerV1List.'),
-		('uint32', 'FirstLayerIndex', None, None, 'Index into LayerV1List.'),
-	]),
-
-	# PaintSolid
-	('PaintFormat2', [
-		('uint8', 'PaintFormat', None, None, 'Format identifier-format = 2'),
-		('ColorIndex', 'Color', None, None, 'A solid color paint.'),
-	]),
-	# PaintVarSolid
-	('PaintFormat3', [
-		('uint8', 'PaintFormat', None, None, 'Format identifier-format = 3'),
-		('VarColorIndex', 'Color', None, None, 'A solid color paint.'),
-	]),
-
-	# PaintLinearGradient
-	('PaintFormat4', [
-		('uint8', 'PaintFormat', None, None, 'Format identifier-format = 4'),
-		('Offset24', 'ColorLine', None, None, 'Offset (from beginning of PaintLinearGradient table) to ColorLine subtable.'),
-		('int16', 'x0', None, None, ''),
-		('int16', 'y0', None, None, ''),
-		('int16', 'x1', None, None, ''),
-		('int16', 'y1', None, None, ''),
-		('int16', 'x2', None, None, ''),
-		('int16', 'y2', None, None, ''),
-	]),
-	# PaintVarLinearGradient
-	('PaintFormat5', [
-		('uint8', 'PaintFormat', None, None, 'Format identifier-format = 5'),
-		('LOffset24To(VarColorLine)', 'ColorLine', None, None, 'Offset (from beginning of PaintVarLinearGradient table) to VarColorLine subtable.'),
-		('VarInt16', 'x0', None, None, ''),
-		('VarInt16', 'y0', None, None, ''),
-		('VarInt16', 'x1', None, None, ''),
-		('VarInt16', 'y1', None, None, ''),
-		('VarInt16', 'x2', None, None, ''),
-		('VarInt16', 'y2', None, None, ''),
-	]),
-
-	# PaintRadialGradient
-	('PaintFormat6', [
-		('uint8', 'PaintFormat', None, None, 'Format identifier-format = 6'),
-		('Offset24', 'ColorLine', None, None, 'Offset (from beginning of PaintRadialGradient table) to ColorLine subtable.'),
-		('int16', 'x0', None, None, ''),
-		('int16', 'y0', None, None, ''),
-		('uint16', 'r0', None, None, ''),
-		('int16', 'x1', None, None, ''),
-		('int16', 'y1', None, None, ''),
-		('uint16', 'r1', None, None, ''),
-	]),
-	# PaintVarRadialGradient
-	('PaintFormat7', [
-		('uint8', 'PaintFormat', None, None, 'Format identifier-format = 7'),
-		('LOffset24To(VarColorLine)', 'ColorLine', None, None, 'Offset (from beginning of PaintVarRadialGradient table) to VarColorLine subtable.'),
-		('VarInt16', 'x0', None, None, ''),
-		('VarInt16', 'y0', None, None, ''),
-		('VarUInt16', 'r0', None, None, ''),
-		('VarInt16', 'x1', None, None, ''),
-		('VarInt16', 'y1', None, None, ''),
-		('VarUInt16', 'r1', None, None, ''),
-	]),
-
-	# PaintSweepGradient
-	('PaintFormat8', [
-		('uint8', 'PaintFormat', None, None, 'Format identifier-format = 8'),
-		('Offset24', 'ColorLine', None, None, 'Offset (from beginning of PaintSweepGradient table) to ColorLine subtable.'),
-		('int16', 'centerX', None, None, 'Center x coordinate.'),
-		('int16', 'centerY', None, None, 'Center y coordinate.'),
-		('Fixed', 'startAngle', None, None, 'Start of the angular range of the gradient.'),
-		('Fixed', 'endAngle', None, None, 'End of the angular range of the gradient.'),
-	]),
-	# PaintVarSweepGradient
-	('PaintFormat9', [
-		('uint8', 'PaintFormat', None, None, 'Format identifier-format = 9'),
-		('LOffset24To(VarColorLine)', 'ColorLine', None, None, 'Offset (from beginning of PaintVarSweepGradient table) to VarColorLine subtable.'),
-		('VarInt16', 'centerX', None, None, 'Center x coordinate.'),
-		('VarInt16', 'centerY', None, None, 'Center y coordinate.'),
-		('VarFixed', 'startAngle', None, None, 'Start of the angular range of the gradient.'),
-		('VarFixed', 'endAngle', None, None, 'End of the angular range of the gradient.'),
-	]),
-
-	# PaintGlyph
-	('PaintFormat10', [
-		('uint8', 'PaintFormat', None, None, 'Format identifier-format = 10'),
-		('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintGlyph table) to Paint subtable.'),
-		('GlyphID', 'Glyph', None, None, 'Glyph ID for the source outline.'),
-	]),
-
-	# PaintColrGlyph
-	('PaintFormat11', [
-		('uint8', 'PaintFormat', None, None, 'Format identifier-format = 11'),
-		('GlyphID', 'Glyph', None, None, 'Virtual glyph ID for a BaseGlyphV1List base glyph.'),
-	]),
-
-	# PaintTransform
-	('PaintFormat12', [
-		('uint8', 'PaintFormat', None, None, 'Format identifier-format = 12'),
-		('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintTransform table) to Paint subtable.'),
-		('Affine2x3', 'Transform', None, None, '2x3 matrix for 2D affine transformations.'),
-	]),
-	# PaintVarTransform
-	('PaintFormat13', [
-		('uint8', 'PaintFormat', None, None, 'Format identifier-format = 13'),
-		('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarTransform table) to Paint subtable.'),
-		('VarAffine2x3', 'Transform', None, None, '2x3 matrix for 2D affine transformations.'),
-	]),
-
-	# PaintTranslate
-	('PaintFormat14', [
-		('uint8', 'PaintFormat', None, None, 'Format identifier-format = 14'),
-		('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintTranslate table) to Paint subtable.'),
-		('Fixed', 'dx', None, None, 'Translation in x direction.'),
-		('Fixed', 'dy', None, None, 'Translation in y direction.'),
-	]),
-	# PaintVarTranslate
-	('PaintFormat15', [
-		('uint8', 'PaintFormat', None, None, 'Format identifier-format = 15'),
-		('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarTranslate table) to Paint subtable.'),
-		('VarFixed', 'dx', None, None, 'Translation in x direction.'),
-		('VarFixed', 'dy', None, None, 'Translation in y direction.'),
-	]),
-
-	# PaintRotate
-	('PaintFormat16', [
-		('uint8', 'PaintFormat', None, None, 'Format identifier-format = 16'),
-		('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintRotate table) to Paint subtable.'),
-		('Fixed', 'angle', None, None, ''),
-		('Fixed', 'centerX', None, None, ''),
-		('Fixed', 'centerY', None, None, ''),
-	]),
-	# PaintVarRotate
-	('PaintFormat17', [
-		('uint8', 'PaintFormat', None, None, 'Format identifier-format = 17'),
-		('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarRotate table) to Paint subtable.'),
-		('VarFixed', 'angle', None, None, ''),
-		('VarFixed', 'centerX', None, None, ''),
-		('VarFixed', 'centerY', None, None, ''),
-	]),
-
-	# PaintSkew
-	('PaintFormat18', [
-		('uint8', 'PaintFormat', None, None, 'Format identifier-format = 18'),
-		('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintSkew table) to Paint subtable.'),
-		('Fixed', 'xSkewAngle', None, None, ''),
-		('Fixed', 'ySkewAngle', None, None, ''),
-		('Fixed', 'centerX', None, None, ''),
-		('Fixed', 'centerY', None, None, ''),
-	]),
-	# PaintVarSkew
-	('PaintFormat19', [
-		('uint8', 'PaintFormat', None, None, 'Format identifier-format = 19'),
-		('Offset24', 'Paint', None, None, 'Offset (from beginning of PaintVarSkew table) to Paint subtable.'),
-		('VarFixed', 'xSkewAngle', None, None, ''),
-		('VarFixed', 'ySkewAngle', None, None, ''),
-		('VarFixed', 'centerX', None, None, ''),
-		('VarFixed', 'centerY', None, None, ''),
-	]),
-
-	# PaintComposite
-	('PaintFormat20', [
-		('uint8', 'PaintFormat', None, None, 'Format identifier-format = 20'),
-		('LOffset24To(Paint)', 'SourcePaint', None, None, 'Offset (from beginning of PaintComposite table) to source Paint subtable.'),
-		('CompositeMode', 'CompositeMode', None, None, 'A CompositeMode enumeration value.'),
-		('LOffset24To(Paint)', 'BackdropPaint', None, None, 'Offset (from beginning of PaintComposite table) to backdrop Paint subtable.'),
-	]),
 ]
diff --git a/Lib/fontTools/ttLib/tables/otTables.py b/Lib/fontTools/ttLib/tables/otTables.py
index 85befb3..737e561 100644
--- a/Lib/fontTools/ttLib/tables/otTables.py
+++ b/Lib/fontTools/ttLib/tables/otTables.py
@@ -5,17 +5,10 @@
 Most are constructed upon import from data in otData.py, all are populated with
 converter objects from otConverters.py.
 """
-from enum import IntEnum
-import itertools
-from collections import namedtuple
-from fontTools.misc.py23 import bytesjoin
-from fontTools.misc.roundTools import otRound
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.textTools import pad, safeEval
-from .otBase import (
-	BaseTable, FormatSwitchingBaseTable, ValueRecord, CountReference,
-	getFormatSwitchingBaseTableClass,
-)
-from fontTools.feaLib.lookupDebugInfo import LookupDebugInfo, LOOKUP_DEBUG_INFO_KEY
+from .otBase import BaseTable, FormatSwitchingBaseTable, ValueRecord
 import logging
 import struct
 
@@ -558,7 +551,6 @@
 		else:
 			self.glyphs = []
 			log.warning("Unknown Coverage format: %s", self.Format)
-		del self.Format # Don't need this anymore
 
 	def preWrite(self, font):
 		glyphs = getattr(self, "glyphs", None)
@@ -696,25 +688,6 @@
 		mapping[glyph] = (outer << 16) | inner
 
 
-class VarRegionList(BaseTable):
-
-	def preWrite(self, font):
-		# The OT spec says VarStore.VarRegionList.RegionAxisCount should always
-		# be equal to the fvar.axisCount, and OTS < v8.0.0 enforces this rule
-		# even when the VarRegionList is empty. We can't treat RegionAxisCount
-		# like a normal propagated count (== len(Region[i].VarRegionAxis)),
-		# otherwise it would default to 0 if VarRegionList is empty.
-		# Thus, we force it to always be equal to fvar.axisCount.
-		# https://github.com/khaledhosny/ots/pull/192
-		fvarTable = font.get("fvar")
-		if fvarTable:
-			self.RegionAxisCount = len(fvarTable.axes)
-		return {
-			**self.__dict__,
-			"RegionAxisCount": CountReference(self.__dict__, "RegionAxisCount")
-		}
-
-
 class SingleSubst(FormatSwitchingBaseTable):
 
 	def populateDefaults(self, propagator=None):
@@ -740,7 +713,6 @@
 		else:
 			assert 0, "unknown format: %s" % self.Format
 		self.mapping = mapping
-		del self.Format # Don't need this anymore
 
 	def preWrite(self, font):
 		mapping = getattr(self, "mapping", None)
@@ -811,7 +783,6 @@
 		else:
 			assert 0, "unknown format: %s" % self.Format
 		self.mapping = mapping
-		del self.Format # Don't need this anymore
 
 	def preWrite(self, font):
 		mapping = getattr(self, "mapping", None)
@@ -930,7 +901,6 @@
 		else:
 			log.warning("Unknown ClassDef format: %s", self.Format)
 		self.classDefs = classDefs
-		del self.Format # Don't need this anymore
 
 	def _getClassRanges(self, font):
 		classDefs = getattr(self, "classDefs", None)
@@ -1019,7 +989,6 @@
 		else:
 			assert 0, "unknown format: %s" % self.Format
 		self.alternates = alternates
-		del self.Format # Don't need this anymore
 
 	def preWrite(self, font):
 		self.Format = 1
@@ -1090,7 +1059,6 @@
 		else:
 			assert 0, "unknown format: %s" % self.Format
 		self.ligatures = ligatures
-		del self.Format # Don't need this anymore
 
 	def preWrite(self, font):
 		self.Format = 1
@@ -1166,248 +1134,6 @@
 			ligs.append(lig)
 
 
-class COLR(BaseTable):
-
-	def decompile(self, reader, font):
-		# COLRv0 is exceptional in that LayerRecordCount appears *after* the
-		# LayerRecordArray it counts, but the parser logic expects Count fields
-		# to always precede the arrays. Here we work around this by parsing the
-		# LayerRecordCount before the rest of the table, and storing it in
-		# the reader's local state.
-		subReader = reader.getSubReader(offset=0)
-		for conv in self.getConverters():
-			if conv.name != "LayerRecordCount":
-				subReader.advance(conv.staticSize)
-				continue
-			conv = self.getConverterByName("LayerRecordCount")
-			reader[conv.name] = conv.read(subReader, font, tableDict={})
-			break
-		else:
-			raise AssertionError("LayerRecordCount converter not found")
-		return BaseTable.decompile(self, reader, font)
-
-	def preWrite(self, font):
-		# The writer similarly assumes Count values precede the things counted,
-		# thus here we pre-initialize a CountReference; the actual count value
-		# will be set to the lenght of the array by the time this is assembled.
-		self.LayerRecordCount = None
-		return {
-			**self.__dict__,
-			"LayerRecordCount": CountReference(self.__dict__, "LayerRecordCount")
-		}
-
-
-class LookupList(BaseTable):
-	@property
-	def table(self):
-		for l in self.Lookup:
-			for st in l.SubTable:
-				if type(st).__name__.endswith("Subst"):
-					return "GSUB"
-				if type(st).__name__.endswith("Pos"):
-					return "GPOS"
-		raise ValueError
-
-	def toXML2(self, xmlWriter, font):
-		if not font or "Debg" not in font or LOOKUP_DEBUG_INFO_KEY not in font["Debg"].data:
-			return super().toXML2(xmlWriter, font)
-		debugData = font["Debg"].data[LOOKUP_DEBUG_INFO_KEY][self.table]
-		for conv in self.getConverters():
-			if conv.repeat:
-				value = getattr(self, conv.name, [])
-				for lookupIndex, item in enumerate(value):
-					if str(lookupIndex) in debugData:
-						info = LookupDebugInfo(*debugData[str(lookupIndex)])
-						tag = info.location
-						if info.name:
-							tag = f'{info.name}: {tag}'
-						if info.feature:
-							script,language,feature = info.feature
-							tag = f'{tag} in {feature} ({script}/{language})'
-						xmlWriter.comment(tag)
-						xmlWriter.newline()
-
-					conv.xmlWrite(xmlWriter, font, item, conv.name,
-							[("index", lookupIndex)])
-			else:
-				if conv.aux and not eval(conv.aux, None, vars(self)):
-					continue
-				value = getattr(self, conv.name, None) # TODO Handle defaults instead of defaulting to None!
-				conv.xmlWrite(xmlWriter, font, value, conv.name, [])
-
-class BaseGlyphRecordArray(BaseTable):
-
-	def preWrite(self, font):
-		self.BaseGlyphRecord = sorted(
-			self.BaseGlyphRecord,
-			key=lambda rec: font.getGlyphID(rec.BaseGlyph)
-		)
-		return self.__dict__.copy()
-
-
-class BaseGlyphV1List(BaseTable):
-
-	def preWrite(self, font):
-		self.BaseGlyphV1Record = sorted(
-			self.BaseGlyphV1Record,
-			key=lambda rec: font.getGlyphID(rec.BaseGlyph)
-		)
-		return self.__dict__.copy()
-
-
-
-class VariableValue(namedtuple("VariableValue", ["value", "varIdx"])):
-	__slots__ = ()
-
-	_value_mapper = None
-
-	def __new__(cls, value, varIdx=0):
-		return super().__new__(
-			cls,
-			cls._value_mapper(value) if cls._value_mapper else value,
-			varIdx
-		)
-
-	@classmethod
-	def _make(cls, iterable):
-		if cls._value_mapper:
-			it = iter(iterable)
-			try:
-				value = next(it)
-			except StopIteration:
-				pass
-			else:
-				value = cls._value_mapper(value)
-				iterable = itertools.chain((value,), it)
-		return super()._make(iterable)
-
-
-class VariableFloat(VariableValue):
-	__slots__ = ()
-	_value_mapper = float
-
-
-class VariableInt(VariableValue):
-	__slots__ = ()
-	_value_mapper = otRound
-
-
-class ExtendMode(IntEnum):
-	PAD = 0
-	REPEAT = 1
-	REFLECT = 2
-
-
-# Porter-Duff modes for COLRv1 PaintComposite:
-# https://github.com/googlefonts/colr-gradients-spec/tree/off_sub_1#compositemode-enumeration
-class CompositeMode(IntEnum):
-	CLEAR = 0
-	SRC = 1
-	DEST = 2
-	SRC_OVER = 3
-	DEST_OVER = 4
-	SRC_IN = 5
-	DEST_IN = 6
-	SRC_OUT = 7
-	DEST_OUT = 8
-	SRC_ATOP = 9
-	DEST_ATOP = 10
-	XOR = 11
-	SCREEN = 12
-	OVERLAY = 13
-	DARKEN = 14
-	LIGHTEN = 15
-	COLOR_DODGE = 16
-	COLOR_BURN = 17
-	HARD_LIGHT = 18
-	SOFT_LIGHT = 19
-	DIFFERENCE = 20
-	EXCLUSION = 21
-	MULTIPLY = 22
-	HSL_HUE = 23
-	HSL_SATURATION = 24
-	HSL_COLOR = 25
-	HSL_LUMINOSITY = 26
-
-
-class PaintFormat(IntEnum):
-	PaintColrLayers = 1
-	PaintSolid = 2
-	PaintVarSolid = 3,
-	PaintLinearGradient = 4
-	PaintVarLinearGradient = 5
-	PaintRadialGradient = 6
-	PaintVarRadialGradient = 7
-	PaintSweepGradient = 8
-	PaintVarSweepGradient = 9
-	PaintGlyph = 10
-	PaintColrGlyph = 11
-	PaintTransform = 12
-	PaintVarTransform = 13
-	PaintTranslate = 14
-	PaintVarTranslate = 15
-	PaintRotate = 16
-	PaintVarRotate = 17
-	PaintSkew = 18
-	PaintVarSkew = 19
-	PaintComposite = 20
-
-
-class Paint(getFormatSwitchingBaseTableClass("uint8")):
-
-	def getFormatName(self):
-		try:
-			return PaintFormat(self.Format).name
-		except ValueError:
-			raise NotImplementedError(f"Unknown Paint format: {self.Format}")
-
-	def toXML(self, xmlWriter, font, attrs=None, name=None):
-		tableName = name if name else self.__class__.__name__
-		if attrs is None:
-			attrs = []
-		attrs.append(("Format", self.Format))
-		xmlWriter.begintag(tableName, attrs)
-		xmlWriter.comment(self.getFormatName())
-		xmlWriter.newline()
-		self.toXML2(xmlWriter, font)
-		xmlWriter.endtag(tableName)
-		xmlWriter.newline()
-
-	def getChildren(self, colr):
-		if self.Format == PaintFormat.PaintColrLayers:
-			return colr.LayerV1List.Paint[
-				self.FirstLayerIndex : self.FirstLayerIndex + self.NumLayers
-			]
-
-		if self.Format == PaintFormat.PaintColrGlyph:
-			for record in colr.BaseGlyphV1List.BaseGlyphV1Record:
-				if record.BaseGlyph == self.Glyph:
-					return [record.Paint]
-			else:
-				raise KeyError(f"{self.Glyph!r} not in colr.BaseGlyphV1List")
-
-		children = []
-		for conv in self.getConverters():
-			if conv.tableClass is not None and issubclass(conv.tableClass, type(self)):
-				children.append(getattr(self, conv.name))
-
-		return children
-
-	def traverse(self, colr: COLR, callback):
-		"""Depth-first traversal of graph rooted at self, callback on each node."""
-		if not callable(callback):
-			raise TypeError("callback must be callable")
-		stack = [self]
-		visited = set()
-		while stack:
-			current = stack.pop()
-			if id(current) in visited:
-				continue
-			callback(current)
-			visited.add(id(current))
-			stack.extend(reversed(current.getChildren(colr)))
-
-
 # For each subtable format there is a class. However, we don't really distinguish
 # between "field name" and "format name": often these are the same. Yet there's
 # a whole bunch of fields with different names. The following dict is a mapping
@@ -1501,32 +1227,6 @@
 	ok = 1
 	return ok
 
-def splitMultipleSubst(oldSubTable, newSubTable, overflowRecord):
-	ok = 1
-	newSubTable.Format = oldSubTable.Format
-	oldMapping = sorted(oldSubTable.mapping.items())
-	oldLen = len(oldMapping)
-
-	if overflowRecord.itemName in ['Coverage', 'RangeRecord']:
-		# Coverage table is written last. Overflow is to or within the
-		# the coverage table. We will just cut the subtable in half.
-		newLen = oldLen // 2
-
-	elif overflowRecord.itemName == 'Sequence':
-		# We just need to back up by two items from the overflowed
-		# Sequence index to make sure the offset to the Coverage table
-		# doesn't overflow.
-		newLen = overflowRecord.itemIndex - 1
-
-	newSubTable.mapping = {}
-	for i in range(newLen, oldLen):
-		item = oldMapping[i]
-		key = item[0]
-		newSubTable.mapping[key] = item[1]
-		del oldSubTable.mapping[key]
-
-	return ok
-
 def splitAlternateSubst(oldSubTable, newSubTable, overflowRecord):
 	ok = 1
 	newSubTable.Format = oldSubTable.Format
@@ -1671,7 +1371,6 @@
 			oldMarkCoverage.append(glyphName)
 			oldMarkRecords.append(markRecord)
 		else:
-			markRecord.Class -= oldClassCount
 			newMarkCoverage.append(glyphName)
 			newMarkRecords.append(markRecord)
 
@@ -1687,6 +1386,7 @@
 
 	oldSubTable.MarkCoverage.glyphs = oldMarkCoverage
 	newSubTable.MarkCoverage = oldSubTable.MarkCoverage.__class__()
+	newSubTable.MarkCoverage.Format = oldSubTable.MarkCoverage.Format
 	newSubTable.MarkCoverage.glyphs = newMarkCoverage
 
 	# share the same BaseCoverage in both halves
@@ -1714,7 +1414,7 @@
 
 splitTable = {	'GSUB': {
 #					1: splitSingleSubst,
-					2: splitMultipleSubst,
+#					2: splitMultipleSubst,
 					3: splitAlternateSubst,
 					4: splitLigatureSubst,
 #					5: splitContextSubst,
@@ -1806,11 +1506,7 @@
 		if m:
 			# XxxFormatN subtable, we only add the "base" table
 			name = m.group(1)
-			# the first row of a format-switching otData table describes the Format;
-			# the first column defines the type of the Format field.
-			# Currently this can be either 'uint16' or 'uint8'.
-			formatType = table[0][0]
-			baseClass = getFormatSwitchingBaseTableClass(formatType)
+			baseClass = FormatSwitchingBaseTable
 		if name not in namespace:
 			# the class doesn't exist yet, so the base implementation is used.
 			cls = type(name, (baseClass,), {})
diff --git a/Lib/fontTools/ttLib/tables/sbixGlyph.py b/Lib/fontTools/ttLib/tables/sbixGlyph.py
index fe29c09..c053908 100644
--- a/Lib/fontTools/ttLib/tables/sbixGlyph.py
+++ b/Lib/fontTools/ttLib/tables/sbixGlyph.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from fontTools.misc.textTools import readHex, safeEval
 import struct
diff --git a/Lib/fontTools/ttLib/tables/sbixStrike.py b/Lib/fontTools/ttLib/tables/sbixStrike.py
index b367a99..6c1ac77 100644
--- a/Lib/fontTools/ttLib/tables/sbixStrike.py
+++ b/Lib/fontTools/ttLib/tables/sbixStrike.py
@@ -1,6 +1,8 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
-from fontTools.misc.textTools import safeEval
-from .sbixGlyph import Glyph
+from fontTools.misc.textTools import readHex
+from .sbixGlyph import *
 import struct
 
 sbixStrikeHeaderFormat = """
diff --git a/Lib/fontTools/ttLib/tables/ttProgram.py b/Lib/fontTools/ttLib/tables/ttProgram.py
index a1dfa3c..7ffb37a 100644
--- a/Lib/fontTools/ttLib/tables/ttProgram.py
+++ b/Lib/fontTools/ttLib/tables/ttProgram.py
@@ -1,9 +1,9 @@
 """ttLib.tables.ttProgram.py -- Assembler/disassembler for TrueType bytecode programs."""
 
-from fontTools.misc.py23 import strjoin
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.textTools import num2binary, binary2num, readHex
 import array
-from io import StringIO
 import re
 import logging
 
@@ -223,7 +223,7 @@
 	def getBytecode(self):
 		if not hasattr(self, "bytecode"):
 			self._assemble()
-		return self.bytecode.tobytes()
+		return self.bytecode.tostring()
 
 	def getAssembly(self, preserve=True):
 		if not hasattr(self, "assembly"):
diff --git a/Lib/fontTools/ttLib/ttCollection.py b/Lib/fontTools/ttLib/ttCollection.py
index 3db4c8c..2507fe3 100644
--- a/Lib/fontTools/ttLib/ttCollection.py
+++ b/Lib/fontTools/ttLib/ttCollection.py
@@ -1,6 +1,7 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.ttLib.ttFont import TTFont
 from fontTools.ttLib.sfnt import readTTCHeader, writeTTCHeader
-from io import BytesIO
 import struct
 import logging
 
@@ -35,16 +36,6 @@
 		for i in range(header.numFonts):
 			font = TTFont(file, fontNumber=i, _tableCache=tableCache, **kwargs)
 			fonts.append(font)
-			
-	def __enter__(self):
-		return self
-	
-	def __exit__(self, type, value, traceback):
-		self.close()
-		
-	def close(self):
-		for font in self.fonts:
-			font.close()
 
 	def save(self, file, shareTables=True):
 		"""Save the font to disk. Similarly to the constructor,
@@ -104,7 +95,7 @@
 		return self.fonts[item]
 
 	def __setitem__(self, item, value):
-		self.fonts[item] = value
+		self.fonts[item] = values
 
 	def __delitem__(self, item):
 		return self.fonts[item]
diff --git a/Lib/fontTools/ttLib/ttFont.py b/Lib/fontTools/ttLib/ttFont.py
index 41a4875..dca0b51 100644
--- a/Lib/fontTools/ttLib/ttFont.py
+++ b/Lib/fontTools/ttLib/ttFont.py
@@ -1,12 +1,12 @@
+from __future__ import print_function, division, absolute_import
 from fontTools.misc import xmlWriter
-from fontTools.misc.py23 import Tag, byteord, tostr
+from fontTools.misc.py23 import *
 from fontTools.misc.loggingTools import deprecateArgument
 from fontTools.ttLib import TTLibError
 from fontTools.ttLib.sfnt import SFNTReader, SFNTWriter
-from io import BytesIO, StringIO
 import os
 import logging
-import traceback
+import itertools
 
 log = logging.getLogger(__name__)
 
@@ -19,7 +19,7 @@
 	"""
 
 	def __init__(self, file=None, res_name_or_index=None,
-			sfntVersion="\000\001\000\000", flavor=None, checkChecksums=0,
+			sfntVersion="\000\001\000\000", flavor=None, checkChecksums=False,
 			verbose=None, recalcBBoxes=True, allowVID=False, ignoreDecompileErrors=False,
 			recalcTimestamp=True, fontNumber=-1, lazy=None, quiet=None,
 			_tableCache=None):
@@ -162,17 +162,22 @@
 			if self.lazy and self.reader.file.name == file:
 				raise TTLibError(
 					"Can't overwrite TTFont when 'lazy' attribute is True")
-			createStream = True
+			closeStream = True
+			file = open(file, "wb")
 		else:
 			# assume "file" is a writable file object
-			createStream = False
+			closeStream = False
 
 		tmp = BytesIO()
 
 		writer_reordersTables = self._save(tmp)
 
-		if not (reorderTables is None or writer_reordersTables or
+		if (reorderTables is None or writer_reordersTables or
 				(reorderTables is False and self.reader is None)):
+			# don't reorder tables and save as is
+			file.write(tmp.getvalue())
+			tmp.close()
+		else:
 			if reorderTables is False:
 				# sort tables using the original font's order
 				tableOrder = list(self.reader.keys())
@@ -182,17 +187,12 @@
 			tmp.flush()
 			tmp2 = BytesIO()
 			reorderFontTables(tmp, tmp2, tableOrder)
+			file.write(tmp2.getvalue())
 			tmp.close()
-			tmp = tmp2
+			tmp2.close()
 
-		if createStream:
-			# "file" is a path
-			with open(file, "wb") as file:
-				file.write(tmp.getvalue())
-		else:
-			file.write(tmp.getvalue())
-
-		tmp.close()
+		if closeStream:
+			file.close()
 
 	def _save(self, file, tableCache=None):
 		"""Internal function, to be shared by save() and TTCollection.save()"""
@@ -369,46 +369,45 @@
 
 	def __getitem__(self, tag):
 		tag = Tag(tag)
-		table = self.tables.get(tag)
-		if table is None:
+		try:
+			return self.tables[tag]
+		except KeyError:
 			if tag == "GlyphOrder":
 				table = GlyphOrder(tag)
 				self.tables[tag] = table
-			elif self.reader is not None:
-				table = self._readTable(tag)
+				return table
+			if self.reader is not None:
+				import traceback
+				log.debug("Reading '%s' table from disk", tag)
+				data = self.reader[tag]
+				if self._tableCache is not None:
+					table = self._tableCache.get((Tag(tag), data))
+					if table is not None:
+						return table
+				tableClass = getTableClass(tag)
+				table = tableClass(tag)
+				self.tables[tag] = table
+				log.debug("Decompiling '%s' table", tag)
+				try:
+					table.decompile(data, self)
+				except:
+					if not self.ignoreDecompileErrors:
+						raise
+					# fall back to DefaultTable, retaining the binary table data
+					log.exception(
+						"An exception occurred during the decompilation of the '%s' table", tag)
+					from .tables.DefaultTable import DefaultTable
+					file = StringIO()
+					traceback.print_exc(file=file)
+					table = DefaultTable(tag)
+					table.ERROR = file.getvalue()
+					self.tables[tag] = table
+					table.decompile(data, self)
+				if self._tableCache is not None:
+					self._tableCache[(Tag(tag), data)] = table
+				return table
 			else:
 				raise KeyError("'%s' table not found" % tag)
-		return table
-
-	def _readTable(self, tag):
-		log.debug("Reading '%s' table from disk", tag)
-		data = self.reader[tag]
-		if self._tableCache is not None:
-			table = self._tableCache.get((tag, data))
-			if table is not None:
-				return table
-		tableClass = getTableClass(tag)
-		table = tableClass(tag)
-		self.tables[tag] = table
-		log.debug("Decompiling '%s' table", tag)
-		try:
-			table.decompile(data, self)
-		except Exception:
-			if not self.ignoreDecompileErrors:
-				raise
-			# fall back to DefaultTable, retaining the binary table data
-			log.exception(
-				"An exception occurred during the decompilation of the '%s' table", tag)
-			from .tables.DefaultTable import DefaultTable
-			file = StringIO()
-			traceback.print_exc(file=file)
-			table = DefaultTable(tag)
-			table.ERROR = file.getvalue()
-			self.tables[tag] = table
-			table.decompile(data, self)
-		if self._tableCache is not None:
-			self._tableCache[(tag, data)] = table
-		return table
 
 	def __setitem__(self, tag, table):
 		self.tables[Tag(tag)] = table
@@ -638,7 +637,7 @@
 				log.debug("reusing '%s' table", tag)
 				writer.setEntry(tag, entry)
 				return
-		log.debug("Writing '%s' table to disk", tag)
+		log.debug("writing '%s' table to disk", tag)
 		writer[tag] = tabledata
 		if tableCache is not None:
 			tableCache[(Tag(tag), tabledata)] = writer[tag]
@@ -648,7 +647,7 @@
 		"""
 		tag = Tag(tag)
 		if self.isLoaded(tag):
-			log.debug("Compiling '%s' table", tag)
+			log.debug("compiling '%s' table", tag)
 			return self.tables[tag].compile(self)
 		elif self.reader and tag in self.reader:
 			log.debug("Reading '%s' table from disk", tag)
@@ -702,13 +701,6 @@
 	"""
 
 	def __init__(self, ttFont, glyphs, glyphType):
-		"""Construct a new glyphset.
-
-		Args:
-			font (TTFont): The font object (used to get metrics).
-			glyphs (dict): A dictionary mapping glyph names to ``_TTGlyph`` objects.
-			glyphType (class): Either ``_TTGlyphCFF`` or ``_TTGlyphGlyf``.
-		"""
 		self._glyphs = glyphs
 		self._hmtx = ttFont['hmtx']
 		self._vmtx = ttFont['vmtx'] if 'vmtx' in ttFont else None
@@ -749,13 +741,6 @@
 	"""
 
 	def __init__(self, glyphset, glyph, horizontalMetrics, verticalMetrics=None):
-		"""Construct a new _TTGlyph.
-
-		Args:
-			glyphset (_TTGlyphSet): A glyphset object used to resolve components.
-			glyph (ttLib.tables._g_l_y_f.Glyph): The glyph object.
-			horizontalMetrics (int, int): The glyph's width and left sidebearing.
-		"""
 		self._glyphset = glyphset
 		self._glyph = glyph
 		self.width, self.lsb = horizontalMetrics
@@ -765,7 +750,7 @@
 			self.height, self.tsb = None, None
 
 	def draw(self, pen):
-		"""Draw the glyph onto ``pen``. See fontTools.pens.basePen for details
+		"""Draw the glyph onto Pen. See fontTools.pens.basePen for details
 		how that works.
 		"""
 		self._glyph.draw(pen)
@@ -846,48 +831,10 @@
 		return getattr(tables, pyTag)
 
 
-# Registry for custom table packer/unpacker classes. Keys are table
-# tags, values are (moduleName, className) tuples.
-# See registerCustomTableClass() and getCustomTableClass()
-_customTableRegistry = {}
-
-
-def registerCustomTableClass(tag, moduleName, className=None):
-	"""Register a custom packer/unpacker class for a table.
-	The 'moduleName' must be an importable module. If no 'className'
-	is given, it is derived from the tag, for example it will be
-	table_C_U_S_T_ for a 'CUST' tag.
-
-	The registered table class should be a subclass of
-	fontTools.ttLib.tables.DefaultTable.DefaultTable
-	"""
-	if className is None:
-		className = "table_" + tagToIdentifier(tag)
-	_customTableRegistry[tag] = (moduleName, className)
-
-
-def unregisterCustomTableClass(tag):
-	"""Unregister the custom packer/unpacker class for a table."""
-	del _customTableRegistry[tag]
-
-
-def getCustomTableClass(tag):
-	"""Return the custom table class for tag, if one has been registered
-	with 'registerCustomTableClass()'. Else return None.
-	"""
-	if tag not in _customTableRegistry:
-		return None
-	import importlib
-	moduleName, className = _customTableRegistry[tag]
-	module = importlib.import_module(moduleName)
-	return getattr(module, className)
-
-
 def getTableClass(tag):
-	"""Fetch the packer/unpacker class for a table."""
-	tableClass = getCustomTableClass(tag)
-	if tableClass is not None:
-		return tableClass
+	"""Fetch the packer/unpacker class for a table.
+	Return None when no class is found.
+	"""
 	module = getTableModule(tag)
 	if module is None:
 		from .tables.DefaultTable import DefaultTable
diff --git a/Lib/fontTools/ttLib/woff2.py b/Lib/fontTools/ttLib/woff2.py
index cc58afa..56b119a 100644
--- a/Lib/fontTools/ttLib/woff2.py
+++ b/Lib/fontTools/ttLib/woff2.py
@@ -1,5 +1,5 @@
-from fontTools.misc.py23 import Tag, bytechr, byteord, bytesjoin
-from io import BytesIO
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 import sys
 import array
 import struct
@@ -12,7 +12,7 @@
 from fontTools.ttLib.sfnt import (SFNTReader, SFNTWriter, DirectoryEntry,
 	WOFFFlavorData, sfntDirectoryFormat, sfntDirectorySize, SFNTDirectoryEntry,
 	sfntDirectoryEntrySize, calcChecksum)
-from fontTools.ttLib.tables import ttProgram, _g_l_y_f
+from fontTools.ttLib.tables import ttProgram
 import logging
 
 
@@ -20,10 +20,7 @@
 
 haveBrotli = False
 try:
-	try:
-		import brotlicffi as brotli
-	except ImportError:
-		import brotli
+	import brotli
 	haveBrotli = True
 except ImportError:
 	pass
@@ -33,7 +30,7 @@
 
 	flavor = "woff2"
 
-	def __init__(self, file, checkChecksums=0, fontNumber=-1):
+	def __init__(self, file, checkChecksums=1, fontNumber=-1):
 		if not haveBrotli:
 			log.error(
 				'The WOFF2 decoder requires the Brotli Python extension, available at: '
@@ -230,11 +227,7 @@
 		# See:
 		# https://github.com/khaledhosny/ots/issues/60
 		# https://github.com/google/woff2/issues/15
-		if (
-			isTrueType
-			and "glyf" in self.flavorData.transformedTables
-			and "glyf" in self.tables
-		):
+		if isTrueType and "glyf" in self.flavorData.transformedTables:
 			self._normaliseGlyfAndLoca(padding=4)
 		self._setHeadTransformFlag()
 
@@ -659,7 +652,7 @@
 			else:
 				locations = array.array("I", self.locations)
 			if sys.byteorder != "big": locations.byteswap()
-			data = locations.tobytes()
+			data = locations.tostring()
 		else:
 			# use the most compact indexFormat given the current glyph offsets
 			data = super(WOFF2LocaTable, self).compile(ttFont)
@@ -741,7 +734,7 @@
 		for glyphID in range(self.numGlyphs):
 			self._encodeGlyph(glyphID)
 
-		self.bboxStream = self.bboxBitmap.tobytes() + self.bboxStream
+		self.bboxStream = self.bboxBitmap.tostring() + self.bboxStream
 		for stream in self.subStreams:
 			setattr(self, stream + 'Size', len(getattr(self, stream)))
 		self.version = 0
@@ -935,7 +928,7 @@
 		flags = array.array('B')
 		triplets = array.array('B')
 		for i in range(len(coordinates)):
-			onCurve = glyph.flags[i] & _g_l_y_f.flagOnCurve
+			onCurve = glyph.flags[i]
 			x, y = coordinates[i]
 			absX = abs(x)
 			absY = abs(y)
@@ -969,8 +962,8 @@
 				triplets.append(absY >> 8)
 				triplets.append(absY & 0xff)
 
-		self.flagStream += flags.tobytes()
-		self.glyphStream += triplets.tobytes()
+		self.flagStream += flags.tostring()
+		self.glyphStream += triplets.tostring()
 
 
 class WOFF2HmtxTable(getTableClass("hmtx")):
@@ -1101,7 +1094,7 @@
 		)
 		if sys.byteorder != "big":
 			advanceWidthArray.byteswap()
-		data += advanceWidthArray.tobytes()
+		data += advanceWidthArray.tostring()
 
 		if hasLsbArray:
 			lsbArray = array.array(
@@ -1114,7 +1107,7 @@
 			)
 			if sys.byteorder != "big":
 				lsbArray.byteswap()
-			data += lsbArray.tobytes()
+			data += lsbArray.tostring()
 
 		if hasLeftSideBearingArray:
 			leftSideBearingArray = array.array(
@@ -1126,7 +1119,7 @@
 			)
 			if sys.byteorder != "big":
 				leftSideBearingArray.byteswap()
-			data += leftSideBearingArray.tobytes()
+			data += leftSideBearingArray.tostring()
 
 		return data
 
@@ -1172,8 +1165,26 @@
 				raise ValueError(
 					"'glyf' and 'loca' must be transformed (or not) together"
 				)
-		super(WOFF2FlavorData, self).__init__(reader=reader)
+
+		self.majorVersion = None
+		self.minorVersion = None
+		self.metaData = None
+		self.privData = None
 		if reader:
+			self.majorVersion = reader.majorVersion
+			self.minorVersion = reader.minorVersion
+			if reader.metaLength:
+				reader.file.seek(reader.metaOffset)
+				rawData = reader.file.read(reader.metaLength)
+				assert len(rawData) == reader.metaLength
+				metaData = brotli.decompress(rawData)
+				assert len(metaData) == reader.metaOrigLength
+				self.metaData = metaData
+			if reader.privLength:
+				reader.file.seek(reader.privOffset)
+				privData = reader.file.read(reader.privLength)
+				assert len(privData) == reader.privLength
+				self.privData = privData
 			transformedTables = [
 				tag
 				for tag, entry in reader.tables.items()
@@ -1192,9 +1203,6 @@
 
 		self.transformedTables = set(transformedTables)
 
-	def _decompress(self, rawData):
-		return brotli.decompress(rawData)
-
 
 def unpackBase128(data):
 	r""" Read one to five bytes from UIntBase128-encoded input string, and return
@@ -1394,22 +1402,10 @@
 
 
 def main(args=None):
-	"""Compress and decompress WOFF2 fonts"""
 	import argparse
 	from fontTools import configLogger
 	from fontTools.ttx import makeOutputFileName
 
-	class _HelpAction(argparse._HelpAction):
-
-		def __call__(self, parser, namespace, values, option_string=None):
-			subparsers_actions = [
-					action for action in parser._actions
-					if isinstance(action, argparse._SubParsersAction)]
-			for subparsers_action in subparsers_actions:
-					for choice, subparser in subparsers_action.choices.items():
-							print(subparser.format_help())
-			parser.exit()
-
 	class _NoGlyfTransformAction(argparse.Action):
 		def __call__(self, parser, namespace, values, option_string=None):
 			namespace.transform_tables.difference_update({"glyf", "loca"})
@@ -1420,18 +1416,12 @@
 
 	parser = argparse.ArgumentParser(
 		prog="fonttools ttLib.woff2",
-		description=main.__doc__,
-		add_help = False
+		description="Compress and decompress WOFF2 fonts",
 	)
 
-	parser.add_argument('-h', '--help', action=_HelpAction,
-		help='show this help message and exit')
-
 	parser_group = parser.add_subparsers(title="sub-commands")
-	parser_compress = parser_group.add_parser("compress",
-		description = "Compress a TTF or OTF font to WOFF2")
-	parser_decompress = parser_group.add_parser("decompress",
-		description = "Decompress a WOFF2 font to OTF")
+	parser_compress = parser_group.add_parser("compress")
+	parser_decompress = parser_group.add_parser("decompress")
 
 	for subparser in (parser_compress, parser_decompress):
 		group = subparser.add_mutually_exclusive_group(required=False)
diff --git a/Lib/fontTools/ttx.py b/Lib/fontTools/ttx.py
index 2eed0c5..8f598f8 100644
--- a/Lib/fontTools/ttx.py
+++ b/Lib/fontTools/ttx.py
@@ -86,7 +86,8 @@
 """
 
 
-from fontTools.misc.py23 import Tag, tostr
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.ttLib import TTFont, TTLibError
 from fontTools.misc.macCreatorType import getMacCreatorAndType
 from fontTools.unicode import setUnicodeData
@@ -384,7 +385,6 @@
 
 
 def main(args=None):
-	"""Convert OpenType fonts to XML and back"""
 	from fontTools import configLogger
 
 	if args is None:
diff --git a/Lib/fontTools/ufoLib/__init__.py b/Lib/fontTools/ufoLib/__init__.py
index e846d08..4a1fa86 100755
--- a/Lib/fontTools/ufoLib/__init__.py
+++ b/Lib/fontTools/ufoLib/__init__.py
@@ -1,6 +1,7 @@
+from __future__ import absolute_import, unicode_literals
+import sys
 import os
 from copy import deepcopy
-from os import fsdecode
 import logging
 import zipfile
 import enum
@@ -14,12 +15,13 @@
 import fs.zipfs
 import fs.tempfs
 import fs.tools
+from fontTools.misc.py23 import basestring, unicode, tounicode
 from fontTools.misc import plistlib
 from fontTools.ufoLib.validators import *
 from fontTools.ufoLib.filenames import userNameToFileName
 from fontTools.ufoLib.converters import convertUFO1OrUFO2KerningToUFO3Kerning
 from fontTools.ufoLib.errors import UFOLibError
-from fontTools.ufoLib.utils import numberTypes, _VersionTupleEnumMixin
+from fontTools.ufoLib.utils import datetimeAsTimestamp, fsdecode, numberTypes
 
 """
 A library for importing .ufo files and their descendants.
@@ -92,11 +94,7 @@
 
 DEFAULT_LAYER_NAME = "public.default"
 
-
-class UFOFormatVersion(tuple, _VersionTupleEnumMixin, enum.Enum):
-	FORMAT_1_0 = (1, 0)
-	FORMAT_2_0 = (2, 0)
-	FORMAT_3_0 = (3, 0)
+supportedUFOFormatVersions = [1, 2, 3]
 
 
 class UFOFileStructure(enum.Enum):
@@ -109,7 +107,7 @@
 # --------------
 
 
-class _UFOBaseIO:
+class _UFOBaseIO(object):
 
 	def getFileModificationTime(self, path):
 		"""
@@ -123,7 +121,7 @@
 		except (fs.errors.MissingInfoNamespace, fs.errors.ResourceNotFound):
 			return None
 		else:
-			return dt.timestamp()
+			return datetimeAsTimestamp(dt)
 
 	def _getPlist(self, fileName, default=None):
 		"""
@@ -149,7 +147,7 @@
 		except Exception as e:
 			# TODO(anthrotype): try to narrow this down a little
 			raise UFOLibError(
-				f"'{fileName}' could not be read on {self.fs}: {e}"
+				"'%s' could not be read on %s: %s" % (fileName, self.fs, e)
 			)
 
 	def _writePlist(self, fileName, obj):
@@ -207,7 +205,7 @@
 		if hasattr(path, "__fspath__"):  # support os.PathLike objects
 			path = path.__fspath__()
 
-		if isinstance(path, str):
+		if isinstance(path, basestring):
 			structure = _sniffFileStructure(path)
 			try:
 				if structure is UFOFileStructure.ZIP:
@@ -215,7 +213,7 @@
 				else:
 					parentFS = fs.osfs.OSFS(path)
 			except fs.errors.CreateFailed as e:
-				raise UFOLibError(f"unable to open '{path}': {e}")
+				raise UFOLibError("unable to open '%s': %s" % (path, e))
 
 			if structure is UFOFileStructure.ZIP:
 				# .ufoz zip files must contain a single root directory, with arbitrary
@@ -254,7 +252,7 @@
 				path = filesystem.getsyspath("/")
 			except fs.errors.NoSysPath:
 				# network or in-memory FS may not map to the local one
-				path = str(filesystem)
+				path = unicode(filesystem)
 			# when user passed an already initialized fs instance, it is her
 			# responsibility to close it, thus UFOReader.close/__exit__ are no-op
 			self._shouldClose = False
@@ -267,14 +265,9 @@
 			)
 		self._path = fsdecode(path)
 		self._validate = validate
+		self.readMetaInfo(validate=validate)
 		self._upConvertedKerningData = None
 
-		try:
-			self.readMetaInfo(validate=validate)
-		except UFOLibError:
-			self.close()
-			raise
-
 	# properties
 
 	def _get_path(self):
@@ -290,27 +283,10 @@
 	path = property(_get_path, doc="The path of the UFO (DEPRECATED).")
 
 	def _get_formatVersion(self):
-		import warnings
-
-		warnings.warn(
-			"The 'formatVersion' attribute is deprecated; use the 'formatVersionTuple'",
-			DeprecationWarning,
-			stacklevel=2,
-		)
-		return self._formatVersion.major
-
-	formatVersion = property(
-		_get_formatVersion,
-		doc="The (major) format version of the UFO. DEPRECATED: Use formatVersionTuple"
-	)
-
-	@property
-	def formatVersionTuple(self):
-		"""The (major, minor) format version of the UFO.
-		This is determined by reading metainfo.plist during __init__.
-		"""
 		return self._formatVersion
 
+	formatVersion = property(_get_formatVersion, doc="The format version of the UFO. This is determined by reading metainfo.plist during __init__.")
+
 	def _get_fileStructure(self):
 		return self._fileStructure
 
@@ -348,12 +324,12 @@
 				if not isinstance(groups, dict):
 					raise UFOLibError(invalidFormatMessage)
 				for groupName, glyphList in groups.items():
-					if not isinstance(groupName, str):
+					if not isinstance(groupName, basestring):
 						raise UFOLibError(invalidFormatMessage)
 					elif not isinstance(glyphList, list):
 						raise UFOLibError(invalidFormatMessage)
 					for glyphName in glyphList:
-						if not isinstance(glyphName, str):
+						if not isinstance(glyphName, basestring):
 							raise UFOLibError(invalidFormatMessage)
 			self._upConvertedKerningData = dict(
 				kerning={},
@@ -364,8 +340,7 @@
 			# convert kerning and groups
 			kerning, groups, conversionMaps = convertUFO1OrUFO2KerningToUFO3Kerning(
 				self._upConvertedKerningData["originalKerning"],
-				deepcopy(self._upConvertedKerningData["originalGroups"]),
-				self.getGlyphSet()
+				deepcopy(self._upConvertedKerningData["originalGroups"])
 			)
 			# store
 			self._upConvertedKerningData["kerning"] = kerning
@@ -391,7 +366,7 @@
 		The path must be relative to the UFO path.
 		Returns None if the file does not exist.
 		By default the file is opened in binary mode (reads bytes).
-		If encoding is passed, the file is opened in text mode (reads str).
+		If encoding is passed, the file is opened in text mode (reads unicode).
 
 		Note: The caller is responsible for closing the open file.
 		"""
@@ -405,9 +380,9 @@
 			return None
 	# metainfo.plist
 
-	def _readMetaInfo(self, validate=None):
+	def readMetaInfo(self, validate=None):
 		"""
-		Read metainfo.plist and return raw data. Only used for internal operations.
+		Read metainfo.plist. Only used for internal operations.
 
 		``validate`` will validate the read data, by default it is set
 		to the class's validate value, can be overridden.
@@ -417,54 +392,24 @@
 		data = self._getPlist(METAINFO_FILENAME)
 		if validate and not isinstance(data, dict):
 			raise UFOLibError("metainfo.plist is not properly formatted.")
-		try:
-			formatVersionMajor = data["formatVersion"]
-		except KeyError:
-			raise UFOLibError(
-				f"Missing required formatVersion in '{METAINFO_FILENAME}' on {self.fs}"
-			)
-		formatVersionMinor = data.setdefault("formatVersionMinor", 0)
-
-		try:
-			formatVersion = UFOFormatVersion((formatVersionMajor, formatVersionMinor))
-		except ValueError as e:
-			unsupportedMsg = (
-				f"Unsupported UFO format ({formatVersionMajor}.{formatVersionMinor}) "
-				f"in '{METAINFO_FILENAME}' on {self.fs}"
-			)
-			if validate:
-				from fontTools.ufoLib.errors import UnsupportedUFOFormat
-
-				raise UnsupportedUFOFormat(unsupportedMsg) from e
-
-			formatVersion = UFOFormatVersion.default()
-			logger.warning(
-				"%s. Assuming the latest supported version (%s). "
-				"Some data may be skipped or parsed incorrectly",
-				unsupportedMsg, formatVersion
-			)
-		data["formatVersionTuple"] = formatVersion
-		return data
-
-	def readMetaInfo(self, validate=None):
-		"""
-		Read metainfo.plist and set formatVersion. Only used for internal operations.
-
-		``validate`` will validate the read data, by default it is set
-		to the class's validate value, can be overridden.
-		"""
-		data = self._readMetaInfo(validate=validate)
-		self._formatVersion = data["formatVersionTuple"]
+		formatVersion = data["formatVersion"]
+		if validate:
+			if not isinstance(formatVersion, int):
+				raise UFOLibError(
+					"formatVersion must be specified as an integer in '%s' on %s"
+					% (METAINFO_FILENAME, self.fs)
+				)
+			if formatVersion not in supportedUFOFormatVersions:
+				raise UFOLibError(
+					"Unsupported UFO format (%d) in '%s' on %s"
+					% (formatVersion, METAINFO_FILENAME, self.fs)
+				)
+		self._formatVersion = formatVersion
 
 	# groups.plist
 
 	def _readGroups(self):
-		groups = self._getPlist(GROUPS_FILENAME, {})
-		# remove any duplicate glyphs in a kerning group
-		for groupName, glyphList in groups.items():
-			if groupName.startswith(('public.kern1.', 'public.kern2.')):
-				groups[groupName] = list(OrderedDict.fromkeys(glyphList))
-		return groups
+		return self._getPlist(GROUPS_FILENAME, {})
 
 	def readGroups(self, validate=None):
 		"""
@@ -475,7 +420,7 @@
 		if validate is None:
 			validate = self._validate
 		# handle up conversion
-		if self._formatVersion < UFOFormatVersion.FORMAT_3_0:
+		if self._formatVersion < 3:
 			self._upConvertKerning(validate)
 			groups = self._upConvertedKerningData["groups"]
 		# normal
@@ -506,7 +451,7 @@
 		"""
 		if validate is None:
 			validate = self._validate
-		if self._formatVersion >= UFOFormatVersion.FORMAT_3_0:
+		if self._formatVersion >= 3:
 			return dict(side1={}, side2={})
 		# use the public group reader to force the load and
 		# conversion of the data if it hasn't happened yet.
@@ -536,7 +481,7 @@
 		infoDict = self._readInfo(validate)
 		infoDataToSet = {}
 		# version 1
-		if self._formatVersion == UFOFormatVersion.FORMAT_1_0:
+		if self._formatVersion == 1:
 			for attr in fontInfoAttributesVersion1:
 				value = infoDict.get(attr)
 				if value is not None:
@@ -544,15 +489,15 @@
 			infoDataToSet = _convertFontInfoDataVersion1ToVersion2(infoDataToSet)
 			infoDataToSet = _convertFontInfoDataVersion2ToVersion3(infoDataToSet)
 		# version 2
-		elif self._formatVersion == UFOFormatVersion.FORMAT_2_0:
+		elif self._formatVersion == 2:
 			for attr, dataValidationDict in list(fontInfoAttributesVersion2ValueData.items()):
 				value = infoDict.get(attr)
 				if value is None:
 					continue
 				infoDataToSet[attr] = value
 			infoDataToSet = _convertFontInfoDataVersion2ToVersion3(infoDataToSet)
-		# version 3.x
-		elif self._formatVersion.major == UFOFormatVersion.FORMAT_3_0.major:
+		# version 3
+		elif self._formatVersion == 3:
 			for attr, dataValidationDict in list(fontInfoAttributesVersion3ValueData.items()):
 				value = infoDict.get(attr)
 				if value is None:
@@ -560,7 +505,7 @@
 				infoDataToSet[attr] = value
 		# unsupported version
 		else:
-			raise NotImplementedError(self._formatVersion)
+			raise NotImplementedError
 		# validate data
 		if validate:
 			infoDataToSet = validateInfoVersion3Data(infoDataToSet)
@@ -587,7 +532,7 @@
 		if validate is None:
 			validate = self._validate
 		# handle up conversion
-		if self._formatVersion < UFOFormatVersion.FORMAT_3_0:
+		if self._formatVersion < 3:
 			self._upConvertKerning(validate)
 			kerningNested = self._upConvertedKerningData["kerning"]
 		# normal
@@ -627,7 +572,7 @@
 
 	def readFeatures(self):
 		"""
-		Read features.fea. Return a string.
+		Read features.fea. Return a unicode string.
 		The returned string is empty if the file is missing.
 		"""
 		try:
@@ -645,7 +590,7 @@
 
 		``validate`` will validate the layer contents.
 		"""
-		if self._formatVersion < UFOFormatVersion.FORMAT_3_0:
+		if self._formatVersion < 3:
 			return [(DEFAULT_LAYER_NAME, DEFAULT_GLYPHS_DIRNAME)]
 		contents = self._getPlist(LAYERCONTENTS_FILENAME)
 		if validate:
@@ -693,7 +638,7 @@
 
 		``validateRead`` will validate the read data, by default it is set to the
 		class's validate value, can be overridden.
-		``validateWrite`` will validate the written data, by default it is set to the
+		``validateWrte`` will validate the written data, by default it is set to the
 		class's validate value, can be overridden.
 		"""
 		from fontTools.ufoLib.glifLib import GlyphSet
@@ -716,14 +661,13 @@
 			glyphSubFS = self.fs.opendir(directory)
 		except fs.errors.ResourceNotFound:
 			raise UFOLibError(
-				f"No '{directory}' directory for layer '{layerName}'"
+				"No '%s' directory for layer '%s'" % (directory, layerName)
 			)
 		return GlyphSet(
 			glyphSubFS,
 			ufoFormatVersion=self._formatVersion,
 			validateRead=validateRead,
 			validateWrite=validateWrite,
-			expectContentsFile=True
 		)
 
 	def getCharacterMapping(self, layerName=None, validate=None):
@@ -778,7 +722,7 @@
 		``validate`` will validate the data, by default it is set to the
 		class's validate value, can be overridden.
 		"""
-		if self._formatVersion < UFOFormatVersion.FORMAT_3_0:
+		if self._formatVersion < 3:
 			return []
 		if validate is None:
 			validate = self._validate
@@ -816,7 +760,7 @@
 				dataFS = self.fs.opendir(DATA_DIRNAME)
 			data = dataFS.readbytes(fileName)
 		except fs.errors.ResourceNotFound:
-			raise UFOLibError(f"No data file named '{fileName}' on {self.fs}")
+			raise UFOLibError("No data file named '%s' on %s" % (fileName, self.fs))
 		return data
 
 	def readImage(self, fileName, validate=None):
@@ -828,10 +772,8 @@
 		"""
 		if validate is None:
 			validate = self._validate
-		if self._formatVersion < UFOFormatVersion.FORMAT_3_0:
-			raise UFOLibError(
-				f"Reading images is not allowed in UFO {self._formatVersion.major}."
-			)
+		if self._formatVersion < 3:
+			raise UFOLibError("Reading images is not allowed in UFO %d." % self._formatVersion)
 		fileName = fsdecode(fileName)
 		try:
 			try:
@@ -841,7 +783,7 @@
 				imagesFS = self.fs.opendir(IMAGES_DIRNAME)
 			data = imagesFS.readbytes(fileName)
 		except fs.errors.ResourceNotFound:
-			raise UFOLibError(f"No image file named '{fileName}' on {self.fs}")
+			raise UFOLibError("No image file named '%s' on %s" % (fileName, self.fs))
 		if validate:
 			valid, error = pngValidator(data=data)
 			if not valid:
@@ -871,35 +813,23 @@
 	By default, the written data will be validated before writing. Set ``validate`` to
 	``False`` if you do not want to validate the data. Validation can also be overriden
 	on a per method level if desired.
-
-	The ``formatVersion`` argument allows to specify the UFO format version as a tuple
-	of integers (major, minor), or as a single integer for the major digit only (minor
-	is implied as 0). By default the latest formatVersion will be used; currently it's
-	3.0, which is equivalent to formatVersion=(3, 0).
-
-	An UnsupportedUFOFormat exception is raised if the requested UFO formatVersion is
-	not supported.
 	"""
 
 	def __init__(
 		self,
 		path,
-		formatVersion=None,
+		formatVersion=3,
 		fileCreator="com.github.fonttools.ufoLib",
 		structure=None,
 		validate=True,
 	):
-		try:
-			formatVersion = UFOFormatVersion(formatVersion)
-		except ValueError as e:
-			from fontTools.ufoLib.errors import UnsupportedUFOFormat
-
-			raise UnsupportedUFOFormat(f"Unsupported UFO format: {formatVersion!r}") from e
+		if formatVersion not in supportedUFOFormatVersions:
+			raise UFOLibError("Unsupported UFO format (%d)." % formatVersion)
 
 		if hasattr(path, "__fspath__"):  # support os.PathLike objects
 			path = path.__fspath__()
 
-		if isinstance(path, str):
+		if isinstance(path, basestring):
 			# normalize path by removing trailing or double slashes
 			path = os.path.normpath(path)
 			havePreviousFile = os.path.exists(path)
@@ -979,7 +909,7 @@
 				path = filesystem.getsyspath("/")
 			except fs.errors.NoSysPath:
 				# network or in-memory FS may not map to the local one
-				path = str(filesystem)
+				path = unicode(filesystem)
 			# if passed an FS object, always use 'package' structure
 			if structure and structure is not UFOFileStructure.PACKAGE:
 				import warnings
@@ -1010,20 +940,22 @@
 		# this will be needed for up and down conversion.
 		previousFormatVersion = None
 		if self._havePreviousFile:
-			metaInfo = self._readMetaInfo(validate=validate)
-			previousFormatVersion = metaInfo["formatVersionTuple"]
-			# catch down conversion
-			if previousFormatVersion > formatVersion:
-				from fontTools.ufoLib.errors import UnsupportedUFOFormat
-
-				raise UnsupportedUFOFormat(
-					"The UFO located at this path is a higher version "
-					f"({previousFormatVersion}) than the version ({formatVersion}) "
-					"that is trying to be written. This is not supported."
-				)
+			metaInfo = self._getPlist(METAINFO_FILENAME)
+			previousFormatVersion = metaInfo.get("formatVersion")
+			try:
+				previousFormatVersion = int(previousFormatVersion)
+			except (ValueError, TypeError):
+				self.fs.close()
+				raise UFOLibError("The existing metainfo.plist is not properly formatted.")
+			if previousFormatVersion not in supportedUFOFormatVersions:
+				self.fs.close()
+				raise UFOLibError("Unsupported UFO format (%d)." % formatVersion)
+		# catch down conversion
+		if previousFormatVersion is not None and previousFormatVersion > formatVersion:
+			raise UFOLibError("The UFO located at this path is a higher version (%d) than the version (%d) that is trying to be written. This is not supported." % (previousFormatVersion, formatVersion))
 		# handle the layer contents
 		self.layerContents = {}
-		if previousFormatVersion is not None and previousFormatVersion.major >= 3:
+		if previousFormatVersion is not None and previousFormatVersion >= 3:
 			# already exists
 			self.layerContents = OrderedDict(self._readLayerContents(validate))
 		else:
@@ -1108,7 +1040,7 @@
 				return self.fs.open(path, mode=mode, encoding=encoding)
 		except fs.errors.ResourceError as e:
 			return UFOLibError(
-				f"unable to open '{path}' on {self.fs}: {e}"
+				"unable to open '%s' on %s: %s" % (path, self.fs, e)
 			)
 
 	def removePath(self, path, force=False, removeEmptyParents=True):
@@ -1128,7 +1060,7 @@
 		except fs.errors.ResourceNotFound:
 			if not force:
 				raise UFOLibError(
-					f"'{path}' does not exist on {self.fs}"
+					"'%s' does not exist on %s" % (path, self.fs)
 				)
 		if removeEmptyParents:
 			parent = fs.path.dirname(path)
@@ -1159,10 +1091,8 @@
 	def _writeMetaInfo(self):
 		metaInfo = dict(
 			creator=self._fileCreator,
-			formatVersion=self._formatVersion.major,
+			formatVersion=self._formatVersion
 		)
-		if self._formatVersion.minor != 0:
-			metaInfo["formatVersionMinor"] = self._formatVersion.minor
 		self._writePlist(METAINFO_FILENAME, metaInfo)
 
 	# groups.plist
@@ -1183,7 +1113,7 @@
 		This is the same form returned by UFOReader's
 		getKerningGroupConversionRenameMaps method.
 		"""
-		if self._formatVersion >= UFOFormatVersion.FORMAT_3_0:
+		if self._formatVersion >= 3:
 			return # XXX raise an error here
 		# flip the dictionaries
 		remap = {}
@@ -1208,10 +1138,7 @@
 			if not valid:
 				raise UFOLibError(message)
 		# down convert
-		if (
-			self._formatVersion < UFOFormatVersion.FORMAT_3_0
-			and self._downConversionKerningData is not None
-		):
+		if self._formatVersion < 3 and self._downConversionKerningData is not None:
 			remap = self._downConversionKerningData["groupRenameMap"]
 			remappedGroups = {}
 			# there are some edge cases here that are ignored:
@@ -1272,21 +1199,20 @@
 					continue
 				infoData[attr] = value
 		# down convert data if necessary and validate
-		if self._formatVersion == UFOFormatVersion.FORMAT_3_0:
+		if self._formatVersion == 3:
 			if validate:
 				infoData = validateInfoVersion3Data(infoData)
-		elif self._formatVersion == UFOFormatVersion.FORMAT_2_0:
+		elif self._formatVersion == 2:
 			infoData = _convertFontInfoDataVersion3ToVersion2(infoData)
 			if validate:
 				infoData = validateInfoVersion2Data(infoData)
-		elif self._formatVersion == UFOFormatVersion.FORMAT_1_0:
+		elif self._formatVersion == 1:
 			infoData = _convertFontInfoDataVersion3ToVersion2(infoData)
 			if validate:
 				infoData = validateInfoVersion2Data(infoData)
 			infoData = _convertFontInfoDataVersion2ToVersion1(infoData)
-		# write file if there is anything to write
-		if infoData:
-			self._writePlist(FONTINFO_FILENAME, infoData)
+		# write file
+		self._writePlist(FONTINFO_FILENAME, infoData)
 
 	# kerning.plist
 
@@ -1315,17 +1241,14 @@
 					raise UFOLibError(invalidFormatMessage)
 				if not len(pair) == 2:
 					raise UFOLibError(invalidFormatMessage)
-				if not isinstance(pair[0], str):
+				if not isinstance(pair[0], basestring):
 					raise UFOLibError(invalidFormatMessage)
-				if not isinstance(pair[1], str):
+				if not isinstance(pair[1], basestring):
 					raise UFOLibError(invalidFormatMessage)
 				if not isinstance(value, numberTypes):
 					raise UFOLibError(invalidFormatMessage)
 		# down convert
-		if (
-			self._formatVersion < UFOFormatVersion.FORMAT_3_0
-			and self._downConversionKerningData is not None
-		):
+		if self._formatVersion < 3 and self._downConversionKerningData is not None:
 			remap = self._downConversionKerningData["groupRenameMap"]
 			remappedKerning = {}
 			for (side1, side2), value in list(kerning.items()):
@@ -1375,10 +1298,10 @@
 		"""
 		if validate is None:
 			validate = self._validate
-		if self._formatVersion == UFOFormatVersion.FORMAT_1_0:
+		if self._formatVersion == 1:
 			raise UFOLibError("features.fea is not allowed in UFO Format Version 1.")
 		if validate:
-			if not isinstance(features, str):
+			if not isinstance(features, basestring):
 				raise UFOLibError("The features are not text.")
 		if features:
 			self.writeBytesToPath(FEATURES_FILENAME, features.encode("utf8"))
@@ -1394,13 +1317,15 @@
 		"""
 		if validate is None:
 			validate = self._validate
-		if self._formatVersion < UFOFormatVersion.FORMAT_3_0:
+		if self.formatVersion < 3:
 			return
 		if layerOrder is not None:
 			newOrder = []
 			for layerName in layerOrder:
 				if layerName is None:
 					layerName = DEFAULT_LAYER_NAME
+				else:
+					layerName = tounicode(layerName)
 				newOrder.append(layerName)
 			layerOrder = newOrder
 		else:
@@ -1423,15 +1348,7 @@
 			raise UFOLibError("Could not locate a glyph set directory for the layer named %s." % layerName)
 		return foundDirectory
 
-	def getGlyphSet(
-		self,
-		layerName=None,
-		defaultLayer=True,
-		glyphNameToFileNameFunc=None,
-		validateRead=None,
-		validateWrite=None,
-		expectContentsFile=False,
-	):
+	def getGlyphSet(self, layerName=None, defaultLayer=True, glyphNameToFileNameFunc=None, validateRead=None, validateWrite=None):
 		"""
 		Return the GlyphSet object associated with the
 		appropriate glyph directory in the .ufo.
@@ -1444,23 +1361,14 @@
 		class's validate value, can be overridden.
 		``validateWrte`` will validate the written data, by default it is set to the
 		class's validate value, can be overridden.
-		``expectContentsFile`` will raise a GlifLibError if a contents.plist file is
-		not found on the glyph set file system. This should be set to ``True`` if you
-		are reading an existing UFO and ``False`` if you use ``getGlyphSet`` to create
-		a fresh	glyph set.
 		"""
 		if validateRead is None:
 			validateRead = self._validate
 		if validateWrite is None:
 			validateWrite = self._validate
 		# only default can be written in < 3
-		if (
-			self._formatVersion < UFOFormatVersion.FORMAT_3_0
-			and (not defaultLayer or layerName is not None)
-		):
-			raise UFOLibError(
-				f"Only the default layer can be writen in UFO {self._formatVersion.major}."
-			)
+		if self._formatVersion < 3 and (not defaultLayer or layerName is not None):
+			raise UFOLibError("Only the default layer can be writen in UFO %d." % self.formatVersion)
 		# locate a layer name when None has been given
 		if layerName is None and defaultLayer:
 			for existingLayerName, directory in self.layerContents.items():
@@ -1471,53 +1379,40 @@
 		elif layerName is None and not defaultLayer:
 			raise UFOLibError("A layer name must be provided for non-default layers.")
 		# move along to format specific writing
-		if self._formatVersion < UFOFormatVersion.FORMAT_3_0:
-			return self._getDefaultGlyphSet(
-				validateRead,
-				validateWrite,
-				glyphNameToFileNameFunc=glyphNameToFileNameFunc,
-				expectContentsFile=expectContentsFile
-			)
-		elif self._formatVersion.major == UFOFormatVersion.FORMAT_3_0.major:
-			return self._getGlyphSetFormatVersion3(
-				validateRead,
-				validateWrite,
-				layerName=layerName,
-				defaultLayer=defaultLayer,
-				glyphNameToFileNameFunc=glyphNameToFileNameFunc,
-				expectContentsFile=expectContentsFile,
-			)
+		if self.formatVersion == 1:
+			return self._getGlyphSetFormatVersion1(validateRead, validateWrite, glyphNameToFileNameFunc=glyphNameToFileNameFunc)
+		elif self.formatVersion == 2:
+			return self._getGlyphSetFormatVersion2(validateRead, validateWrite, glyphNameToFileNameFunc=glyphNameToFileNameFunc)
+		elif self.formatVersion == 3:
+			return self._getGlyphSetFormatVersion3(validateRead, validateWrite, layerName=layerName, defaultLayer=defaultLayer, glyphNameToFileNameFunc=glyphNameToFileNameFunc)
 		else:
-			raise NotImplementedError(self._formatVersion)
+			raise AssertionError(self.formatVersion)
 
-	def _getDefaultGlyphSet(
-		self,
-		validateRead,
-		validateWrite,
-		glyphNameToFileNameFunc=None,
-		expectContentsFile=False,
-	):
+	def _getGlyphSetFormatVersion1(self, validateRead, validateWrite, glyphNameToFileNameFunc=None):
 		from fontTools.ufoLib.glifLib import GlyphSet
 
 		glyphSubFS = self.fs.makedir(DEFAULT_GLYPHS_DIRNAME, recreate=True)
 		return GlyphSet(
 			glyphSubFS,
 			glyphNameToFileNameFunc=glyphNameToFileNameFunc,
-			ufoFormatVersion=self._formatVersion,
+			ufoFormatVersion=1,
 			validateRead=validateRead,
 			validateWrite=validateWrite,
-			expectContentsFile=expectContentsFile,
 		)
 
-	def _getGlyphSetFormatVersion3(
-		self,
-		validateRead,
-		validateWrite,
-		layerName=None,
-		defaultLayer=True,
-		glyphNameToFileNameFunc=None,
-		expectContentsFile=False,
-	):
+	def _getGlyphSetFormatVersion2(self, validateRead, validateWrite, glyphNameToFileNameFunc=None):
+		from fontTools.ufoLib.glifLib import GlyphSet
+
+		glyphSubFS = self.fs.makedir(DEFAULT_GLYPHS_DIRNAME, recreate=True)
+		return GlyphSet(
+			glyphSubFS,
+			glyphNameToFileNameFunc=glyphNameToFileNameFunc,
+			ufoFormatVersion=2,
+			validateRead=validateRead,
+			validateWrite=validateWrite,
+		)
+
+	def _getGlyphSetFormatVersion3(self, validateRead, validateWrite, layerName=None, defaultLayer=True, glyphNameToFileNameFunc=None):
 		from fontTools.ufoLib.glifLib import GlyphSet
 
 		# if the default flag is on, make sure that the default in the file
@@ -1544,6 +1439,11 @@
 				# not caching this could be slightly expensive,
 				# but caching it will be cumbersome
 				existing = {d.lower() for d in self.layerContents.values()}
+				if not isinstance(layerName, unicode):
+					try:
+						layerName = unicode(layerName)
+					except UnicodeDecodeError:
+						raise UFOLibError("The specified layer name is not a Unicode string.")
 				directory = userNameToFileName(layerName, existing=existing, prefix="glyphs.")
 		# make the directory
 		glyphSubFS = self.fs.makedir(directory, recreate=True)
@@ -1553,10 +1453,9 @@
 		return GlyphSet(
 			glyphSubFS,
 			glyphNameToFileNameFunc=glyphNameToFileNameFunc,
-			ufoFormatVersion=self._formatVersion,
+			ufoFormatVersion=3,
 			validateRead=validateRead,
 			validateWrite=validateWrite,
-			expectContentsFile=expectContentsFile,
 		)
 
 	def renameGlyphSet(self, layerName, newLayerName, defaultLayer=False):
@@ -1567,7 +1466,7 @@
 		layerName, it is up to the caller to inform that object that
 		the directory it represents has changed.
 		"""
-		if self._formatVersion < UFOFormatVersion.FORMAT_3_0:
+		if self._formatVersion < 3:
 			# ignore renaming glyph sets for UFO1 UFO2
 			# just write the data from the default layer
 			return
@@ -1606,7 +1505,7 @@
 		"""
 		Remove the glyph set matching layerName.
 		"""
-		if self._formatVersion < UFOFormatVersion.FORMAT_3_0:
+		if self._formatVersion < 3:
 			# ignore deleting glyph sets for UFO1 UFO2 as there are no layers
 			# just write the data from the default layer
 			return
@@ -1619,13 +1518,13 @@
 		Write data to fileName in the 'data' directory.
 		The data must be a bytes string.
 		"""
-		self.writeBytesToPath(f"{DATA_DIRNAME}/{fsdecode(fileName)}", data)
+		self.writeBytesToPath("%s/%s" % (DATA_DIRNAME, fsdecode(fileName)), data)
 
 	def removeData(self, fileName):
 		"""
 		Remove the file named fileName from the data directory.
 		"""
-		self.removePath(f"{DATA_DIRNAME}/{fsdecode(fileName)}")
+		self.removePath("%s/%s" % (DATA_DIRNAME, fsdecode(fileName)))
 
 	# /images
 
@@ -1636,27 +1535,23 @@
 		"""
 		if validate is None:
 			validate = self._validate
-		if self._formatVersion < UFOFormatVersion.FORMAT_3_0:
-			raise UFOLibError(
-				f"Images are not allowed in UFO {self._formatVersion.major}."
-			)
+		if self._formatVersion < 3:
+			raise UFOLibError("Images are not allowed in UFO %d." % self._formatVersion)
 		fileName = fsdecode(fileName)
 		if validate:
 			valid, error = pngValidator(data=data)
 			if not valid:
 				raise UFOLibError(error)
-		self.writeBytesToPath(f"{IMAGES_DIRNAME}/{fileName}", data)
+		self.writeBytesToPath("%s/%s" % (IMAGES_DIRNAME, fileName), data)
 
 	def removeImage(self, fileName, validate=None):  # XXX remove unused 'validate'?
 		"""
 		Remove the file named fileName from the
 		images directory.
 		"""
-		if self._formatVersion < UFOFormatVersion.FORMAT_3_0:
-			raise UFOLibError(
-				f"Images are not allowed in UFO {self._formatVersion.major}."
-			)
-		self.removePath(f"{IMAGES_DIRNAME}/{fsdecode(fileName)}")
+		if self._formatVersion < 3:
+			raise UFOLibError("Images are not allowed in UFO %d." % self._formatVersion)
+		self.removePath("%s/%s" % (IMAGES_DIRNAME, fsdecode(fileName)))
 
 	def copyImageFromReader(self, reader, sourceFileName, destFileName, validate=None):
 		"""
@@ -1666,12 +1561,10 @@
 		"""
 		if validate is None:
 			validate = self._validate
-		if self._formatVersion < UFOFormatVersion.FORMAT_3_0:
-			raise UFOLibError(
-				f"Images are not allowed in UFO {self._formatVersion.major}."
-			)
-		sourcePath = f"{IMAGES_DIRNAME}/{fsdecode(sourceFileName)}"
-		destPath = f"{IMAGES_DIRNAME}/{fsdecode(destFileName)}"
+		if self._formatVersion < 3:
+			raise UFOLibError("Images are not allowed in UFO %d." % self._formatVersion)
+		sourcePath = "%s/%s" % (IMAGES_DIRNAME, fsdecode(sourceFileName))
+		destPath = "%s/%s" % (IMAGES_DIRNAME, fsdecode(destFileName))
 		self.copyFromReader(reader, sourcePath, destPath)
 
 	def close(self):
@@ -1681,7 +1574,7 @@
 			rootDir = os.path.splitext(os.path.basename(self._path))[0] + ".ufo"
 			with fs.zipfs.ZipFS(self._path, write=True, encoding="utf-8") as destFS:
 				fs.copy.copy_fs(self.fs, destFS.makedir(rootDir))
-		super().close()
+		super(UFOWriter, self).close()
 
 
 # just an alias, makes it more explicit
@@ -1694,7 +1587,7 @@
 
 
 def _sniffFileStructure(ufo_path):
-	"""Return UFOFileStructure.ZIP if the UFO at path 'ufo_path' (str)
+	"""Return UFOFileStructure.ZIP if the UFO at path 'ufo_path' (basestring)
 	is a zip file, else return UFOFileStructure.PACKAGE if 'ufo_path' is a
 	directory.
 	Raise UFOLibError if it is a file with unknown structure, or if the path
@@ -1776,7 +1669,7 @@
 	for attr, value in list(infoData.items()):
 		isValidValue = validateFontInfoVersion2ValueForAttribute(attr, value)
 		if not isValidValue:
-			raise UFOLibError(f"Invalid value for attribute {attr} ({value!r}).")
+			raise UFOLibError("Invalid value for attribute %s (%s)." % (attr, repr(value)))
 		else:
 			validInfoData[attr] = value
 	return validInfoData
@@ -1820,7 +1713,7 @@
 	for attr, value in list(infoData.items()):
 		isValidValue = validateFontInfoVersion3ValueForAttribute(attr, value)
 		if not isValidValue:
-			raise UFOLibError(f"Invalid value for attribute {attr} ({value!r}).")
+			raise UFOLibError("Invalid value for attribute %s (%s)." % (attr, repr(value)))
 		else:
 			validInfoData[attr] = value
 	return validInfoData
@@ -1838,7 +1731,7 @@
 # cases the possible values, that can exist is
 # fontinfo.plist.
 
-fontInfoAttributesVersion1 = {
+fontInfoAttributesVersion1 = set([
 	"familyName",
 	"styleName",
 	"fullName",
@@ -1879,26 +1772,26 @@
 	"ttVendor",
 	"ttUniqueID",
 	"ttVersion",
-}
+])
 
 fontInfoAttributesVersion2ValueData = {
-	"familyName"							: dict(type=str),
-	"styleName"								: dict(type=str),
-	"styleMapFamilyName"					: dict(type=str),
-	"styleMapStyleName"						: dict(type=str, valueValidator=fontInfoStyleMapStyleNameValidator),
+	"familyName"							: dict(type=basestring),
+	"styleName"								: dict(type=basestring),
+	"styleMapFamilyName"					: dict(type=basestring),
+	"styleMapStyleName"						: dict(type=basestring, valueValidator=fontInfoStyleMapStyleNameValidator),
 	"versionMajor"							: dict(type=int),
 	"versionMinor"							: dict(type=int),
 	"year"									: dict(type=int),
-	"copyright"								: dict(type=str),
-	"trademark"								: dict(type=str),
+	"copyright"								: dict(type=basestring),
+	"trademark"								: dict(type=basestring),
 	"unitsPerEm"							: dict(type=(int, float)),
 	"descender"								: dict(type=(int, float)),
 	"xHeight"								: dict(type=(int, float)),
 	"capHeight"								: dict(type=(int, float)),
 	"ascender"								: dict(type=(int, float)),
 	"italicAngle"							: dict(type=(float, int)),
-	"note"									: dict(type=str),
-	"openTypeHeadCreated"					: dict(type=str, valueValidator=fontInfoOpenTypeHeadCreatedValidator),
+	"note"									: dict(type=basestring),
+	"openTypeHeadCreated"					: dict(type=basestring, valueValidator=fontInfoOpenTypeHeadCreatedValidator),
 	"openTypeHeadLowestRecPPEM"				: dict(type=(int, float)),
 	"openTypeHeadFlags"						: dict(type="integerList", valueValidator=genericIntListValidator, valueOptions=fontInfoOpenTypeHeadFlagsOptions),
 	"openTypeHheaAscender"					: dict(type=(int, float)),
@@ -1907,25 +1800,25 @@
 	"openTypeHheaCaretSlopeRise"			: dict(type=int),
 	"openTypeHheaCaretSlopeRun"				: dict(type=int),
 	"openTypeHheaCaretOffset"				: dict(type=(int, float)),
-	"openTypeNameDesigner"					: dict(type=str),
-	"openTypeNameDesignerURL"				: dict(type=str),
-	"openTypeNameManufacturer"				: dict(type=str),
-	"openTypeNameManufacturerURL"			: dict(type=str),
-	"openTypeNameLicense"					: dict(type=str),
-	"openTypeNameLicenseURL"				: dict(type=str),
-	"openTypeNameVersion"					: dict(type=str),
-	"openTypeNameUniqueID"					: dict(type=str),
-	"openTypeNameDescription"				: dict(type=str),
-	"openTypeNamePreferredFamilyName"		: dict(type=str),
-	"openTypeNamePreferredSubfamilyName"	: dict(type=str),
-	"openTypeNameCompatibleFullName"		: dict(type=str),
-	"openTypeNameSampleText"				: dict(type=str),
-	"openTypeNameWWSFamilyName"				: dict(type=str),
-	"openTypeNameWWSSubfamilyName"			: dict(type=str),
+	"openTypeNameDesigner"					: dict(type=basestring),
+	"openTypeNameDesignerURL"				: dict(type=basestring),
+	"openTypeNameManufacturer"				: dict(type=basestring),
+	"openTypeNameManufacturerURL"			: dict(type=basestring),
+	"openTypeNameLicense"					: dict(type=basestring),
+	"openTypeNameLicenseURL"				: dict(type=basestring),
+	"openTypeNameVersion"					: dict(type=basestring),
+	"openTypeNameUniqueID"					: dict(type=basestring),
+	"openTypeNameDescription"				: dict(type=basestring),
+	"openTypeNamePreferredFamilyName"		: dict(type=basestring),
+	"openTypeNamePreferredSubfamilyName"	: dict(type=basestring),
+	"openTypeNameCompatibleFullName"		: dict(type=basestring),
+	"openTypeNameSampleText"				: dict(type=basestring),
+	"openTypeNameWWSFamilyName"				: dict(type=basestring),
+	"openTypeNameWWSSubfamilyName"			: dict(type=basestring),
 	"openTypeOS2WidthClass"					: dict(type=int, valueValidator=fontInfoOpenTypeOS2WidthClassValidator),
 	"openTypeOS2WeightClass"				: dict(type=int, valueValidator=fontInfoOpenTypeOS2WeightClassValidator),
 	"openTypeOS2Selection"					: dict(type="integerList", valueValidator=genericIntListValidator, valueOptions=fontInfoOpenTypeOS2SelectionOptions),
-	"openTypeOS2VendorID"					: dict(type=str),
+	"openTypeOS2VendorID"					: dict(type=basestring),
 	"openTypeOS2Panose"						: dict(type="integerList", valueValidator=fontInfoVersion2OpenTypeOS2PanoseValidator),
 	"openTypeOS2FamilyClass"				: dict(type="integerList", valueValidator=fontInfoOpenTypeOS2FamilyClassValidator),
 	"openTypeOS2UnicodeRanges"				: dict(type="integerList", valueValidator=genericIntListValidator, valueOptions=fontInfoOpenTypeOS2UnicodeRangesOptions),
@@ -1952,8 +1845,8 @@
 	"openTypeVheaCaretSlopeRise"			: dict(type=int),
 	"openTypeVheaCaretSlopeRun"				: dict(type=int),
 	"openTypeVheaCaretOffset"				: dict(type=(int, float)),
-	"postscriptFontName"					: dict(type=str),
-	"postscriptFullName"					: dict(type=str),
+	"postscriptFontName"					: dict(type=basestring),
+	"postscriptFullName"					: dict(type=basestring),
 	"postscriptSlantAngle"					: dict(type=(float, int)),
 	"postscriptUniqueID"					: dict(type=int),
 	"postscriptUnderlineThickness"			: dict(type=(int, float)),
@@ -1971,11 +1864,11 @@
 	"postscriptForceBold"					: dict(type=bool),
 	"postscriptDefaultWidthX"				: dict(type=(int, float)),
 	"postscriptNominalWidthX"				: dict(type=(int, float)),
-	"postscriptWeightName"					: dict(type=str),
-	"postscriptDefaultCharacter"			: dict(type=str),
+	"postscriptWeightName"					: dict(type=basestring),
+	"postscriptDefaultCharacter"			: dict(type=basestring),
 	"postscriptWindowsCharacterSet"			: dict(type=int, valueValidator=fontInfoPostscriptWindowsCharacterSetValidator),
 	"macintoshFONDFamilyID"					: dict(type=int),
-	"macintoshFONDName"						: dict(type=str),
+	"macintoshFONDName"						: dict(type=basestring),
 }
 fontInfoAttributesVersion2 = set(fontInfoAttributesVersion2ValueData.keys())
 
@@ -2150,17 +2043,17 @@
 		if attr == "fontStyle":
 			v = _fontStyle1To2.get(value)
 			if v is None:
-				raise UFOLibError(f"Cannot convert value ({value!r}) for attribute {attr}.")
+				raise UFOLibError("Cannot convert value (%s) for attribute %s." % (repr(value), attr))
 			value = v
 		elif attr == "widthName":
 			v = _widthName1To2.get(value)
 			if v is None:
-				raise UFOLibError(f"Cannot convert value ({value!r}) for attribute {attr}.")
+				raise UFOLibError("Cannot convert value (%s) for attribute %s." % (repr(value), attr))
 			value = v
 		elif attr == "msCharSet":
 			v = _msCharSet1To2.get(value)
 			if v is None:
-				raise UFOLibError(f"Cannot convert value ({value!r}) for attribute {attr}.")
+				raise UFOLibError("Cannot convert value (%s) for attribute %s." % (repr(value), attr))
 			value = v
 	attr = fontInfoAttributesVersion1To2.get(attr, attr)
 	return attr, value
@@ -2195,7 +2088,7 @@
 			continue
 		# catch values that can't be converted
 		if value is None:
-			raise UFOLibError(f"Cannot convert value ({value!r}) for attribute {newAttr}.")
+			raise UFOLibError("Cannot convert value (%s) for attribute %s." % (repr(value), newAttr))
 		# store
 		converted[newAttr] = newValue
 	return converted
@@ -2209,23 +2102,23 @@
 			continue
 		# catch values that can't be converted
 		if value is None:
-			raise UFOLibError(f"Cannot convert value ({value!r}) for attribute {newAttr}.")
+			raise UFOLibError("Cannot convert value (%s) for attribute %s." % (repr(value), newAttr))
 		# store
 		converted[newAttr] = newValue
 	return converted
 
 # 2 <-> 3
 
-_ufo2To3NonNegativeInt = {
+_ufo2To3NonNegativeInt = set((
 	"versionMinor",
 	"openTypeHeadLowestRecPPEM",
 	"openTypeOS2WinAscent",
 	"openTypeOS2WinDescent"
-}
-_ufo2To3NonNegativeIntOrFloat = {
-	"unitsPerEm",
-}
-_ufo2To3FloatToInt = {
+))
+_ufo2To3NonNegativeIntOrFloat = set((
+	"unitsPerEm"
+))
+_ufo2To3FloatToInt = set(((
 	"openTypeHeadLowestRecPPEM",
 	"openTypeHheaAscender",
 	"openTypeHheaDescender",
@@ -2250,7 +2143,7 @@
 	"openTypeVheaVertTypoDescender",
 	"openTypeVheaVertTypoLineGap",
 	"openTypeVheaCaretOffset"
-}
+)))
 
 def convertFontInfoValueForAttributeFromVersion2ToVersion3(attr, value):
 	"""
@@ -2260,14 +2153,18 @@
 	"""
 	if attr in _ufo2To3FloatToInt:
 		try:
-			value = round(value)
+			v = int(round(value))
 		except (ValueError, TypeError):
 			raise UFOLibError("Could not convert value for %s." % attr)
+		if v != value:
+			value = v
 	if attr in _ufo2To3NonNegativeInt:
 		try:
-			value = int(abs(value))
+			v = int(abs(value))
 		except (ValueError, TypeError):
 			raise UFOLibError("Could not convert value for %s." % attr)
+		if v != value:
+			value = v
 	elif attr in _ufo2To3NonNegativeIntOrFloat:
 		try:
 			v = float(abs(value))
diff --git a/Lib/fontTools/ufoLib/converters.py b/Lib/fontTools/ufoLib/converters.py
index 3b8112c..c9ec990 100644
--- a/Lib/fontTools/ufoLib/converters.py
+++ b/Lib/fontTools/ufoLib/converters.py
@@ -2,20 +2,21 @@
 Conversion functions.
 """
 
+from __future__ import absolute_import, unicode_literals
 
 
 # adapted from the UFO spec
 
-def convertUFO1OrUFO2KerningToUFO3Kerning(kerning, groups, glyphSet=()):
+def convertUFO1OrUFO2KerningToUFO3Kerning(kerning, groups):
     # gather known kerning groups based on the prefixes
     firstReferencedGroups, secondReferencedGroups = findKnownKerningGroups(groups)
     # Make lists of groups referenced in kerning pairs.
     for first, seconds in list(kerning.items()):
-        if first in groups and first not in glyphSet:
+        if first in groups:
             if not first.startswith("public.kern1."):
                 firstReferencedGroups.add(first)
         for second in list(seconds.keys()):
-            if second in groups and second not in glyphSet:
+            if second in groups:
                 if not second.startswith("public.kern2."):
                     secondReferencedGroups.add(second)
     # Create new names for these groups.
@@ -154,7 +155,7 @@
     ...     "DGroup" : ["D"],
     ... }
     >>> kerning, groups, maps = convertUFO1OrUFO2KerningToUFO3Kerning(
-    ...     testKerning, testGroups, [])
+    ...     testKerning, testGroups)
     >>> expected = {
     ...     "A" : {
     ...         "A": 1,
@@ -220,7 +221,7 @@
     ...     "@MMK_R_XGroup" : ["X"],
     ... }
     >>> kerning, groups, maps = convertUFO1OrUFO2KerningToUFO3Kerning(
-    ...     testKerning, testGroups, [])
+    ...     testKerning, testGroups)
     >>> expected = {
     ...     "A" : {
     ...         "A": 1,
@@ -293,7 +294,7 @@
     ...     "DGroup" : ["D"],
     ... }
     >>> kerning, groups, maps = convertUFO1OrUFO2KerningToUFO3Kerning(
-    ...     testKerning, testGroups, [])
+    ...     testKerning, testGroups)
     >>> expected = {
     ...     "A" : {
     ...         "A": 1,
diff --git a/Lib/fontTools/ufoLib/errors.py b/Lib/fontTools/ufoLib/errors.py
index 304345e..fb048d1 100644
--- a/Lib/fontTools/ufoLib/errors.py
+++ b/Lib/fontTools/ufoLib/errors.py
@@ -1,16 +1,9 @@
+from __future__ import absolute_import, unicode_literals
 
 
 class UFOLibError(Exception):
     pass
 
 
-class UnsupportedUFOFormat(UFOLibError):
-    pass
-
-
 class GlifLibError(UFOLibError):
     pass
-
-
-class UnsupportedGLIFFormat(GlifLibError):
-    pass
diff --git a/Lib/fontTools/ufoLib/filenames.py b/Lib/fontTools/ufoLib/filenames.py
index 2815469..1c5630f 100644
--- a/Lib/fontTools/ufoLib/filenames.py
+++ b/Lib/fontTools/ufoLib/filenames.py
@@ -1,7 +1,10 @@
 """
 User name to file name conversion.
-This was taken from the UFO 3 spec.
+This was taken form the UFO 3 spec.
 """
+from __future__ import absolute_import, unicode_literals
+from fontTools.misc.py23 import basestring, unicode
+
 
 illegalCharacters = r"\" * + / : < > ? [ \ ] | \0".split(" ")
 illegalCharacters += [chr(i) for i in range(1, 32)]
@@ -15,7 +18,7 @@
 	pass
 
 
-def userNameToFileName(userName: str, existing=[], prefix="", suffix=""):
+def userNameToFileName(userName, existing=[], prefix="", suffix=""):
 	"""
 	existing should be a case-insensitive list
 	of all existing file names.
@@ -65,9 +68,9 @@
 	>>> userNameToFileName("alt.con") == "alt._con"
 	True
 	"""
-	# the incoming name must be a string
-	if not isinstance(userName, str):
-		raise ValueError("The value for userName must be a string.")
+	# the incoming name must be a unicode string
+	if not isinstance(userName, unicode):
+		raise ValueError("The value for userName must be a unicode string.")
 	# establish the prefix and suffix lengths
 	prefixLength = len(prefix)
 	suffixLength = len(suffix)
diff --git a/Lib/fontTools/ufoLib/glifLib.py b/Lib/fontTools/ufoLib/glifLib.py
index 3003110..99dd2cf 100755
--- a/Lib/fontTools/ufoLib/glifLib.py
+++ b/Lib/fontTools/ufoLib/glifLib.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 """
 glifLib.py -- Generic module for reading and writing the .glif format.
 
@@ -10,8 +11,7 @@
 glyph data. See the class doc string for details.
 """
 
-import logging
-import enum
+from __future__ import absolute_import, unicode_literals
 from warnings import warn
 from collections import OrderedDict
 import fs
@@ -19,7 +19,7 @@
 import fs.errors
 import fs.osfs
 import fs.path
-from fontTools.misc.py23 import tobytes
+from fontTools.misc.py23 import basestring, unicode, tobytes, tounicode
 from fontTools.misc import plistlib
 from fontTools.pens.pointPen import AbstractPointPen, PointToSegmentPen
 from fontTools.ufoLib.errors import GlifLibError
@@ -34,8 +34,8 @@
 	glyphLibValidator,
 )
 from fontTools.misc import etree
-from fontTools.ufoLib import _UFOBaseIO, UFOFormatVersion
-from fontTools.ufoLib.utils import numberTypes, _VersionTupleEnumMixin
+from fontTools.ufoLib import _UFOBaseIO
+from fontTools.ufoLib.utils import integerTypes, numberTypes
 
 
 __all__ = [
@@ -45,8 +45,6 @@
 	"glyphNameToFileName"
 ]
 
-logger = logging.getLogger(__name__)
-
 
 # ---------
 # Constants
@@ -54,35 +52,15 @@
 
 CONTENTS_FILENAME = "contents.plist"
 LAYERINFO_FILENAME = "layerinfo.plist"
-
-
-class GLIFFormatVersion(tuple, _VersionTupleEnumMixin, enum.Enum):
-	FORMAT_1_0 = (1, 0)
-	FORMAT_2_0 = (2, 0)
-
-	@classmethod
-	def default(cls, ufoFormatVersion=None):
-		if ufoFormatVersion is not None:
-			return max(cls.supported_versions(ufoFormatVersion))
-		return super().default()
-
-	@classmethod
-	def supported_versions(cls, ufoFormatVersion=None):
-		if ufoFormatVersion is None:
-			# if ufo format unspecified, return all the supported GLIF formats
-			return super().supported_versions()
-		# else only return the GLIF formats supported by the given UFO format
-		versions = {cls.FORMAT_1_0}
-		if ufoFormatVersion >= UFOFormatVersion.FORMAT_3_0:
-			versions.add(cls.FORMAT_2_0)
-		return frozenset(versions)
+supportedUFOFormatVersions = [1, 2, 3]
+supportedGLIFFormatVersions = [1, 2]
 
 
 # ------------
 # Simple Glyph
 # ------------
 
-class Glyph:
+class Glyph(object):
 
 	"""
 	Minimal glyph object. It has no glyph attributes until either
@@ -132,10 +110,9 @@
 		self,
 		path,
 		glyphNameToFileNameFunc=None,
-		ufoFormatVersion=None,
+		ufoFormatVersion=3,
 		validateRead=True,
 		validateWrite=True,
-		expectContentsFile=False,
 	):
 		"""
 		'path' should be a path (string) to an existing local directory, or
@@ -149,23 +126,10 @@
 
 		``validateRead`` will validate read operations. Its default is ``True``.
 		``validateWrite`` will validate write operations. Its default is ``True``.
-		``expectContentsFile`` will raise a GlifLibError if a contents.plist file is
-		not found on the glyph set file system. This should be set to ``True`` if you
-		are reading an existing UFO and ``False`` if you create a fresh	glyph set.
 		"""
-		try:
-			ufoFormatVersion = UFOFormatVersion(ufoFormatVersion)
-		except ValueError as e:
-			from fontTools.ufoLib.errors import UnsupportedUFOFormat
-
-			raise UnsupportedUFOFormat(
-				f"Unsupported UFO format: {ufoFormatVersion!r}"
-			) from e
-
-		if hasattr(path, "__fspath__"):  # support os.PathLike objects
-			path = path.__fspath__()
-
-		if isinstance(path, str):
+		if ufoFormatVersion not in supportedUFOFormatVersions:
+			raise GlifLibError("Unsupported UFO format version: %s" % ufoFormatVersion)
+		if isinstance(path, basestring):
 			try:
 				filesystem = fs.osfs.OSFS(path)
 			except fs.errors.CreateFailed:
@@ -187,7 +151,7 @@
 			path = filesystem.getsyspath("/")
 		except fs.errors.NoSysPath:
 			# network or in-memory FS may not map to the local one
-			path = str(filesystem)
+			path = unicode(filesystem)
 		# 'dirName' is kept for backward compatibility only, but it's DEPRECATED
 		# as it's not guaranteed that it maps to an existing OSFS directory.
 		# Client could use the FS api via the `self.fs` attribute instead.
@@ -195,11 +159,7 @@
 		self.fs = filesystem
 		# if glyphSet contains no 'contents.plist', we consider it empty
 		self._havePreviousFile = filesystem.exists(CONTENTS_FILENAME)
-		if expectContentsFile and not self._havePreviousFile:
-			raise GlifLibError(f"{CONTENTS_FILENAME} is missing.")
-		# attribute kept for backward compatibility
-		self.ufoFormatVersion = ufoFormatVersion.major
-		self.ufoFormatVersionTuple = ufoFormatVersion
+		self.ufoFormatVersion = ufoFormatVersion
 		if glyphNameToFileNameFunc is None:
 			glyphNameToFileNameFunc = glyphNameToFileName
 		self.glyphNameToFileName = glyphNameToFileNameFunc
@@ -227,9 +187,9 @@
 				invalidFormat = True
 			else:
 				for name, fileName in contents.items():
-					if not isinstance(name, str):
+					if not isinstance(name, basestring):
 						invalidFormat = True
-					if not isinstance(fileName, str):
+					if not isinstance(fileName, basestring):
 						invalidFormat = True
 					elif not self.fs.exists(fileName):
 						raise GlifLibError(
@@ -293,10 +253,8 @@
 		"""
 		if validateWrite is None:
 			validateWrite = self._validateWrite
-		if self.ufoFormatVersionTuple.major < 3:
-			raise GlifLibError(
-				"layerinfo.plist is not allowed in UFO %d." % self.ufoFormatVersionTuple.major
-			)
+		if self.ufoFormatVersion < 3:
+			raise GlifLibError("layerinfo.plist is not allowed in UFO %d." % self.ufoFormatVersion)
 		# gather data
 		infoData = {}
 		for attr in layerInfoVersion3ValueData.keys():
@@ -390,7 +348,10 @@
 			validate = self._validateRead
 		text = self.getGLIF(glyphName)
 		tree = _glifTreeFromString(text)
-		formatVersions = GLIFFormatVersion.supported_versions(self.ufoFormatVersionTuple)
+		if self.ufoFormatVersion < 3:
+			formatVersions = (1,)
+		else:
+			formatVersions = (1, 2)
 		_readGlyphFromTree(tree, glyphObject, pointPen, formatVersions=formatVersions, validate=validate)
 
 	def writeGlyph(self, glyphName, glyphObject=None, drawPointsFunc=None, formatVersion=None, validate=None):
@@ -420,35 +381,21 @@
 		The GLIF format version will be chosen based on the ufoFormatVersion
 		passed during the creation of this object. If a particular format
 		version is desired, it can be passed with the formatVersion argument.
-		The formatVersion argument accepts either a tuple of integers for
-		(major, minor), or a single integer for the major digit only (with
-		minor digit implied as 0).
-
-		An UnsupportedGLIFFormat exception is raised if the requested GLIF
-		formatVersion is not supported.
 
 		``validate`` will validate the data, by default it is set to the
 		class's ``validateWrite`` value, can be overridden.
 		"""
 		if formatVersion is None:
-			formatVersion = GLIFFormatVersion.default(self.ufoFormatVersionTuple)
-		else:
-			try:
-				formatVersion = GLIFFormatVersion(formatVersion)
-			except ValueError as e:
-				from fontTools.ufoLib.errors import UnsupportedGLIFFormat
-
-				raise UnsupportedGLIFFormat(
-					f"Unsupported GLIF format version: {formatVersion!r}"
-				) from e
-		if formatVersion not in GLIFFormatVersion.supported_versions(
-			self.ufoFormatVersionTuple
-		):
-			from fontTools.ufoLib.errors import UnsupportedGLIFFormat
-
-			raise UnsupportedGLIFFormat(
-				f"Unsupported GLIF format version ({formatVersion!s}) "
-				f"for UFO format version {self.ufoFormatVersionTuple!s}."
+			if self.ufoFormatVersion >= 3:
+				formatVersion = 2
+			else:
+				formatVersion = 1
+		if formatVersion not in supportedGLIFFormatVersions:
+			raise GlifLibError("Unsupported GLIF format version: %s" % formatVersion)
+		if formatVersion == 2 and self.ufoFormatVersion < 3:
+			raise GlifLibError(
+				"Unsupported GLIF format version (%d) for UFO format version %d."
+				% (formatVersion, self.ufoFormatVersion)
 			)
 		if validate is None:
 			validate = self._validateWrite
@@ -458,7 +405,7 @@
 				self._existingFileNames = {}
 				for fileName in self.contents.values():
 					self._existingFileNames[fileName] = fileName.lower()
-			fileName = self.glyphNameToFileName(glyphName, self._existingFileNames.values())
+			fileName = self.glyphNameToFileName(glyphName, self._existingFileNames)
 			self.contents[glyphName] = fileName
 			self._existingFileNames[fileName] = fileName.lower()
 			if self._reverseContents is not None:
@@ -576,19 +523,19 @@
 	"""
 	if existingFileNames is None:
 		existingFileNames = []
+	if not isinstance(glyphName, unicode):
+		try:
+			new = unicode(glyphName)
+			glyphName = new
+		except UnicodeDecodeError:
+			pass
 	return userNameToFileName(glyphName, existing=existingFileNames, suffix=".glif")
 
 # -----------------------
 # GLIF To and From String
 # -----------------------
 
-def readGlyphFromString(
-	aString,
-	glyphObject=None,
-	pointPen=None,
-	formatVersions=None,
-	validate=True,
-):
+def readGlyphFromString(aString, glyphObject=None, pointPen=None, formatVersions=(1, 2), validate=True):
 	"""
 	Read .glif data from a string into a glyph object.
 
@@ -617,65 +564,25 @@
 	conforming to the PointPen protocol as the 'pointPen' argument.
 	This argument may be None if you don't need the outline data.
 
-	The formatVersions optional argument define the GLIF format versions
+	The formatVersions argument defined the GLIF format versions
 	that are allowed to be read.
-	The type is Optional[Iterable[Tuple[int, int], int]]. It can contain
-	either integers (for the major versions to be allowed, with minor
-	digits defaulting to 0), or tuples of integers to specify both
-	(major, minor) versions.
-	By default when formatVersions is None all the GLIF format versions
-	currently defined are allowed to be read.
 
 	``validate`` will validate the read data. It is set to ``True`` by default.
 	"""
 	tree = _glifTreeFromString(aString)
-
-	if formatVersions is None:
-		validFormatVersions = GLIFFormatVersion.supported_versions()
-	else:
-		validFormatVersions, invalidFormatVersions = set(), set()
-		for v in formatVersions:
-			try:
-				formatVersion = GLIFFormatVersion(v)
-			except ValueError:
-				invalidFormatVersions.add(v)
-			else:
-				validFormatVersions.add(formatVersion)
-		if not validFormatVersions:
-			raise ValueError(
-				"None of the requested GLIF formatVersions are supported: "
-				f"{formatVersions!r}"
-			)
-
-	_readGlyphFromTree(
-		tree, glyphObject, pointPen, formatVersions=validFormatVersions, validate=validate
-	)
+	_readGlyphFromTree(tree, glyphObject, pointPen, formatVersions=formatVersions, validate=validate)
 
 
 def _writeGlyphToBytes(
-		glyphName,
-		glyphObject=None,
-		drawPointsFunc=None,
-		writer=None,
-		formatVersion=None,
-		validate=True,
-):
+		glyphName, glyphObject=None, drawPointsFunc=None, writer=None,
+		formatVersion=2, validate=True):
 	"""Return .glif data for a glyph as a UTF-8 encoded bytes string."""
-	try:
-		formatVersion = GLIFFormatVersion(formatVersion)
-	except ValueError:
-		from fontTools.ufoLib.errors import UnsupportedGLIFFormat
-
-		raise UnsupportedGLIFFormat("Unsupported GLIF format version: {formatVersion!r}")
 	# start
-	if validate and not isinstance(glyphName, str):
+	if validate and not isinstance(glyphName, basestring):
 		raise GlifLibError("The glyph name is not properly formatted.")
 	if validate and len(glyphName) == 0:
 		raise GlifLibError("The glyph name is empty.")
-	glyphAttrs = OrderedDict([("name", glyphName), ("format", repr(formatVersion.major))])
-	if formatVersion.minor != 0:
-		glyphAttrs["formatMinor"] = repr(formatVersion.minor)
-	root = etree.Element("glyph", glyphAttrs)
+	root = etree.Element("glyph", OrderedDict([("name", glyphName), ("format", repr(formatVersion))]))
 	identifiers = set()
 	# advance
 	_writeAdvance(glyphObject, root, validate)
@@ -686,21 +593,21 @@
 	if getattr(glyphObject, "note", None):
 		_writeNote(glyphObject, root, validate)
 	# image
-	if formatVersion.major >= 2 and getattr(glyphObject, "image", None):
+	if formatVersion >= 2 and getattr(glyphObject, "image", None):
 		_writeImage(glyphObject, root, validate)
 	# guidelines
-	if formatVersion.major >= 2 and getattr(glyphObject, "guidelines", None):
+	if formatVersion >= 2 and getattr(glyphObject, "guidelines", None):
 		_writeGuidelines(glyphObject, root, identifiers, validate)
 	# anchors
 	anchors = getattr(glyphObject, "anchors", None)
-	if formatVersion.major >= 2 and anchors:
+	if formatVersion >= 2 and anchors:
 		_writeAnchors(glyphObject, root, identifiers, validate)
 	# outline
 	if drawPointsFunc is not None:
 		outline = etree.SubElement(root, "outline")
 		pen = GLIFPointPen(outline, identifiers=identifiers, validate=validate)
 		drawPointsFunc(pen)
-		if formatVersion.major == 1 and anchors:
+		if formatVersion == 1 and anchors:
 			_writeAnchorsFormat1(pen, anchors, validate)
 		# prevent lxml from writing self-closing tags
 		if not len(outline):
@@ -715,16 +622,10 @@
 	return data
 
 
-def writeGlyphToString(
-	glyphName,
-	glyphObject=None,
-	drawPointsFunc=None,
-	formatVersion=None,
-	validate=True,
-):
+def writeGlyphToString(glyphName, glyphObject=None, drawPointsFunc=None, formatVersion=2, validate=True):
 	"""
-	Return .glif data for a glyph as a string. The XML declaration's
-	encoding is always set to "UTF-8".
+	Return .glif data for a glyph as a Unicode string (`unicode` in py2, `str`
+	in py3). The XML declaration's encoding is always set to "UTF-8".
 	The 'glyphObject' argument can be any kind of object (even None);
 	the writeGlyphToString() method will attempt to get the following
 	attributes from it:
@@ -747,13 +648,6 @@
 	proper PointPen methods to transfer the outline to the .glif file.
 
 	The GLIF format version can be specified with the formatVersion argument.
-	This accepts either a tuple of integers for (major, minor), or a single
-	integer for the major digit only (with minor digit implied as 0).
-	By default when formatVesion is None the latest GLIF format version will
-	be used; currently it's 2.0, which is equivalent to formatVersion=(2, 0).
-
-	An UnsupportedGLIFFormat exception is raised if the requested UFO
-	formatVersion is not supported.
 
 	``validate`` will validate the written data. It is set to ``True`` by default.
 	"""
@@ -789,11 +683,11 @@
 
 def _writeUnicodes(glyphObject, element, validate):
 	unicodes = getattr(glyphObject, "unicodes", None)
-	if validate and isinstance(unicodes, int):
+	if validate and isinstance(unicodes, integerTypes):
 		unicodes = [unicodes]
 	seen = set()
 	for code in unicodes:
-		if validate and not isinstance(code, int):
+		if validate and not isinstance(code, integerTypes):
 			raise GlifLibError("unicode values must be int")
 		if code in seen:
 			continue
@@ -803,11 +697,12 @@
 
 def _writeNote(glyphObject, element, validate):
 	note = getattr(glyphObject, "note", None)
-	if validate and not isinstance(note, str):
-		raise GlifLibError("note attribute must be str")
+	if validate and not isinstance(note, basestring):
+		raise GlifLibError("note attribute must be str or unicode")
 	note = note.strip()
 	note = "\n" + note + "\n"
-	etree.SubElement(element, "note").text = note
+	# ensure text is unicode, if it's bytes decode as ASCII
+	etree.SubElement(element, "note").text = tounicode(note)
 
 def _writeImage(glyphObject, element, validate):
 	image = getattr(glyphObject, "image", None)
@@ -912,7 +807,7 @@
 # -----------------------
 
 layerInfoVersion3ValueData = {
-	"color"			: dict(type=str, valueValidator=colorValidator),
+	"color"			: dict(type=basestring, valueValidator=colorValidator),
 	"lib"			: dict(type=dict, valueValidator=genericTypeValidator)
 }
 
@@ -958,7 +853,7 @@
 			raise GlifLibError("Unknown attribute %s." % attr)
 		isValidValue = validateLayerInfoVersion3ValueForAttribute(attr, value)
 		if not isValidValue:
-			raise GlifLibError(f"Invalid value for attribute {attr} ({value!r}).")
+			raise GlifLibError("Invalid value for attribute %s (%s)." % (attr, repr(value)))
 	return infoData
 
 # -----------------
@@ -966,11 +861,7 @@
 # -----------------
 
 def _glifTreeFromFile(aFile):
-	if etree._have_lxml:
-		tree = etree.parse(aFile, parser=etree.XMLParser(remove_comments=True))
-	else:
-		tree = etree.parse(aFile)
-	root = tree.getroot()
+	root = etree.parse(aFile).getroot()
 	if root.tag != "glyph":
 		raise GlifLibError("The GLIF is not properly formatted.")
 	if root.text and root.text.strip() != '':
@@ -980,64 +871,34 @@
 
 def _glifTreeFromString(aString):
 	data = tobytes(aString, encoding="utf-8")
-	if etree._have_lxml:
-		root = etree.fromstring(data, parser=etree.XMLParser(remove_comments=True))
-	else:
-		root = etree.fromstring(data)
+	root = etree.fromstring(data)
 	if root.tag != "glyph":
 		raise GlifLibError("The GLIF is not properly formatted.")
 	if root.text and root.text.strip() != '':
 		raise GlifLibError("Invalid GLIF structure.")
 	return root
 
-
-def _readGlyphFromTree(
-	tree,
-	glyphObject=None,
-	pointPen=None,
-	formatVersions=GLIFFormatVersion.supported_versions(),
-	validate=True,
-):
+def _readGlyphFromTree(tree, glyphObject=None, pointPen=None, formatVersions=(1, 2), validate=True):
 	# check the format version
-	formatVersionMajor = tree.get("format")
-	if validate and formatVersionMajor is None:
+	formatVersion = tree.get("format")
+	if validate and formatVersion is None:
 		raise GlifLibError("Unspecified format version in GLIF.")
-	formatVersionMinor = tree.get("formatMinor", 0)
 	try:
-		formatVersion = GLIFFormatVersion((int(formatVersionMajor), int(formatVersionMinor)))
-	except ValueError as e:
-		msg = "Unsupported GLIF format: %s.%s" % (formatVersionMajor, formatVersionMinor)
-		if validate:
-			from fontTools.ufoLib.errors import UnsupportedGLIFFormat
-
-			raise UnsupportedGLIFFormat(msg) from e
-		# warn but continue using the latest supported format
-		formatVersion = GLIFFormatVersion.default()
-		logger.warning(
-			"%s. Assuming the latest supported version (%s). "
-			"Some data may be skipped or parsed incorrectly.",
-			msg,
-			formatVersion,
-		)
-
+		v = int(formatVersion)
+		formatVersion = v
+	except ValueError:
+		pass
 	if validate and formatVersion not in formatVersions:
-		raise GlifLibError(f"Forbidden GLIF format version: {formatVersion!s}")
-
-	try:
-		readGlyphFromTree = _READ_GLYPH_FROM_TREE_FUNCS[formatVersion]
-	except KeyError:
-		raise NotImplementedError(formatVersion)
-
-	readGlyphFromTree(
-		tree=tree,
-		glyphObject=glyphObject,
-		pointPen=pointPen,
-		validate=validate,
-		formatMinor=formatVersion.minor,
-	)
+		raise GlifLibError("Forbidden GLIF format version: %s" % formatVersion)
+	if formatVersion == 1:
+		_readGlyphFromTreeFormat1(tree=tree, glyphObject=glyphObject, pointPen=pointPen, validate=validate)
+	elif formatVersion == 2:
+		_readGlyphFromTreeFormat2(tree=tree, glyphObject=glyphObject, pointPen=pointPen, validate=validate)
+	else:
+		raise GlifLibError("Unsupported GLIF format version: %s" % formatVersion)
 
 
-def _readGlyphFromTreeFormat1(tree, glyphObject=None, pointPen=None, validate=None, **kwargs):
+def _readGlyphFromTreeFormat1(tree, glyphObject=None, pointPen=None, validate=None):
 	# get the name
 	_readName(glyphObject, tree, validate)
 	# populate the sub elements
@@ -1085,9 +946,7 @@
 	if unicodes:
 		_relaxedSetattr(glyphObject, "unicodes", unicodes)
 
-def _readGlyphFromTreeFormat2(
-	tree, glyphObject=None, pointPen=None, validate=None, formatMinor=0
-):
+def _readGlyphFromTreeFormat2(tree, glyphObject=None, pointPen=None, validate=None):
 	# get the name
 	_readName(glyphObject, tree, validate)
 	# populate the sub elements
@@ -1173,13 +1032,6 @@
 			raise GlifLibError("The anchors are improperly formatted.")
 		_relaxedSetattr(glyphObject, "anchors", anchors)
 
-
-_READ_GLYPH_FROM_TREE_FUNCS = {
-	GLIFFormatVersion.FORMAT_1_0: _readGlyphFromTreeFormat1,
-	GLIFFormatVersion.FORMAT_2_0: _readGlyphFromTreeFormat2,
-}
-
-
 def _readName(glyphObject, root, validate):
 	glyphName = root.get("name")
 	if validate and not glyphName:
@@ -1221,13 +1073,13 @@
 # GLIF to PointPen
 # ----------------
 
-contourAttributesFormat2 = {"identifier"}
-componentAttributesFormat1 = {"base", "xScale", "xyScale", "yxScale", "yScale", "xOffset", "yOffset"}
-componentAttributesFormat2 = componentAttributesFormat1 | {"identifier"}
-pointAttributesFormat1 = {"x", "y", "type", "smooth", "name"}
-pointAttributesFormat2 = pointAttributesFormat1 | {"identifier"}
-pointSmoothOptions = {"no", "yes"}
-pointTypeOptions = {"move", "line", "offcurve", "curve", "qcurve"}
+contourAttributesFormat2 = set(["identifier"])
+componentAttributesFormat1 = set(["base", "xScale", "xyScale", "yxScale", "yScale", "xOffset", "yOffset"])
+componentAttributesFormat2 = componentAttributesFormat1 | set(["identifier"])
+pointAttributesFormat1 = set(["x", "y", "type", "smooth", "name"])
+pointAttributesFormat2 = pointAttributesFormat1 | set(["identifier"])
+pointSmoothOptions = set(("no", "yes"))
+pointTypeOptions = set(["move", "line", "offcurve", "curve", "qcurve"])
 
 # format 1
 
@@ -1422,10 +1274,10 @@
 				raise GlifLibError("Unknown child elements in point element.")
 		# x and y are required
 		for attr in ("x", "y"):
-			try:
-				point[attr] = _number(point[attr])
-			except KeyError as e:
-				raise GlifLibError(f"Required {attr} attribute is missing in point element.") from e
+			value = element.get(attr)
+			if validate and value is None:
+				raise GlifLibError("Required %s attribute is missing in point element." % attr)
+			point[attr] = _number(value)
 		# segment type
 		pointType = point.pop("type", "offcurve")
 		if validate and pointType not in pointTypeOptions:
@@ -1537,7 +1389,7 @@
 
 class _DoneParsing(Exception): pass
 
-class _BaseParser:
+class _BaseParser(object):
 
 	def __init__(self):
 		self._elementStack = []
@@ -1571,7 +1423,7 @@
 
 	def __init__(self):
 		self.unicodes = []
-		super().__init__()
+		super(_FetchUnicodesParser, self).__init__()
 
 	def startElementHandler(self, name, attrs):
 		if name == "unicode" and self._elementStack and self._elementStack[-1] == "glyph":
@@ -1583,7 +1435,7 @@
 						self.unicodes.append(value)
 				except ValueError:
 					pass
-		super().startElementHandler(name, attrs)
+		super(_FetchUnicodesParser, self).startElementHandler(name, attrs)
 
 # image
 
@@ -1602,13 +1454,13 @@
 
 	def __init__(self):
 		self.fileName = None
-		super().__init__()
+		super(_FetchImageFileNameParser, self).__init__()
 
 	def startElementHandler(self, name, attrs):
 		if name == "image" and self._elementStack and self._elementStack[-1] == "glyph":
 			self.fileName = attrs.get("fileName")
 			raise _DoneParsing
-		super().startElementHandler(name, attrs)
+		super(_FetchImageFileNameParser, self).startElementHandler(name, attrs)
 
 # component references
 
@@ -1627,19 +1479,19 @@
 
 	def __init__(self):
 		self.bases = []
-		super().__init__()
+		super(_FetchComponentBasesParser, self).__init__()
 
 	def startElementHandler(self, name, attrs):
 		if name == "component" and self._elementStack and self._elementStack[-1] == "outline":
 			base = attrs.get("base")
 			if base is not None:
 				self.bases.append(base)
-		super().startElementHandler(name, attrs)
+		super(_FetchComponentBasesParser, self).startElementHandler(name, attrs)
 
 	def endElementHandler(self, name):
 		if name == "outline":
 			raise _DoneParsing
-		super().endElementHandler(name)
+		super(_FetchComponentBasesParser, self).endElementHandler(name)
 
 # --------------
 # GLIF Point Pen
@@ -1662,10 +1514,10 @@
 	part of .glif files.
 	"""
 
-	def __init__(self, element, formatVersion=None, identifiers=None, validate=True):
+	def __init__(self, element, formatVersion=2, identifiers=None, validate=True):
 		if identifiers is None:
 			identifiers = set()
-		self.formatVersion = GLIFFormatVersion(formatVersion)
+		self.formatVersion = formatVersion
 		self.identifiers = identifiers
 		self.outline = element
 		self.contour = None
@@ -1675,7 +1527,7 @@
 
 	def beginPath(self, identifier=None, **kwargs):
 		attrs = OrderedDict()
-		if identifier is not None and self.formatVersion.major >= 2:
+		if identifier is not None and self.formatVersion >= 2:
 			if self.validate:
 				if identifier in self.identifiers:
 					raise GlifLibError("identifier used more than once: %s" % identifier)
@@ -1736,7 +1588,7 @@
 		if name is not None:
 			attrs["name"] = name
 		# identifier
-		if identifier is not None and self.formatVersion.major >= 2:
+		if identifier is not None and self.formatVersion >= 2:
 			if self.validate:
 				if identifier in self.identifiers:
 					raise GlifLibError("identifier used more than once: %s" % identifier)
@@ -1753,7 +1605,7 @@
 				raise GlifLibError("transformation values must be int or float")
 			if value != default:
 				attrs[attr] = repr(value)
-		if identifier is not None and self.formatVersion.major >= 2:
+		if identifier is not None and self.formatVersion >= 2:
 			if self.validate:
 				if identifier in self.identifiers:
 					raise GlifLibError("identifier used more than once: %s" % identifier)
diff --git a/Lib/fontTools/ufoLib/kerning.py b/Lib/fontTools/ufoLib/kerning.py
index 947222a..03e413f 100644
--- a/Lib/fontTools/ufoLib/kerning.py
+++ b/Lib/fontTools/ufoLib/kerning.py
@@ -1,3 +1,4 @@
+from __future__ import absolute_import, unicode_literals
 
 
 def lookupKerningValue(pair, kerning, groups, fallback=0, glyphToFirstGroup=None, glyphToSecondGroup=None):
diff --git a/Lib/fontTools/ufoLib/plistlib.py b/Lib/fontTools/ufoLib/plistlib.py
index 7638168..d0247bf 100644
--- a/Lib/fontTools/ufoLib/plistlib.py
+++ b/Lib/fontTools/ufoLib/plistlib.py
@@ -2,8 +2,7 @@
 for the old ufoLib.plistlib module, which was moved to fontTools.misc.plistlib.
 Please use the latter instead.
 """
-from fontTools.misc.plistlib import dump, dumps, load, loads
-from fontTools.misc.py23 import tobytes
+from fontTools.misc.plistlib import *
 
 # The following functions were part of the old py2-like ufoLib.plistlib API.
 # They are kept only for backward compatiblity.
@@ -13,7 +12,7 @@
 @deprecated("Use 'fontTools.misc.plistlib.load' instead")
 def readPlist(path_or_file):
     did_open = False
-    if isinstance(path_or_file, str):
+    if isinstance(path_or_file, basestring):
         path_or_file = open(path_or_file, "rb")
         did_open = True
     try:
@@ -26,7 +25,7 @@
 @deprecated("Use 'fontTools.misc.plistlib.dump' instead")
 def writePlist(value, path_or_file):
     did_open = False
-    if isinstance(path_or_file, str):
+    if isinstance(path_or_file, basestring):
         path_or_file = open(path_or_file, "wb")
         did_open = True
     try:
diff --git a/Lib/fontTools/ufoLib/utils.py b/Lib/fontTools/ufoLib/utils.py
index 85878b4..77e2f92 100644
--- a/Lib/fontTools/ufoLib/utils.py
+++ b/Lib/fontTools/ufoLib/utils.py
@@ -1,11 +1,51 @@
 """The module contains miscellaneous helpers.
 It's not considered part of the public ufoLib API.
 """
+from __future__ import absolute_import, unicode_literals
+import sys
 import warnings
 import functools
+from datetime import datetime
+from fontTools.misc.py23 import tounicode
 
 
-numberTypes = (int, float)
+if hasattr(datetime, "timestamp"):  # python >= 3.3
+
+    def datetimeAsTimestamp(dt):
+        return dt.timestamp()
+
+else:
+    from datetime import tzinfo, timedelta
+
+    ZERO = timedelta(0)
+
+    class UTC(tzinfo):
+
+        def utcoffset(self, dt):
+            return ZERO
+
+        def tzname(self, dt):
+            return "UTC"
+
+        def dst(self, dt):
+            return ZERO
+
+    utc = UTC()
+
+    EPOCH = datetime.fromtimestamp(0, tz=utc)
+
+    def datetimeAsTimestamp(dt):
+        return (dt - EPOCH).total_seconds()
+
+
+# TODO: should import from fontTools.misc.py23
+try:
+	long = long
+except NameError:
+	long = int
+
+integerTypes = (int, long)
+numberTypes = (int, float, long)
 
 
 def deprecated(msg=""):
@@ -25,7 +65,7 @@
         @functools.wraps(func)
         def wrapper(*args, **kwargs):
             warnings.warn(
-                f"{func.__name__} function is a deprecated. {msg}",
+                "{} function is a deprecated. {}".format(func.__name__, msg),
                 category=DeprecationWarning,
                 stacklevel=2,
             )
@@ -36,37 +76,8 @@
     return deprecated_decorator
 
 
-# To be mixed with enum.Enum in UFOFormatVersion and GLIFFormatVersion
-class _VersionTupleEnumMixin:
-    @property
-    def major(self):
-        return self.value[0]
-
-    @property
-    def minor(self):
-        return self.value[1]
-
-    @classmethod
-    def _missing_(cls, value):
-        # allow to initialize a version enum from a single (major) integer
-        if isinstance(value, int):
-            return cls((value, 0))
-        # or from None to obtain the current default version
-        if value is None:
-            return cls.default()
-        return super()._missing_(value)
-
-    def __str__(self):
-        return f"{self.major}.{self.minor}"
-
-    @classmethod
-    def default(cls):
-        # get the latest defined version (i.e. the max of all versions)
-        return max(cls.__members__.values())
-
-    @classmethod
-    def supported_versions(cls):
-        return frozenset(cls.__members__.values())
+def fsdecode(path, encoding=sys.getfilesystemencoding()):
+    return tounicode(path, encoding=encoding)
 
 
 if __name__ == "__main__":
diff --git a/Lib/fontTools/ufoLib/validators.py b/Lib/fontTools/ufoLib/validators.py
index 49cb0e4..844b7f1 100644
--- a/Lib/fontTools/ufoLib/validators.py
+++ b/Lib/fontTools/ufoLib/validators.py
@@ -1,12 +1,18 @@
 """Various low level data validators."""
 
+from __future__ import absolute_import, unicode_literals
 import calendar
 from io import open
 import fs.base
 import fs.osfs
 
-from collections.abc import Mapping
-from fontTools.ufoLib.utils import numberTypes
+try:
+    from collections.abc import Mapping  # python >= 3.3
+except ImportError:
+    from collections import Mapping
+
+from fontTools.misc.py23 import basestring
+from fontTools.ufoLib.utils import integerTypes, numberTypes
 
 
 # -------
@@ -42,7 +48,7 @@
 	if valuesSet - validValuesSet:
 		return False
 	for value in values:
-		if not isinstance(value, int):
+		if not isinstance(value, integerTypes):
 			return False
 	return True
 
@@ -50,7 +56,7 @@
 	"""
 	Generic. (Added at version 3.)
 	"""
-	if not isinstance(value, int):
+	if not isinstance(value, integerTypes):
 		return False
 	if value < 0:
 		return False
@@ -137,7 +143,7 @@
 	Version 2+.
 	"""
 	# format: 0000/00/00 00:00:00
-	if not isinstance(value, str):
+	if not isinstance(value, basestring):
 		return False
 	# basic formatting
 	if not len(value) == 19:
@@ -197,7 +203,7 @@
 	"""
 	if not isinstance(value, list):
 		return False
-	dictPrototype = dict(nameID=(int, True), platformID=(int, True), encodingID=(int, True), languageID=(int, True), string=(str, True))
+	dictPrototype = dict(nameID=(int, True), platformID=(int, True), encodingID=(int, True), languageID=(int, True), string=(basestring, True))
 	for nameRecord in value:
 		if not genericDictValidator(nameRecord, dictPrototype):
 			return False
@@ -207,7 +213,7 @@
 	"""
 	Version 2+.
 	"""
-	if not isinstance(value, int):
+	if not isinstance(value, integerTypes):
 		return False
 	if value < 0:
 		return False
@@ -217,7 +223,7 @@
 	"""
 	Version 2+.
 	"""
-	if not isinstance(value, int):
+	if not isinstance(value, integerTypes):
 		return False
 	if value < 1:
 		return False
@@ -234,7 +240,7 @@
 	if len(values) != 10:
 		return False
 	for value in values:
-		if not isinstance(value, int):
+		if not isinstance(value, integerTypes):
 			return False
 	# XXX further validation?
 	return True
@@ -248,7 +254,7 @@
 	if len(values) != 10:
 		return False
 	for value in values:
-		if not isinstance(value, int):
+		if not isinstance(value, integerTypes):
 			return False
 		if value < 0:
 			return False
@@ -264,7 +270,7 @@
 	if len(values) != 2:
 		return False
 	for value in values:
-		if not isinstance(value, int):
+		if not isinstance(value, integerTypes):
 			return False
 	classID, subclassID = values
 	if classID < 0 or classID > 14:
@@ -329,7 +335,7 @@
 	"""
 	Version 3+.
 	"""
-	dictPrototype = dict(id=(str, True))
+	dictPrototype = dict(id=(basestring, True))
 	if not genericDictValidator(value, dictPrototype):
 		return False
 	return True
@@ -338,7 +344,7 @@
 	"""
 	Version 3+.
 	"""
-	dictPrototype = {"name" : (str, True), "url" : (str, False), "dir" : (str, False), "class" : (str, False)}
+	dictPrototype = {"name" : (basestring, True), "url" : (basestring, False), "dir" : (basestring, False), "class" : (basestring, False)}
 	if not genericDictValidator(value, dictPrototype):
 		return False
 	if "dir" in value and value.get("dir") not in ("ltr", "rtl"):
@@ -354,7 +360,7 @@
 		return False
 	if not len(value["credits"]):
 		return False
-	dictPrototype = {"name" : (str, True), "url" : (str, False), "role" : (str, False), "dir" : (str, False), "class" : (str, False)}
+	dictPrototype = {"name" : (basestring, True), "url" : (basestring, False), "role" : (basestring, False), "dir" : (basestring, False), "class" : (basestring, False)}
 	for credit in value["credits"]:
 		if not genericDictValidator(credit, dictPrototype):
 			return False
@@ -366,7 +372,7 @@
 	"""
 	Version 3+.
 	"""
-	dictPrototype = dict(url=(str, False), text=(list, True))
+	dictPrototype = dict(url=(basestring, False), text=(list, True))
 	if not genericDictValidator(value, dictPrototype):
 		return False
 	for text in value["text"]:
@@ -378,7 +384,7 @@
 	"""
 	Version 3+.
 	"""
-	dictPrototype = dict(url=(str, False), text=(list, False), id=(str, False))
+	dictPrototype = dict(url=(basestring, False), text=(list, False), id=(basestring, False))
 	if not genericDictValidator(value, dictPrototype):
 		return False
 	if "text" in value:
@@ -415,7 +421,7 @@
 	"""
 	Version 3+.
 	"""
-	dictPrototype = {"name" : (str, True), "dir" : (str, False), "class" : (str, False)}
+	dictPrototype = {"name" : (basestring, True), "dir" : (basestring, False), "class" : (basestring, False)}
 	if not genericDictValidator(value, dictPrototype):
 		return False
 	if "dir" in value and value.get("dir") not in ("ltr", "rtl"):
@@ -426,7 +432,7 @@
 	"""
 	Version 3+.
 	"""
-	dictPrototype = {"text" : (str, True), "language" : (str, False), "dir" : (str, False), "class" : (str, False)}
+	dictPrototype = {"text" : (basestring, True), "language" : (basestring, False), "dir" : (basestring, False), "class" : (basestring, False)}
 	if not genericDictValidator(value, dictPrototype):
 		return False
 	if "dir" in value and value.get("dir") not in ("ltr", "rtl"):
@@ -450,7 +456,7 @@
 	"""
 	Version 3+.
 	"""
-	dictPrototype = dict(names=(list, False), items=(list, True), id=(str, False))
+	dictPrototype = dict(names=(list, False), items=(list, True), id=(basestring, False))
 	if not genericDictValidator(value, dictPrototype):
 		return False
 	if "names" in value:
@@ -466,7 +472,7 @@
 	"""
 	Version 3+.
 	"""
-	dictPrototype = dict(id=(str, False), names=(list, True), values=(list, True))
+	dictPrototype = dict(id=(basestring, False), names=(list, True), values=(list, True))
 	if not genericDictValidator(value, dictPrototype):
 		return False
 	for name in value["names"]:
@@ -481,7 +487,7 @@
 	"""
 	Version 3+.
 	"""
-	dictPrototype = {"text" : (str, True), "language" : (str, False), "dir" : (str, False), "class" : (str, False)}
+	dictPrototype = {"text" : (basestring, True), "language" : (basestring, False), "dir" : (basestring, False), "class" : (basestring, False)}
 	if not genericDictValidator(value, dictPrototype):
 		return False
 	if "dir" in value and value.get("dir") not in ("ltr", "rtl"):
@@ -492,7 +498,7 @@
 	"""
 	Version 3+.
 	"""
-	dictPrototype = {"text" : (str, True), "language" : (str, False), "dir" : (str, False), "class" : (str, False)}
+	dictPrototype = {"text" : (basestring, True), "language" : (basestring, False), "dir" : (basestring, False), "class" : (basestring, False)}
 	if not genericDictValidator(value, dictPrototype):
 		return False
 	if "dir" in value and value.get("dir") not in ("ltr", "rtl"):
@@ -523,7 +529,7 @@
 
 _guidelineDictPrototype = dict(
 	x=((int, float), False), y=((int, float), False), angle=((int, float), False),
-	name=(str, False), color=(str, False), identifier=(str, False)
+	name=(basestring, False), color=(basestring, False), identifier=(basestring, False)
 )
 
 def guidelineValidator(value):
@@ -585,8 +591,8 @@
 
 _anchorDictPrototype = dict(
 	x=((int, float), False), y=((int, float), False),
-	name=(str, False), color=(str, False),
-	identifier=(str, False)
+	name=(basestring, False), color=(basestring, False),
+	identifier=(basestring, False)
 )
 
 def anchorValidator(value):
@@ -627,7 +633,7 @@
 	"""
 	validCharactersMin = 0x20
 	validCharactersMax = 0x7E
-	if not isinstance(value, str):
+	if not isinstance(value, basestring):
 		return False
 	if not value:
 		return False
@@ -686,7 +692,7 @@
 	>>> colorValidator("1, 1, 1, 1")
 	True
 	"""
-	if not isinstance(value, str):
+	if not isinstance(value, basestring):
 		return False
 	parts = value.split(",")
 	if len(parts) != 4:
@@ -720,11 +726,11 @@
 pngSignature = b"\x89PNG\r\n\x1a\n"
 
 _imageDictPrototype = dict(
-	fileName=(str, True),
+	fileName=(basestring, True),
 	xScale=((int, float), False), xyScale=((int, float), False),
 	yxScale=((int, float), False), yScale=((int, float), False),
 	xOffset=((int, float), False), yOffset=((int, float), False),
-	color=(str, False)
+	color=(basestring, False)
 )
 
 def imageValidator(value):
@@ -791,7 +797,7 @@
 		if not len(entry) == 2:
 			return False, bogusFileMessage
 		for i in entry:
-			if not isinstance(i, str):
+			if not isinstance(i, basestring):
 				return False, bogusFileMessage
 		layerName, directoryName = entry
 		# check directory naming
@@ -875,7 +881,7 @@
 	firstSideMapping = {}
 	secondSideMapping = {}
 	for groupName, glyphList in value.items():
-		if not isinstance(groupName, (str)):
+		if not isinstance(groupName, (basestring)):
 			return False, bogusFormatMessage
 		if not isinstance(glyphList, (list, tuple)):
 			return False, bogusFormatMessage
@@ -883,7 +889,7 @@
 			return False, "A group has an empty name."
 		if groupName.startswith("public."):
 			if not groupName.startswith("public.kern1.") and not groupName.startswith("public.kern2."):
-				# unknown public.* name. silently skip.
+				# unknown pubic.* name. silently skip.
 				continue
 			else:
 				if len("public.kernN.") == len(groupName):
@@ -893,7 +899,7 @@
 			else:
 				d = secondSideMapping
 			for glyphName in glyphList:
-				if not isinstance(glyphName, str):
+				if not isinstance(glyphName, basestring):
 					return False, "The group data %s contains an invalid member." % groupName
 				if glyphName in d:
 					return False, "The glyph \"%s\" occurs in too many kerning groups." % glyphName
@@ -931,12 +937,12 @@
 	if not isinstance(data, Mapping):
 		return False, bogusFormatMessage
 	for first, secondDict in data.items():
-		if not isinstance(first, str):
+		if not isinstance(first, basestring):
 			return False, bogusFormatMessage
 		elif not isinstance(secondDict, Mapping):
 			return False, bogusFormatMessage
 		for second, value in secondDict.items():
-			if not isinstance(second, str):
+			if not isinstance(second, basestring):
 				return False, bogusFormatMessage
 			elif not isinstance(value, numberTypes):
 				return False, bogusFormatMessage
@@ -977,7 +983,7 @@
 	>>> valid
 	False
 	>>> print(msg)
-	The lib key is not properly formatted: expected str, found int: 1
+	The lib key is not properly formatted: expected basestring, found int: 1
 
 	>>> lib = {"public.glyphOrder" : "hello"}
 	>>> valid, msg = fontLibValidator(lib)
@@ -991,15 +997,15 @@
 	>>> valid
 	False
 	>>> print(msg)  # doctest: +ELLIPSIS
-	public.glyphOrder is not properly formatted: expected str,...
+	public.glyphOrder is not properly formatted: expected basestring,...
 	"""
 	if not isDictEnough(value):
 		reason = "expected a dictionary, found %s" % type(value).__name__
 		return False, _bogusLibFormatMessage % reason
 	for key, value in value.items():
-		if not isinstance(key, str):
+		if not isinstance(key, basestring):
 			return False, (
-				"The lib key is not properly formatted: expected str, found %s: %r" %
+				"The lib key is not properly formatted: expected basestring, found %s: %r" %
 				(type(key).__name__, key))
 		# public.glyphOrder
 		if key == "public.glyphOrder":
@@ -1008,8 +1014,8 @@
 				reason = "expected list or tuple, found %s" % type(value).__name__
 				return False, bogusGlyphOrderMessage % reason
 			for glyphName in value:
-				if not isinstance(glyphName, str):
-					reason = "expected str, found %s" % type(glyphName).__name__
+				if not isinstance(glyphName, basestring):
+					reason = "expected basestring, found %s" % type(glyphName).__name__
 					return False, bogusGlyphOrderMessage % reason
 	return True, None
 
@@ -1045,7 +1051,7 @@
 		reason = "expected a dictionary, found %s" % type(value).__name__
 		return False, _bogusLibFormatMessage % reason
 	for key, value in value.items():
-		if not isinstance(key, str):
+		if not isinstance(key, basestring):
 			reason = "key (%s) should be a string" % key
 			return False, _bogusLibFormatMessage % reason
 		# public.markColor
diff --git a/Lib/fontTools/unicode.py b/Lib/fontTools/unicode.py
index e0867aa..ef3ed69 100644
--- a/Lib/fontTools/unicode.py
+++ b/Lib/fontTools/unicode.py
@@ -1,4 +1,8 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+
 def _makeunicodes(f):
+	import re
 	lines = iter(f.readlines())
 	unicodes = {}
 	for line in lines:
@@ -13,7 +17,7 @@
 class _UnicodeCustom(object):
 
 	def __init__(self, f):
-		if isinstance(f, str):
+		if isinstance(f, basestring):
 			with open(f) as fd:
 				codes = _makeunicodes(fd)
 		else:
@@ -36,7 +40,7 @@
 		except ImportError: 
 			import unicodedata
 		try:
-			return unicodedata.name(chr(charCode))
+			return unicodedata.name(unichr(charCode))
 		except ValueError:
 			return "????"
 
diff --git a/Lib/fontTools/unicodedata/Blocks.py b/Lib/fontTools/unicodedata/Blocks.py
index 0755074..132b095 100644
--- a/Lib/fontTools/unicodedata/Blocks.py
+++ b/Lib/fontTools/unicodedata/Blocks.py
@@ -4,8 +4,8 @@
 # Source: https://unicode.org/Public/UNIDATA/Blocks.txt
 # License: http://unicode.org/copyright.html#License
 #
-# Blocks-13.0.0.txt
-# Date: 2019-07-10, 19:06:00 GMT [KW]
+# Blocks-12.1.0.txt
+# Date: 2019-03-08, 23:59:00 GMT [KW]
 # © 2019 Unicode®, Inc.
 # For terms of use, see http://www.unicode.org/terms_of_use.html
 #
@@ -234,12 +234,10 @@
     0x10D00,  # .. 0x10D3F ; Hanifi Rohingya
     0x10D40,  # .. 0x10E5F ; No_Block
     0x10E60,  # .. 0x10E7F ; Rumi Numeral Symbols
-    0x10E80,  # .. 0x10EBF ; Yezidi
-    0x10EC0,  # .. 0x10EFF ; No_Block
+    0x10E80,  # .. 0x10EFF ; No_Block
     0x10F00,  # .. 0x10F2F ; Old Sogdian
     0x10F30,  # .. 0x10F6F ; Sogdian
-    0x10F70,  # .. 0x10FAF ; No_Block
-    0x10FB0,  # .. 0x10FDF ; Chorasmian
+    0x10F70,  # .. 0x10FDF ; No_Block
     0x10FE0,  # .. 0x10FFF ; Elymaic
     0x11000,  # .. 0x1107F ; Brahmi
     0x11080,  # .. 0x110CF ; Kaithi
@@ -267,8 +265,7 @@
     0x11800,  # .. 0x1184F ; Dogra
     0x11850,  # .. 0x1189F ; No_Block
     0x118A0,  # .. 0x118FF ; Warang Citi
-    0x11900,  # .. 0x1195F ; Dives Akuru
-    0x11960,  # .. 0x1199F ; No_Block
+    0x11900,  # .. 0x1199F ; No_Block
     0x119A0,  # .. 0x119FF ; Nandinagari
     0x11A00,  # .. 0x11A4F ; Zanabazar Square
     0x11A50,  # .. 0x11AAF ; Soyombo
@@ -282,8 +279,7 @@
     0x11D60,  # .. 0x11DAF ; Gunjala Gondi
     0x11DB0,  # .. 0x11EDF ; No_Block
     0x11EE0,  # .. 0x11EFF ; Makasar
-    0x11F00,  # .. 0x11FAF ; No_Block
-    0x11FB0,  # .. 0x11FBF ; Lisu Supplement
+    0x11F00,  # .. 0x11FBF ; No_Block
     0x11FC0,  # .. 0x11FFF ; Tamil Supplement
     0x12000,  # .. 0x123FF ; Cuneiform
     0x12400,  # .. 0x1247F ; Cuneiform Numbers and Punctuation
@@ -307,9 +303,7 @@
     0x16FE0,  # .. 0x16FFF ; Ideographic Symbols and Punctuation
     0x17000,  # .. 0x187FF ; Tangut
     0x18800,  # .. 0x18AFF ; Tangut Components
-    0x18B00,  # .. 0x18CFF ; Khitan Small Script
-    0x18D00,  # .. 0x18D8F ; Tangut Supplement
-    0x18D90,  # .. 0x1AFFF ; No_Block
+    0x18B00,  # .. 0x1AFFF ; No_Block
     0x1B000,  # .. 0x1B0FF ; Kana Supplement
     0x1B100,  # .. 0x1B12F ; Kana Extended-A
     0x1B130,  # .. 0x1B16F ; Small Kana Extension
@@ -360,8 +354,7 @@
     0x1F900,  # .. 0x1F9FF ; Supplemental Symbols and Pictographs
     0x1FA00,  # .. 0x1FA6F ; Chess Symbols
     0x1FA70,  # .. 0x1FAFF ; Symbols and Pictographs Extended-A
-    0x1FB00,  # .. 0x1FBFF ; Symbols for Legacy Computing
-    0x1FC00,  # .. 0x1FFFF ; No_Block
+    0x1FB00,  # .. 0x1FFFF ; No_Block
     0x20000,  # .. 0x2A6DF ; CJK Unified Ideographs Extension B
     0x2A6E0,  # .. 0x2A6FF ; No_Block
     0x2A700,  # .. 0x2B73F ; CJK Unified Ideographs Extension C
@@ -370,9 +363,7 @@
     0x2CEB0,  # .. 0x2EBEF ; CJK Unified Ideographs Extension F
     0x2EBF0,  # .. 0x2F7FF ; No_Block
     0x2F800,  # .. 0x2FA1F ; CJK Compatibility Ideographs Supplement
-    0x2FA20,  # .. 0x2FFFF ; No_Block
-    0x30000,  # .. 0x3134F ; CJK Unified Ideographs Extension G
-    0x31350,  # .. 0xDFFFF ; No_Block
+    0x2FA20,  # .. 0xDFFFF ; No_Block
     0xE0000,  # .. 0xE007F ; Tags
     0xE0080,  # .. 0xE00FF ; No_Block
     0xE0100,  # .. 0xE01EF ; Variation Selectors Supplement
@@ -599,12 +590,10 @@
     'Hanifi Rohingya',                                 # 10D00..10D3F
     'No_Block',                                        # 10D40..10E5F
     'Rumi Numeral Symbols',                            # 10E60..10E7F
-    'Yezidi',                                          # 10E80..10EBF
-    'No_Block',                                        # 10EC0..10EFF
+    'No_Block',                                        # 10E80..10EFF
     'Old Sogdian',                                     # 10F00..10F2F
     'Sogdian',                                         # 10F30..10F6F
-    'No_Block',                                        # 10F70..10FAF
-    'Chorasmian',                                      # 10FB0..10FDF
+    'No_Block',                                        # 10F70..10FDF
     'Elymaic',                                         # 10FE0..10FFF
     'Brahmi',                                          # 11000..1107F
     'Kaithi',                                          # 11080..110CF
@@ -632,8 +621,7 @@
     'Dogra',                                           # 11800..1184F
     'No_Block',                                        # 11850..1189F
     'Warang Citi',                                     # 118A0..118FF
-    'Dives Akuru',                                     # 11900..1195F
-    'No_Block',                                        # 11960..1199F
+    'No_Block',                                        # 11900..1199F
     'Nandinagari',                                     # 119A0..119FF
     'Zanabazar Square',                                # 11A00..11A4F
     'Soyombo',                                         # 11A50..11AAF
@@ -647,8 +635,7 @@
     'Gunjala Gondi',                                   # 11D60..11DAF
     'No_Block',                                        # 11DB0..11EDF
     'Makasar',                                         # 11EE0..11EFF
-    'No_Block',                                        # 11F00..11FAF
-    'Lisu Supplement',                                 # 11FB0..11FBF
+    'No_Block',                                        # 11F00..11FBF
     'Tamil Supplement',                                # 11FC0..11FFF
     'Cuneiform',                                       # 12000..123FF
     'Cuneiform Numbers and Punctuation',               # 12400..1247F
@@ -672,9 +659,7 @@
     'Ideographic Symbols and Punctuation',             # 16FE0..16FFF
     'Tangut',                                          # 17000..187FF
     'Tangut Components',                               # 18800..18AFF
-    'Khitan Small Script',                             # 18B00..18CFF
-    'Tangut Supplement',                               # 18D00..18D8F
-    'No_Block',                                        # 18D90..1AFFF
+    'No_Block',                                        # 18B00..1AFFF
     'Kana Supplement',                                 # 1B000..1B0FF
     'Kana Extended-A',                                 # 1B100..1B12F
     'Small Kana Extension',                            # 1B130..1B16F
@@ -725,8 +710,7 @@
     'Supplemental Symbols and Pictographs',            # 1F900..1F9FF
     'Chess Symbols',                                   # 1FA00..1FA6F
     'Symbols and Pictographs Extended-A',              # 1FA70..1FAFF
-    'Symbols for Legacy Computing',                    # 1FB00..1FBFF
-    'No_Block',                                        # 1FC00..1FFFF
+    'No_Block',                                        # 1FB00..1FFFF
     'CJK Unified Ideographs Extension B',              # 20000..2A6DF
     'No_Block',                                        # 2A6E0..2A6FF
     'CJK Unified Ideographs Extension C',              # 2A700..2B73F
@@ -735,9 +719,7 @@
     'CJK Unified Ideographs Extension F',              # 2CEB0..2EBEF
     'No_Block',                                        # 2EBF0..2F7FF
     'CJK Compatibility Ideographs Supplement',         # 2F800..2FA1F
-    'No_Block',                                        # 2FA20..2FFFF
-    'CJK Unified Ideographs Extension G',              # 30000..3134F
-    'No_Block',                                        # 31350..DFFFF
+    'No_Block',                                        # 2FA20..DFFFF
     'Tags',                                            # E0000..E007F
     'No_Block',                                        # E0080..E00FF
     'Variation Selectors Supplement',                  # E0100..E01EF
diff --git a/Lib/fontTools/unicodedata/ScriptExtensions.py b/Lib/fontTools/unicodedata/ScriptExtensions.py
index b4e09cd..d7d2e3c 100644
--- a/Lib/fontTools/unicodedata/ScriptExtensions.py
+++ b/Lib/fontTools/unicodedata/ScriptExtensions.py
@@ -4,9 +4,9 @@
 # Source: https://unicode.org/Public/UNIDATA/ScriptExtensions.txt
 # License: http://unicode.org/copyright.html#License
 #
-# ScriptExtensions-13.0.0.txt
-# Date: 2020-01-22, 00:07:43 GMT
-# © 2020 Unicode®, Inc.
+# ScriptExtensions-12.1.0.txt
+# Date: 2019-04-01, 09:10:42 GMT
+# © 2019 Unicode®, Inc.
 # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
 # For terms of use, see http://www.unicode.org/terms_of_use.html
 #
@@ -52,19 +52,21 @@
     0x0484,  # .. 0x0484 ; {'Cyrl', 'Glag'}
     0x0485,  # .. 0x0486 ; {'Cyrl', 'Latn'}
     0x0487,  # .. 0x0487 ; {'Cyrl', 'Glag'}
-    0x0488,  # .. 0x060B ; None
-    0x060C,  # .. 0x060C ; {'Arab', 'Rohg', 'Syrc', 'Thaa', 'Yezi'}
+    0x0488,  # .. 0x0588 ; None
+    0x0589,  # .. 0x0589 ; {'Armn', 'Geor'}
+    0x058A,  # .. 0x060B ; None
+    0x060C,  # .. 0x060C ; {'Arab', 'Rohg', 'Syrc', 'Thaa'}
     0x060D,  # .. 0x061A ; None
-    0x061B,  # .. 0x061B ; {'Arab', 'Rohg', 'Syrc', 'Thaa', 'Yezi'}
+    0x061B,  # .. 0x061B ; {'Arab', 'Rohg', 'Syrc', 'Thaa'}
     0x061C,  # .. 0x061C ; {'Arab', 'Syrc', 'Thaa'}
     0x061D,  # .. 0x061E ; None
-    0x061F,  # .. 0x061F ; {'Arab', 'Rohg', 'Syrc', 'Thaa', 'Yezi'}
+    0x061F,  # .. 0x061F ; {'Arab', 'Rohg', 'Syrc', 'Thaa'}
     0x0620,  # .. 0x063F ; None
     0x0640,  # .. 0x0640 ; {'Adlm', 'Arab', 'Mand', 'Mani', 'Phlp', 'Rohg', 'Sogd', 'Syrc'}
     0x0641,  # .. 0x064A ; None
     0x064B,  # .. 0x0655 ; {'Arab', 'Syrc'}
     0x0656,  # .. 0x065F ; None
-    0x0660,  # .. 0x0669 ; {'Arab', 'Thaa', 'Yezi'}
+    0x0660,  # .. 0x0669 ; {'Arab', 'Thaa'}
     0x066A,  # .. 0x066F ; None
     0x0670,  # .. 0x0670 ; {'Arab', 'Syrc'}
     0x0671,  # .. 0x06D3 ; None
@@ -127,9 +129,7 @@
     0x1CFA,  # .. 0x1CFA ; {'Nand'}
     0x1CFB,  # .. 0x1DBF ; None
     0x1DC0,  # .. 0x1DC1 ; {'Grek'}
-    0x1DC2,  # .. 0x1DF7 ; None
-    0x1DF8,  # .. 0x1DF8 ; {'Cyrl', 'Syrc'}
-    0x1DF9,  # .. 0x202E ; None
+    0x1DC2,  # .. 0x202E ; None
     0x202F,  # .. 0x202F ; {'Latn', 'Mong'}
     0x2030,  # .. 0x20EF ; None
     0x20F0,  # .. 0x20F0 ; {'Deva', 'Gran', 'Latn'}
@@ -183,9 +183,7 @@
     0x33E0,  # .. 0x33FE ; {'Hani'}
     0x33FF,  # .. 0xA66E ; None
     0xA66F,  # .. 0xA66F ; {'Cyrl', 'Glag'}
-    0xA670,  # .. 0xA6FF ; None
-    0xA700,  # .. 0xA707 ; {'Hani', 'Latn'}
-    0xA708,  # .. 0xA82F ; None
+    0xA670,  # .. 0xA82F ; None
     0xA830,  # .. 0xA832 ; {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Knda', 'Kthi', 'Mahj', 'Mlym', 'Modi', 'Nand', 'Sind', 'Takr', 'Tirh'}
     0xA833,  # .. 0xA835 ; {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Knda', 'Kthi', 'Mahj', 'Modi', 'Nand', 'Sind', 'Takr', 'Tirh'}
     0xA836,  # .. 0xA839 ; {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Kthi', 'Mahj', 'Modi', 'Sind', 'Takr', 'Tirh'}
@@ -248,19 +246,21 @@
     {'Cyrl', 'Glag'},                                          # 0484..0484
     {'Cyrl', 'Latn'},                                          # 0485..0486
     {'Cyrl', 'Glag'},                                          # 0487..0487
-    None,                                                      # 0488..060B
-    {'Arab', 'Rohg', 'Syrc', 'Thaa', 'Yezi'},                  # 060C..060C
+    None,                                                      # 0488..0588
+    {'Armn', 'Geor'},                                          # 0589..0589
+    None,                                                      # 058A..060B
+    {'Arab', 'Rohg', 'Syrc', 'Thaa'},                          # 060C..060C
     None,                                                      # 060D..061A
-    {'Arab', 'Rohg', 'Syrc', 'Thaa', 'Yezi'},                  # 061B..061B
+    {'Arab', 'Rohg', 'Syrc', 'Thaa'},                          # 061B..061B
     {'Arab', 'Syrc', 'Thaa'},                                  # 061C..061C
     None,                                                      # 061D..061E
-    {'Arab', 'Rohg', 'Syrc', 'Thaa', 'Yezi'},                  # 061F..061F
+    {'Arab', 'Rohg', 'Syrc', 'Thaa'},                          # 061F..061F
     None,                                                      # 0620..063F
     {'Adlm', 'Arab', 'Mand', 'Mani', 'Phlp', 'Rohg', 'Sogd', 'Syrc'},  # 0640..0640
     None,                                                      # 0641..064A
     {'Arab', 'Syrc'},                                          # 064B..0655
     None,                                                      # 0656..065F
-    {'Arab', 'Thaa', 'Yezi'},                                  # 0660..0669
+    {'Arab', 'Thaa'},                                          # 0660..0669
     None,                                                      # 066A..066F
     {'Arab', 'Syrc'},                                          # 0670..0670
     None,                                                      # 0671..06D3
@@ -323,9 +323,7 @@
     {'Nand'},                                                  # 1CFA..1CFA
     None,                                                      # 1CFB..1DBF
     {'Grek'},                                                  # 1DC0..1DC1
-    None,                                                      # 1DC2..1DF7
-    {'Cyrl', 'Syrc'},                                          # 1DF8..1DF8
-    None,                                                      # 1DF9..202E
+    None,                                                      # 1DC2..202E
     {'Latn', 'Mong'},                                          # 202F..202F
     None,                                                      # 2030..20EF
     {'Deva', 'Gran', 'Latn'},                                  # 20F0..20F0
@@ -379,9 +377,7 @@
     {'Hani'},                                                  # 33E0..33FE
     None,                                                      # 33FF..A66E
     {'Cyrl', 'Glag'},                                          # A66F..A66F
-    None,                                                      # A670..A6FF
-    {'Hani', 'Latn'},                                          # A700..A707
-    None,                                                      # A708..A82F
+    None,                                                      # A670..A82F
     {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Knda', 'Kthi', 'Mahj', 'Mlym', 'Modi', 'Nand', 'Sind', 'Takr', 'Tirh'},  # A830..A832
     {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Knda', 'Kthi', 'Mahj', 'Modi', 'Nand', 'Sind', 'Takr', 'Tirh'},  # A833..A835
     {'Deva', 'Dogr', 'Gujr', 'Guru', 'Khoj', 'Kthi', 'Mahj', 'Modi', 'Sind', 'Takr', 'Tirh'},  # A836..A839
diff --git a/Lib/fontTools/unicodedata/Scripts.py b/Lib/fontTools/unicodedata/Scripts.py
index 12f9a0e..dc8c1e2 100644
--- a/Lib/fontTools/unicodedata/Scripts.py
+++ b/Lib/fontTools/unicodedata/Scripts.py
@@ -4,9 +4,9 @@
 # Source: https://unicode.org/Public/UNIDATA/Scripts.txt
 # License: http://unicode.org/copyright.html#License
 #
-# Scripts-13.0.0.txt
-# Date: 2020-01-22, 00:07:43 GMT
-# © 2020 Unicode®, Inc.
+# Scripts-12.1.0.txt
+# Date: 2019-04-01, 09:10:42 GMT
+# © 2019 Unicode®, Inc.
 # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
 # For terms of use, see http://www.unicode.org/terms_of_use.html
 #
@@ -68,7 +68,9 @@
     0x0530,  # .. 0x0530 ; Unknown
     0x0531,  # .. 0x0556 ; Armenian
     0x0557,  # .. 0x0558 ; Unknown
-    0x0559,  # .. 0x058A ; Armenian
+    0x0559,  # .. 0x0588 ; Armenian
+    0x0589,  # .. 0x0589 ; Common
+    0x058A,  # .. 0x058A ; Armenian
     0x058B,  # .. 0x058C ; Unknown
     0x058D,  # .. 0x058F ; Armenian
     0x0590,  # .. 0x0590 ; Unknown
@@ -120,8 +122,8 @@
     0x086B,  # .. 0x089F ; Unknown
     0x08A0,  # .. 0x08B4 ; Arabic
     0x08B5,  # .. 0x08B5 ; Unknown
-    0x08B6,  # .. 0x08C7 ; Arabic
-    0x08C8,  # .. 0x08D2 ; Unknown
+    0x08B6,  # .. 0x08BD ; Arabic
+    0x08BE,  # .. 0x08D2 ; Unknown
     0x08D3,  # .. 0x08E1 ; Arabic
     0x08E2,  # .. 0x08E2 ; Common
     0x08E3,  # .. 0x08FF ; Arabic
@@ -237,8 +239,8 @@
     0x0B47,  # .. 0x0B48 ; Oriya
     0x0B49,  # .. 0x0B4A ; Unknown
     0x0B4B,  # .. 0x0B4D ; Oriya
-    0x0B4E,  # .. 0x0B54 ; Unknown
-    0x0B55,  # .. 0x0B57 ; Oriya
+    0x0B4E,  # .. 0x0B55 ; Unknown
+    0x0B56,  # .. 0x0B57 ; Oriya
     0x0B58,  # .. 0x0B5B ; Unknown
     0x0B5C,  # .. 0x0B5D ; Oriya
     0x0B5E,  # .. 0x0B5E ; Unknown
@@ -327,7 +329,9 @@
     0x0CF0,  # .. 0x0CF0 ; Unknown
     0x0CF1,  # .. 0x0CF2 ; Kannada
     0x0CF3,  # .. 0x0CFF ; Unknown
-    0x0D00,  # .. 0x0D0C ; Malayalam
+    0x0D00,  # .. 0x0D03 ; Malayalam
+    0x0D04,  # .. 0x0D04 ; Unknown
+    0x0D05,  # .. 0x0D0C ; Malayalam
     0x0D0D,  # .. 0x0D0D ; Unknown
     0x0D0E,  # .. 0x0D10 ; Malayalam
     0x0D11,  # .. 0x0D11 ; Unknown
@@ -340,8 +344,8 @@
     0x0D54,  # .. 0x0D63 ; Malayalam
     0x0D64,  # .. 0x0D65 ; Unknown
     0x0D66,  # .. 0x0D7F ; Malayalam
-    0x0D80,  # .. 0x0D80 ; Unknown
-    0x0D81,  # .. 0x0D83 ; Sinhala
+    0x0D80,  # .. 0x0D81 ; Unknown
+    0x0D82,  # .. 0x0D83 ; Sinhala
     0x0D84,  # .. 0x0D84 ; Unknown
     0x0D85,  # .. 0x0D96 ; Sinhala
     0x0D97,  # .. 0x0D99 ; Unknown
@@ -533,8 +537,8 @@
     0x1A9A,  # .. 0x1A9F ; Unknown
     0x1AA0,  # .. 0x1AAD ; Tai_Tham
     0x1AAE,  # .. 0x1AAF ; Unknown
-    0x1AB0,  # .. 0x1AC0 ; Inherited
-    0x1AC1,  # .. 0x1AFF ; Unknown
+    0x1AB0,  # .. 0x1ABE ; Inherited
+    0x1ABF,  # .. 0x1AFF ; Unknown
     0x1B00,  # .. 0x1B4B ; Balinese
     0x1B4C,  # .. 0x1B4F ; Unknown
     0x1B50,  # .. 0x1B7C ; Balinese
@@ -654,8 +658,8 @@
     0x2900,  # .. 0x2B73 ; Common
     0x2B74,  # .. 0x2B75 ; Unknown
     0x2B76,  # .. 0x2B95 ; Common
-    0x2B96,  # .. 0x2B96 ; Unknown
-    0x2B97,  # .. 0x2BFF ; Common
+    0x2B96,  # .. 0x2B97 ; Unknown
+    0x2B98,  # .. 0x2BFF ; Common
     0x2C00,  # .. 0x2C2E ; Glagolitic
     0x2C2F,  # .. 0x2C2F ; Unknown
     0x2C30,  # .. 0x2C5E ; Glagolitic
@@ -694,8 +698,8 @@
     0x2DD8,  # .. 0x2DDE ; Ethiopic
     0x2DDF,  # .. 0x2DDF ; Unknown
     0x2DE0,  # .. 0x2DFF ; Cyrillic
-    0x2E00,  # .. 0x2E52 ; Common
-    0x2E53,  # .. 0x2E7F ; Unknown
+    0x2E00,  # .. 0x2E4F ; Common
+    0x2E50,  # .. 0x2E7F ; Unknown
     0x2E80,  # .. 0x2E99 ; Han
     0x2E9A,  # .. 0x2E9A ; Unknown
     0x2E9B,  # .. 0x2EF3 ; Han
@@ -731,7 +735,8 @@
     0x3131,  # .. 0x318E ; Hangul
     0x318F,  # .. 0x318F ; Unknown
     0x3190,  # .. 0x319F ; Common
-    0x31A0,  # .. 0x31BF ; Bopomofo
+    0x31A0,  # .. 0x31BA ; Bopomofo
+    0x31BB,  # .. 0x31BF ; Unknown
     0x31C0,  # .. 0x31E3 ; Common
     0x31E4,  # .. 0x31EF ; Unknown
     0x31F0,  # .. 0x31FF ; Katakana
@@ -744,10 +749,11 @@
     0x32FF,  # .. 0x32FF ; Common
     0x3300,  # .. 0x3357 ; Katakana
     0x3358,  # .. 0x33FF ; Common
-    0x3400,  # .. 0x4DBF ; Han
+    0x3400,  # .. 0x4DB5 ; Han
+    0x4DB6,  # .. 0x4DBF ; Unknown
     0x4DC0,  # .. 0x4DFF ; Common
-    0x4E00,  # .. 0x9FFC ; Han
-    0x9FFD,  # .. 0x9FFF ; Unknown
+    0x4E00,  # .. 0x9FEF ; Han
+    0x9FF0,  # .. 0x9FFF ; Unknown
     0xA000,  # .. 0xA48C ; Yi
     0xA48D,  # .. 0xA48F ; Unknown
     0xA490,  # .. 0xA4C6 ; Yi
@@ -763,11 +769,11 @@
     0xA788,  # .. 0xA78A ; Common
     0xA78B,  # .. 0xA7BF ; Latin
     0xA7C0,  # .. 0xA7C1 ; Unknown
-    0xA7C2,  # .. 0xA7CA ; Latin
-    0xA7CB,  # .. 0xA7F4 ; Unknown
-    0xA7F5,  # .. 0xA7FF ; Latin
-    0xA800,  # .. 0xA82C ; Syloti_Nagri
-    0xA82D,  # .. 0xA82F ; Unknown
+    0xA7C2,  # .. 0xA7C6 ; Latin
+    0xA7C7,  # .. 0xA7F6 ; Unknown
+    0xA7F7,  # .. 0xA7FF ; Latin
+    0xA800,  # .. 0xA82B ; Syloti_Nagri
+    0xA82C,  # .. 0xA82F ; Unknown
     0xA830,  # .. 0xA839 ; Common
     0xA83A,  # .. 0xA83F ; Unknown
     0xA840,  # .. 0xA877 ; Phags_Pa
@@ -820,9 +826,8 @@
     0xAB5B,  # .. 0xAB5B ; Common
     0xAB5C,  # .. 0xAB64 ; Latin
     0xAB65,  # .. 0xAB65 ; Greek
-    0xAB66,  # .. 0xAB69 ; Latin
-    0xAB6A,  # .. 0xAB6B ; Common
-    0xAB6C,  # .. 0xAB6F ; Unknown
+    0xAB66,  # .. 0xAB67 ; Latin
+    0xAB68,  # .. 0xAB6F ; Unknown
     0xAB70,  # .. 0xABBF ; Cherokee
     0xABC0,  # .. 0xABED ; Meetei_Mayek
     0xABEE,  # .. 0xABEF ; Unknown
@@ -927,8 +932,8 @@
     0x10137,  # .. 0x1013F ; Common
     0x10140,  # .. 0x1018E ; Greek
     0x1018F,  # .. 0x1018F ; Unknown
-    0x10190,  # .. 0x1019C ; Common
-    0x1019D,  # .. 0x1019F ; Unknown
+    0x10190,  # .. 0x1019B ; Common
+    0x1019C,  # .. 0x1019F ; Unknown
     0x101A0,  # .. 0x101A0 ; Greek
     0x101A1,  # .. 0x101CF ; Unknown
     0x101D0,  # .. 0x101FC ; Common
@@ -1064,19 +1069,11 @@
     0x10D30,  # .. 0x10D39 ; Hanifi_Rohingya
     0x10D3A,  # .. 0x10E5F ; Unknown
     0x10E60,  # .. 0x10E7E ; Arabic
-    0x10E7F,  # .. 0x10E7F ; Unknown
-    0x10E80,  # .. 0x10EA9 ; Yezidi
-    0x10EAA,  # .. 0x10EAA ; Unknown
-    0x10EAB,  # .. 0x10EAD ; Yezidi
-    0x10EAE,  # .. 0x10EAF ; Unknown
-    0x10EB0,  # .. 0x10EB1 ; Yezidi
-    0x10EB2,  # .. 0x10EFF ; Unknown
+    0x10E7F,  # .. 0x10EFF ; Unknown
     0x10F00,  # .. 0x10F27 ; Old_Sogdian
     0x10F28,  # .. 0x10F2F ; Unknown
     0x10F30,  # .. 0x10F59 ; Sogdian
-    0x10F5A,  # .. 0x10FAF ; Unknown
-    0x10FB0,  # .. 0x10FCB ; Chorasmian
-    0x10FCC,  # .. 0x10FDF ; Unknown
+    0x10F5A,  # .. 0x10FDF ; Unknown
     0x10FE0,  # .. 0x10FF6 ; Elymaic
     0x10FF7,  # .. 0x10FFF ; Unknown
     0x11000,  # .. 0x1104D ; Brahmi
@@ -1094,11 +1091,13 @@
     0x110FA,  # .. 0x110FF ; Unknown
     0x11100,  # .. 0x11134 ; Chakma
     0x11135,  # .. 0x11135 ; Unknown
-    0x11136,  # .. 0x11147 ; Chakma
-    0x11148,  # .. 0x1114F ; Unknown
+    0x11136,  # .. 0x11146 ; Chakma
+    0x11147,  # .. 0x1114F ; Unknown
     0x11150,  # .. 0x11176 ; Mahajani
     0x11177,  # .. 0x1117F ; Unknown
-    0x11180,  # .. 0x111DF ; Sharada
+    0x11180,  # .. 0x111CD ; Sharada
+    0x111CE,  # .. 0x111CF ; Unknown
+    0x111D0,  # .. 0x111DF ; Sharada
     0x111E0,  # .. 0x111E0 ; Unknown
     0x111E1,  # .. 0x111F4 ; Sinhala
     0x111F5,  # .. 0x111FF ; Unknown
@@ -1151,10 +1150,12 @@
     0x1136D,  # .. 0x1136F ; Unknown
     0x11370,  # .. 0x11374 ; Grantha
     0x11375,  # .. 0x113FF ; Unknown
-    0x11400,  # .. 0x1145B ; Newa
+    0x11400,  # .. 0x11459 ; Newa
+    0x1145A,  # .. 0x1145A ; Unknown
+    0x1145B,  # .. 0x1145B ; Newa
     0x1145C,  # .. 0x1145C ; Unknown
-    0x1145D,  # .. 0x11461 ; Newa
-    0x11462,  # .. 0x1147F ; Unknown
+    0x1145D,  # .. 0x1145F ; Newa
+    0x11460,  # .. 0x1147F ; Unknown
     0x11480,  # .. 0x114C7 ; Tirhuta
     0x114C8,  # .. 0x114CF ; Unknown
     0x114D0,  # .. 0x114D9 ; Tirhuta
@@ -1184,22 +1185,7 @@
     0x118A0,  # .. 0x118F2 ; Warang_Citi
     0x118F3,  # .. 0x118FE ; Unknown
     0x118FF,  # .. 0x118FF ; Warang_Citi
-    0x11900,  # .. 0x11906 ; Dives_Akuru
-    0x11907,  # .. 0x11908 ; Unknown
-    0x11909,  # .. 0x11909 ; Dives_Akuru
-    0x1190A,  # .. 0x1190B ; Unknown
-    0x1190C,  # .. 0x11913 ; Dives_Akuru
-    0x11914,  # .. 0x11914 ; Unknown
-    0x11915,  # .. 0x11916 ; Dives_Akuru
-    0x11917,  # .. 0x11917 ; Unknown
-    0x11918,  # .. 0x11935 ; Dives_Akuru
-    0x11936,  # .. 0x11936 ; Unknown
-    0x11937,  # .. 0x11938 ; Dives_Akuru
-    0x11939,  # .. 0x1193A ; Unknown
-    0x1193B,  # .. 0x11946 ; Dives_Akuru
-    0x11947,  # .. 0x1194F ; Unknown
-    0x11950,  # .. 0x11959 ; Dives_Akuru
-    0x1195A,  # .. 0x1199F ; Unknown
+    0x11900,  # .. 0x1199F ; Unknown
     0x119A0,  # .. 0x119A7 ; Nandinagari
     0x119A8,  # .. 0x119A9 ; Unknown
     0x119AA,  # .. 0x119D7 ; Nandinagari
@@ -1253,9 +1239,7 @@
     0x11DA0,  # .. 0x11DA9 ; Gunjala_Gondi
     0x11DAA,  # .. 0x11EDF ; Unknown
     0x11EE0,  # .. 0x11EF8 ; Makasar
-    0x11EF9,  # .. 0x11FAF ; Unknown
-    0x11FB0,  # .. 0x11FB0 ; Lisu
-    0x11FB1,  # .. 0x11FBF ; Unknown
+    0x11EF9,  # .. 0x11FBF ; Unknown
     0x11FC0,  # .. 0x11FF1 ; Tamil
     0x11FF2,  # .. 0x11FFE ; Unknown
     0x11FFF,  # .. 0x11FFF ; Tamil
@@ -1306,17 +1290,11 @@
     0x16FE0,  # .. 0x16FE0 ; Tangut
     0x16FE1,  # .. 0x16FE1 ; Nushu
     0x16FE2,  # .. 0x16FE3 ; Common
-    0x16FE4,  # .. 0x16FE4 ; Khitan_Small_Script
-    0x16FE5,  # .. 0x16FEF ; Unknown
-    0x16FF0,  # .. 0x16FF1 ; Han
-    0x16FF2,  # .. 0x16FFF ; Unknown
+    0x16FE4,  # .. 0x16FFF ; Unknown
     0x17000,  # .. 0x187F7 ; Tangut
     0x187F8,  # .. 0x187FF ; Unknown
-    0x18800,  # .. 0x18AFF ; Tangut
-    0x18B00,  # .. 0x18CD5 ; Khitan_Small_Script
-    0x18CD6,  # .. 0x18CFF ; Unknown
-    0x18D00,  # .. 0x18D08 ; Tangut
-    0x18D09,  # .. 0x1AFFF ; Unknown
+    0x18800,  # .. 0x18AF2 ; Tangut
+    0x18AF3,  # .. 0x1AFFF ; Unknown
     0x1B000,  # .. 0x1B000 ; Katakana
     0x1B001,  # .. 0x1B11E ; Hiragana
     0x1B11F,  # .. 0x1B14F ; Unknown
@@ -1522,8 +1500,12 @@
     0x1F0D0,  # .. 0x1F0D0 ; Unknown
     0x1F0D1,  # .. 0x1F0F5 ; Common
     0x1F0F6,  # .. 0x1F0FF ; Unknown
-    0x1F100,  # .. 0x1F1AD ; Common
-    0x1F1AE,  # .. 0x1F1E5 ; Unknown
+    0x1F100,  # .. 0x1F10C ; Common
+    0x1F10D,  # .. 0x1F10F ; Unknown
+    0x1F110,  # .. 0x1F16C ; Common
+    0x1F16D,  # .. 0x1F16F ; Unknown
+    0x1F170,  # .. 0x1F1AC ; Common
+    0x1F1AD,  # .. 0x1F1E5 ; Unknown
     0x1F1E6,  # .. 0x1F1FF ; Common
     0x1F200,  # .. 0x1F200 ; Hiragana
     0x1F201,  # .. 0x1F202 ; Common
@@ -1536,12 +1518,12 @@
     0x1F252,  # .. 0x1F25F ; Unknown
     0x1F260,  # .. 0x1F265 ; Common
     0x1F266,  # .. 0x1F2FF ; Unknown
-    0x1F300,  # .. 0x1F6D7 ; Common
-    0x1F6D8,  # .. 0x1F6DF ; Unknown
+    0x1F300,  # .. 0x1F6D5 ; Common
+    0x1F6D6,  # .. 0x1F6DF ; Unknown
     0x1F6E0,  # .. 0x1F6EC ; Common
     0x1F6ED,  # .. 0x1F6EF ; Unknown
-    0x1F6F0,  # .. 0x1F6FC ; Common
-    0x1F6FD,  # .. 0x1F6FF ; Unknown
+    0x1F6F0,  # .. 0x1F6FA ; Common
+    0x1F6FB,  # .. 0x1F6FF ; Unknown
     0x1F700,  # .. 0x1F773 ; Common
     0x1F774,  # .. 0x1F77F ; Unknown
     0x1F780,  # .. 0x1F7D8 ; Common
@@ -1557,39 +1539,33 @@
     0x1F860,  # .. 0x1F887 ; Common
     0x1F888,  # .. 0x1F88F ; Unknown
     0x1F890,  # .. 0x1F8AD ; Common
-    0x1F8AE,  # .. 0x1F8AF ; Unknown
-    0x1F8B0,  # .. 0x1F8B1 ; Common
-    0x1F8B2,  # .. 0x1F8FF ; Unknown
-    0x1F900,  # .. 0x1F978 ; Common
-    0x1F979,  # .. 0x1F979 ; Unknown
-    0x1F97A,  # .. 0x1F9CB ; Common
-    0x1F9CC,  # .. 0x1F9CC ; Unknown
+    0x1F8AE,  # .. 0x1F8FF ; Unknown
+    0x1F900,  # .. 0x1F90B ; Common
+    0x1F90C,  # .. 0x1F90C ; Unknown
+    0x1F90D,  # .. 0x1F971 ; Common
+    0x1F972,  # .. 0x1F972 ; Unknown
+    0x1F973,  # .. 0x1F976 ; Common
+    0x1F977,  # .. 0x1F979 ; Unknown
+    0x1F97A,  # .. 0x1F9A2 ; Common
+    0x1F9A3,  # .. 0x1F9A4 ; Unknown
+    0x1F9A5,  # .. 0x1F9AA ; Common
+    0x1F9AB,  # .. 0x1F9AD ; Unknown
+    0x1F9AE,  # .. 0x1F9CA ; Common
+    0x1F9CB,  # .. 0x1F9CC ; Unknown
     0x1F9CD,  # .. 0x1FA53 ; Common
     0x1FA54,  # .. 0x1FA5F ; Unknown
     0x1FA60,  # .. 0x1FA6D ; Common
     0x1FA6E,  # .. 0x1FA6F ; Unknown
-    0x1FA70,  # .. 0x1FA74 ; Common
-    0x1FA75,  # .. 0x1FA77 ; Unknown
+    0x1FA70,  # .. 0x1FA73 ; Common
+    0x1FA74,  # .. 0x1FA77 ; Unknown
     0x1FA78,  # .. 0x1FA7A ; Common
     0x1FA7B,  # .. 0x1FA7F ; Unknown
-    0x1FA80,  # .. 0x1FA86 ; Common
-    0x1FA87,  # .. 0x1FA8F ; Unknown
-    0x1FA90,  # .. 0x1FAA8 ; Common
-    0x1FAA9,  # .. 0x1FAAF ; Unknown
-    0x1FAB0,  # .. 0x1FAB6 ; Common
-    0x1FAB7,  # .. 0x1FABF ; Unknown
-    0x1FAC0,  # .. 0x1FAC2 ; Common
-    0x1FAC3,  # .. 0x1FACF ; Unknown
-    0x1FAD0,  # .. 0x1FAD6 ; Common
-    0x1FAD7,  # .. 0x1FAFF ; Unknown
-    0x1FB00,  # .. 0x1FB92 ; Common
-    0x1FB93,  # .. 0x1FB93 ; Unknown
-    0x1FB94,  # .. 0x1FBCA ; Common
-    0x1FBCB,  # .. 0x1FBEF ; Unknown
-    0x1FBF0,  # .. 0x1FBF9 ; Common
-    0x1FBFA,  # .. 0x1FFFF ; Unknown
-    0x20000,  # .. 0x2A6DD ; Han
-    0x2A6DE,  # .. 0x2A6FF ; Unknown
+    0x1FA80,  # .. 0x1FA82 ; Common
+    0x1FA83,  # .. 0x1FA8F ; Unknown
+    0x1FA90,  # .. 0x1FA95 ; Common
+    0x1FA96,  # .. 0x1FFFF ; Unknown
+    0x20000,  # .. 0x2A6D6 ; Han
+    0x2A6D7,  # .. 0x2A6FF ; Unknown
     0x2A700,  # .. 0x2B734 ; Han
     0x2B735,  # .. 0x2B73F ; Unknown
     0x2B740,  # .. 0x2B81D ; Han
@@ -1599,9 +1575,7 @@
     0x2CEB0,  # .. 0x2EBE0 ; Han
     0x2EBE1,  # .. 0x2F7FF ; Unknown
     0x2F800,  # .. 0x2FA1D ; Han
-    0x2FA1E,  # .. 0x2FFFF ; Unknown
-    0x30000,  # .. 0x3134A ; Han
-    0x3134B,  # .. 0xE0000 ; Unknown
+    0x2FA1E,  # .. 0xE0000 ; Unknown
     0xE0001,  # .. 0xE0001 ; Common
     0xE0002,  # .. 0xE001F ; Unknown
     0xE0020,  # .. 0xE007F ; Common
@@ -1658,7 +1632,9 @@
     'Zzzz',  # 0530..0530 ; Unknown
     'Armn',  # 0531..0556 ; Armenian
     'Zzzz',  # 0557..0558 ; Unknown
-    'Armn',  # 0559..058A ; Armenian
+    'Armn',  # 0559..0588 ; Armenian
+    'Zyyy',  # 0589..0589 ; Common
+    'Armn',  # 058A..058A ; Armenian
     'Zzzz',  # 058B..058C ; Unknown
     'Armn',  # 058D..058F ; Armenian
     'Zzzz',  # 0590..0590 ; Unknown
@@ -1710,8 +1686,8 @@
     'Zzzz',  # 086B..089F ; Unknown
     'Arab',  # 08A0..08B4 ; Arabic
     'Zzzz',  # 08B5..08B5 ; Unknown
-    'Arab',  # 08B6..08C7 ; Arabic
-    'Zzzz',  # 08C8..08D2 ; Unknown
+    'Arab',  # 08B6..08BD ; Arabic
+    'Zzzz',  # 08BE..08D2 ; Unknown
     'Arab',  # 08D3..08E1 ; Arabic
     'Zyyy',  # 08E2..08E2 ; Common
     'Arab',  # 08E3..08FF ; Arabic
@@ -1827,8 +1803,8 @@
     'Orya',  # 0B47..0B48 ; Oriya
     'Zzzz',  # 0B49..0B4A ; Unknown
     'Orya',  # 0B4B..0B4D ; Oriya
-    'Zzzz',  # 0B4E..0B54 ; Unknown
-    'Orya',  # 0B55..0B57 ; Oriya
+    'Zzzz',  # 0B4E..0B55 ; Unknown
+    'Orya',  # 0B56..0B57 ; Oriya
     'Zzzz',  # 0B58..0B5B ; Unknown
     'Orya',  # 0B5C..0B5D ; Oriya
     'Zzzz',  # 0B5E..0B5E ; Unknown
@@ -1917,7 +1893,9 @@
     'Zzzz',  # 0CF0..0CF0 ; Unknown
     'Knda',  # 0CF1..0CF2 ; Kannada
     'Zzzz',  # 0CF3..0CFF ; Unknown
-    'Mlym',  # 0D00..0D0C ; Malayalam
+    'Mlym',  # 0D00..0D03 ; Malayalam
+    'Zzzz',  # 0D04..0D04 ; Unknown
+    'Mlym',  # 0D05..0D0C ; Malayalam
     'Zzzz',  # 0D0D..0D0D ; Unknown
     'Mlym',  # 0D0E..0D10 ; Malayalam
     'Zzzz',  # 0D11..0D11 ; Unknown
@@ -1930,8 +1908,8 @@
     'Mlym',  # 0D54..0D63 ; Malayalam
     'Zzzz',  # 0D64..0D65 ; Unknown
     'Mlym',  # 0D66..0D7F ; Malayalam
-    'Zzzz',  # 0D80..0D80 ; Unknown
-    'Sinh',  # 0D81..0D83 ; Sinhala
+    'Zzzz',  # 0D80..0D81 ; Unknown
+    'Sinh',  # 0D82..0D83 ; Sinhala
     'Zzzz',  # 0D84..0D84 ; Unknown
     'Sinh',  # 0D85..0D96 ; Sinhala
     'Zzzz',  # 0D97..0D99 ; Unknown
@@ -2123,8 +2101,8 @@
     'Zzzz',  # 1A9A..1A9F ; Unknown
     'Lana',  # 1AA0..1AAD ; Tai_Tham
     'Zzzz',  # 1AAE..1AAF ; Unknown
-    'Zinh',  # 1AB0..1AC0 ; Inherited
-    'Zzzz',  # 1AC1..1AFF ; Unknown
+    'Zinh',  # 1AB0..1ABE ; Inherited
+    'Zzzz',  # 1ABF..1AFF ; Unknown
     'Bali',  # 1B00..1B4B ; Balinese
     'Zzzz',  # 1B4C..1B4F ; Unknown
     'Bali',  # 1B50..1B7C ; Balinese
@@ -2244,8 +2222,8 @@
     'Zyyy',  # 2900..2B73 ; Common
     'Zzzz',  # 2B74..2B75 ; Unknown
     'Zyyy',  # 2B76..2B95 ; Common
-    'Zzzz',  # 2B96..2B96 ; Unknown
-    'Zyyy',  # 2B97..2BFF ; Common
+    'Zzzz',  # 2B96..2B97 ; Unknown
+    'Zyyy',  # 2B98..2BFF ; Common
     'Glag',  # 2C00..2C2E ; Glagolitic
     'Zzzz',  # 2C2F..2C2F ; Unknown
     'Glag',  # 2C30..2C5E ; Glagolitic
@@ -2284,8 +2262,8 @@
     'Ethi',  # 2DD8..2DDE ; Ethiopic
     'Zzzz',  # 2DDF..2DDF ; Unknown
     'Cyrl',  # 2DE0..2DFF ; Cyrillic
-    'Zyyy',  # 2E00..2E52 ; Common
-    'Zzzz',  # 2E53..2E7F ; Unknown
+    'Zyyy',  # 2E00..2E4F ; Common
+    'Zzzz',  # 2E50..2E7F ; Unknown
     'Hani',  # 2E80..2E99 ; Han
     'Zzzz',  # 2E9A..2E9A ; Unknown
     'Hani',  # 2E9B..2EF3 ; Han
@@ -2321,7 +2299,8 @@
     'Hang',  # 3131..318E ; Hangul
     'Zzzz',  # 318F..318F ; Unknown
     'Zyyy',  # 3190..319F ; Common
-    'Bopo',  # 31A0..31BF ; Bopomofo
+    'Bopo',  # 31A0..31BA ; Bopomofo
+    'Zzzz',  # 31BB..31BF ; Unknown
     'Zyyy',  # 31C0..31E3 ; Common
     'Zzzz',  # 31E4..31EF ; Unknown
     'Kana',  # 31F0..31FF ; Katakana
@@ -2334,10 +2313,11 @@
     'Zyyy',  # 32FF..32FF ; Common
     'Kana',  # 3300..3357 ; Katakana
     'Zyyy',  # 3358..33FF ; Common
-    'Hani',  # 3400..4DBF ; Han
+    'Hani',  # 3400..4DB5 ; Han
+    'Zzzz',  # 4DB6..4DBF ; Unknown
     'Zyyy',  # 4DC0..4DFF ; Common
-    'Hani',  # 4E00..9FFC ; Han
-    'Zzzz',  # 9FFD..9FFF ; Unknown
+    'Hani',  # 4E00..9FEF ; Han
+    'Zzzz',  # 9FF0..9FFF ; Unknown
     'Yiii',  # A000..A48C ; Yi
     'Zzzz',  # A48D..A48F ; Unknown
     'Yiii',  # A490..A4C6 ; Yi
@@ -2353,11 +2333,11 @@
     'Zyyy',  # A788..A78A ; Common
     'Latn',  # A78B..A7BF ; Latin
     'Zzzz',  # A7C0..A7C1 ; Unknown
-    'Latn',  # A7C2..A7CA ; Latin
-    'Zzzz',  # A7CB..A7F4 ; Unknown
-    'Latn',  # A7F5..A7FF ; Latin
-    'Sylo',  # A800..A82C ; Syloti_Nagri
-    'Zzzz',  # A82D..A82F ; Unknown
+    'Latn',  # A7C2..A7C6 ; Latin
+    'Zzzz',  # A7C7..A7F6 ; Unknown
+    'Latn',  # A7F7..A7FF ; Latin
+    'Sylo',  # A800..A82B ; Syloti_Nagri
+    'Zzzz',  # A82C..A82F ; Unknown
     'Zyyy',  # A830..A839 ; Common
     'Zzzz',  # A83A..A83F ; Unknown
     'Phag',  # A840..A877 ; Phags_Pa
@@ -2410,9 +2390,8 @@
     'Zyyy',  # AB5B..AB5B ; Common
     'Latn',  # AB5C..AB64 ; Latin
     'Grek',  # AB65..AB65 ; Greek
-    'Latn',  # AB66..AB69 ; Latin
-    'Zyyy',  # AB6A..AB6B ; Common
-    'Zzzz',  # AB6C..AB6F ; Unknown
+    'Latn',  # AB66..AB67 ; Latin
+    'Zzzz',  # AB68..AB6F ; Unknown
     'Cher',  # AB70..ABBF ; Cherokee
     'Mtei',  # ABC0..ABED ; Meetei_Mayek
     'Zzzz',  # ABEE..ABEF ; Unknown
@@ -2517,8 +2496,8 @@
     'Zyyy',  # 10137..1013F ; Common
     'Grek',  # 10140..1018E ; Greek
     'Zzzz',  # 1018F..1018F ; Unknown
-    'Zyyy',  # 10190..1019C ; Common
-    'Zzzz',  # 1019D..1019F ; Unknown
+    'Zyyy',  # 10190..1019B ; Common
+    'Zzzz',  # 1019C..1019F ; Unknown
     'Grek',  # 101A0..101A0 ; Greek
     'Zzzz',  # 101A1..101CF ; Unknown
     'Zyyy',  # 101D0..101FC ; Common
@@ -2654,19 +2633,11 @@
     'Rohg',  # 10D30..10D39 ; Hanifi_Rohingya
     'Zzzz',  # 10D3A..10E5F ; Unknown
     'Arab',  # 10E60..10E7E ; Arabic
-    'Zzzz',  # 10E7F..10E7F ; Unknown
-    'Yezi',  # 10E80..10EA9 ; Yezidi
-    'Zzzz',  # 10EAA..10EAA ; Unknown
-    'Yezi',  # 10EAB..10EAD ; Yezidi
-    'Zzzz',  # 10EAE..10EAF ; Unknown
-    'Yezi',  # 10EB0..10EB1 ; Yezidi
-    'Zzzz',  # 10EB2..10EFF ; Unknown
+    'Zzzz',  # 10E7F..10EFF ; Unknown
     'Sogo',  # 10F00..10F27 ; Old_Sogdian
     'Zzzz',  # 10F28..10F2F ; Unknown
     'Sogd',  # 10F30..10F59 ; Sogdian
-    'Zzzz',  # 10F5A..10FAF ; Unknown
-    'Chrs',  # 10FB0..10FCB ; Chorasmian
-    'Zzzz',  # 10FCC..10FDF ; Unknown
+    'Zzzz',  # 10F5A..10FDF ; Unknown
     'Elym',  # 10FE0..10FF6 ; Elymaic
     'Zzzz',  # 10FF7..10FFF ; Unknown
     'Brah',  # 11000..1104D ; Brahmi
@@ -2684,11 +2655,13 @@
     'Zzzz',  # 110FA..110FF ; Unknown
     'Cakm',  # 11100..11134 ; Chakma
     'Zzzz',  # 11135..11135 ; Unknown
-    'Cakm',  # 11136..11147 ; Chakma
-    'Zzzz',  # 11148..1114F ; Unknown
+    'Cakm',  # 11136..11146 ; Chakma
+    'Zzzz',  # 11147..1114F ; Unknown
     'Mahj',  # 11150..11176 ; Mahajani
     'Zzzz',  # 11177..1117F ; Unknown
-    'Shrd',  # 11180..111DF ; Sharada
+    'Shrd',  # 11180..111CD ; Sharada
+    'Zzzz',  # 111CE..111CF ; Unknown
+    'Shrd',  # 111D0..111DF ; Sharada
     'Zzzz',  # 111E0..111E0 ; Unknown
     'Sinh',  # 111E1..111F4 ; Sinhala
     'Zzzz',  # 111F5..111FF ; Unknown
@@ -2741,10 +2714,12 @@
     'Zzzz',  # 1136D..1136F ; Unknown
     'Gran',  # 11370..11374 ; Grantha
     'Zzzz',  # 11375..113FF ; Unknown
-    'Newa',  # 11400..1145B ; Newa
+    'Newa',  # 11400..11459 ; Newa
+    'Zzzz',  # 1145A..1145A ; Unknown
+    'Newa',  # 1145B..1145B ; Newa
     'Zzzz',  # 1145C..1145C ; Unknown
-    'Newa',  # 1145D..11461 ; Newa
-    'Zzzz',  # 11462..1147F ; Unknown
+    'Newa',  # 1145D..1145F ; Newa
+    'Zzzz',  # 11460..1147F ; Unknown
     'Tirh',  # 11480..114C7 ; Tirhuta
     'Zzzz',  # 114C8..114CF ; Unknown
     'Tirh',  # 114D0..114D9 ; Tirhuta
@@ -2774,22 +2749,7 @@
     'Wara',  # 118A0..118F2 ; Warang_Citi
     'Zzzz',  # 118F3..118FE ; Unknown
     'Wara',  # 118FF..118FF ; Warang_Citi
-    'Diak',  # 11900..11906 ; Dives_Akuru
-    'Zzzz',  # 11907..11908 ; Unknown
-    'Diak',  # 11909..11909 ; Dives_Akuru
-    'Zzzz',  # 1190A..1190B ; Unknown
-    'Diak',  # 1190C..11913 ; Dives_Akuru
-    'Zzzz',  # 11914..11914 ; Unknown
-    'Diak',  # 11915..11916 ; Dives_Akuru
-    'Zzzz',  # 11917..11917 ; Unknown
-    'Diak',  # 11918..11935 ; Dives_Akuru
-    'Zzzz',  # 11936..11936 ; Unknown
-    'Diak',  # 11937..11938 ; Dives_Akuru
-    'Zzzz',  # 11939..1193A ; Unknown
-    'Diak',  # 1193B..11946 ; Dives_Akuru
-    'Zzzz',  # 11947..1194F ; Unknown
-    'Diak',  # 11950..11959 ; Dives_Akuru
-    'Zzzz',  # 1195A..1199F ; Unknown
+    'Zzzz',  # 11900..1199F ; Unknown
     'Nand',  # 119A0..119A7 ; Nandinagari
     'Zzzz',  # 119A8..119A9 ; Unknown
     'Nand',  # 119AA..119D7 ; Nandinagari
@@ -2843,9 +2803,7 @@
     'Gong',  # 11DA0..11DA9 ; Gunjala_Gondi
     'Zzzz',  # 11DAA..11EDF ; Unknown
     'Maka',  # 11EE0..11EF8 ; Makasar
-    'Zzzz',  # 11EF9..11FAF ; Unknown
-    'Lisu',  # 11FB0..11FB0 ; Lisu
-    'Zzzz',  # 11FB1..11FBF ; Unknown
+    'Zzzz',  # 11EF9..11FBF ; Unknown
     'Taml',  # 11FC0..11FF1 ; Tamil
     'Zzzz',  # 11FF2..11FFE ; Unknown
     'Taml',  # 11FFF..11FFF ; Tamil
@@ -2896,17 +2854,11 @@
     'Tang',  # 16FE0..16FE0 ; Tangut
     'Nshu',  # 16FE1..16FE1 ; Nushu
     'Zyyy',  # 16FE2..16FE3 ; Common
-    'Kits',  # 16FE4..16FE4 ; Khitan_Small_Script
-    'Zzzz',  # 16FE5..16FEF ; Unknown
-    'Hani',  # 16FF0..16FF1 ; Han
-    'Zzzz',  # 16FF2..16FFF ; Unknown
+    'Zzzz',  # 16FE4..16FFF ; Unknown
     'Tang',  # 17000..187F7 ; Tangut
     'Zzzz',  # 187F8..187FF ; Unknown
-    'Tang',  # 18800..18AFF ; Tangut
-    'Kits',  # 18B00..18CD5 ; Khitan_Small_Script
-    'Zzzz',  # 18CD6..18CFF ; Unknown
-    'Tang',  # 18D00..18D08 ; Tangut
-    'Zzzz',  # 18D09..1AFFF ; Unknown
+    'Tang',  # 18800..18AF2 ; Tangut
+    'Zzzz',  # 18AF3..1AFFF ; Unknown
     'Kana',  # 1B000..1B000 ; Katakana
     'Hira',  # 1B001..1B11E ; Hiragana
     'Zzzz',  # 1B11F..1B14F ; Unknown
@@ -3112,8 +3064,12 @@
     'Zzzz',  # 1F0D0..1F0D0 ; Unknown
     'Zyyy',  # 1F0D1..1F0F5 ; Common
     'Zzzz',  # 1F0F6..1F0FF ; Unknown
-    'Zyyy',  # 1F100..1F1AD ; Common
-    'Zzzz',  # 1F1AE..1F1E5 ; Unknown
+    'Zyyy',  # 1F100..1F10C ; Common
+    'Zzzz',  # 1F10D..1F10F ; Unknown
+    'Zyyy',  # 1F110..1F16C ; Common
+    'Zzzz',  # 1F16D..1F16F ; Unknown
+    'Zyyy',  # 1F170..1F1AC ; Common
+    'Zzzz',  # 1F1AD..1F1E5 ; Unknown
     'Zyyy',  # 1F1E6..1F1FF ; Common
     'Hira',  # 1F200..1F200 ; Hiragana
     'Zyyy',  # 1F201..1F202 ; Common
@@ -3126,12 +3082,12 @@
     'Zzzz',  # 1F252..1F25F ; Unknown
     'Zyyy',  # 1F260..1F265 ; Common
     'Zzzz',  # 1F266..1F2FF ; Unknown
-    'Zyyy',  # 1F300..1F6D7 ; Common
-    'Zzzz',  # 1F6D8..1F6DF ; Unknown
+    'Zyyy',  # 1F300..1F6D5 ; Common
+    'Zzzz',  # 1F6D6..1F6DF ; Unknown
     'Zyyy',  # 1F6E0..1F6EC ; Common
     'Zzzz',  # 1F6ED..1F6EF ; Unknown
-    'Zyyy',  # 1F6F0..1F6FC ; Common
-    'Zzzz',  # 1F6FD..1F6FF ; Unknown
+    'Zyyy',  # 1F6F0..1F6FA ; Common
+    'Zzzz',  # 1F6FB..1F6FF ; Unknown
     'Zyyy',  # 1F700..1F773 ; Common
     'Zzzz',  # 1F774..1F77F ; Unknown
     'Zyyy',  # 1F780..1F7D8 ; Common
@@ -3147,39 +3103,33 @@
     'Zyyy',  # 1F860..1F887 ; Common
     'Zzzz',  # 1F888..1F88F ; Unknown
     'Zyyy',  # 1F890..1F8AD ; Common
-    'Zzzz',  # 1F8AE..1F8AF ; Unknown
-    'Zyyy',  # 1F8B0..1F8B1 ; Common
-    'Zzzz',  # 1F8B2..1F8FF ; Unknown
-    'Zyyy',  # 1F900..1F978 ; Common
-    'Zzzz',  # 1F979..1F979 ; Unknown
-    'Zyyy',  # 1F97A..1F9CB ; Common
-    'Zzzz',  # 1F9CC..1F9CC ; Unknown
+    'Zzzz',  # 1F8AE..1F8FF ; Unknown
+    'Zyyy',  # 1F900..1F90B ; Common
+    'Zzzz',  # 1F90C..1F90C ; Unknown
+    'Zyyy',  # 1F90D..1F971 ; Common
+    'Zzzz',  # 1F972..1F972 ; Unknown
+    'Zyyy',  # 1F973..1F976 ; Common
+    'Zzzz',  # 1F977..1F979 ; Unknown
+    'Zyyy',  # 1F97A..1F9A2 ; Common
+    'Zzzz',  # 1F9A3..1F9A4 ; Unknown
+    'Zyyy',  # 1F9A5..1F9AA ; Common
+    'Zzzz',  # 1F9AB..1F9AD ; Unknown
+    'Zyyy',  # 1F9AE..1F9CA ; Common
+    'Zzzz',  # 1F9CB..1F9CC ; Unknown
     'Zyyy',  # 1F9CD..1FA53 ; Common
     'Zzzz',  # 1FA54..1FA5F ; Unknown
     'Zyyy',  # 1FA60..1FA6D ; Common
     'Zzzz',  # 1FA6E..1FA6F ; Unknown
-    'Zyyy',  # 1FA70..1FA74 ; Common
-    'Zzzz',  # 1FA75..1FA77 ; Unknown
+    'Zyyy',  # 1FA70..1FA73 ; Common
+    'Zzzz',  # 1FA74..1FA77 ; Unknown
     'Zyyy',  # 1FA78..1FA7A ; Common
     'Zzzz',  # 1FA7B..1FA7F ; Unknown
-    'Zyyy',  # 1FA80..1FA86 ; Common
-    'Zzzz',  # 1FA87..1FA8F ; Unknown
-    'Zyyy',  # 1FA90..1FAA8 ; Common
-    'Zzzz',  # 1FAA9..1FAAF ; Unknown
-    'Zyyy',  # 1FAB0..1FAB6 ; Common
-    'Zzzz',  # 1FAB7..1FABF ; Unknown
-    'Zyyy',  # 1FAC0..1FAC2 ; Common
-    'Zzzz',  # 1FAC3..1FACF ; Unknown
-    'Zyyy',  # 1FAD0..1FAD6 ; Common
-    'Zzzz',  # 1FAD7..1FAFF ; Unknown
-    'Zyyy',  # 1FB00..1FB92 ; Common
-    'Zzzz',  # 1FB93..1FB93 ; Unknown
-    'Zyyy',  # 1FB94..1FBCA ; Common
-    'Zzzz',  # 1FBCB..1FBEF ; Unknown
-    'Zyyy',  # 1FBF0..1FBF9 ; Common
-    'Zzzz',  # 1FBFA..1FFFF ; Unknown
-    'Hani',  # 20000..2A6DD ; Han
-    'Zzzz',  # 2A6DE..2A6FF ; Unknown
+    'Zyyy',  # 1FA80..1FA82 ; Common
+    'Zzzz',  # 1FA83..1FA8F ; Unknown
+    'Zyyy',  # 1FA90..1FA95 ; Common
+    'Zzzz',  # 1FA96..1FFFF ; Unknown
+    'Hani',  # 20000..2A6D6 ; Han
+    'Zzzz',  # 2A6D7..2A6FF ; Unknown
     'Hani',  # 2A700..2B734 ; Han
     'Zzzz',  # 2B735..2B73F ; Unknown
     'Hani',  # 2B740..2B81D ; Han
@@ -3189,9 +3139,7 @@
     'Hani',  # 2CEB0..2EBE0 ; Han
     'Zzzz',  # 2EBE1..2F7FF ; Unknown
     'Hani',  # 2F800..2FA1D ; Han
-    'Zzzz',  # 2FA1E..2FFFF ; Unknown
-    'Hani',  # 30000..3134A ; Han
-    'Zzzz',  # 3134B..E0000 ; Unknown
+    'Zzzz',  # 2FA1E..E0000 ; Unknown
     'Zyyy',  # E0001..E0001 ; Common
     'Zzzz',  # E0002..E001F ; Unknown
     'Zyyy',  # E0020..E007F ; Common
@@ -3224,12 +3172,10 @@
     'Cari': 'Carian',
     'Cham': 'Cham',
     'Cher': 'Cherokee',
-    'Chrs': 'Chorasmian',
     'Copt': 'Coptic',
     'Cprt': 'Cypriot',
     'Cyrl': 'Cyrillic',
     'Deva': 'Devanagari',
-    'Diak': 'Dives_Akuru',
     'Dogr': 'Dogra',
     'Dsrt': 'Deseret',
     'Dupl': 'Duployan',
@@ -3264,7 +3210,6 @@
     'Khar': 'Kharoshthi',
     'Khmr': 'Khmer',
     'Khoj': 'Khojki',
-    'Kits': 'Khitan_Small_Script',
     'Knda': 'Kannada',
     'Kthi': 'Kaithi',
     'Lana': 'Tai_Tham',
@@ -3353,7 +3298,6 @@
     'Wcho': 'Wancho',
     'Xpeo': 'Old_Persian',
     'Xsux': 'Cuneiform',
-    'Yezi': 'Yezidi',
     'Yiii': 'Yi',
     'Zanb': 'Zanabazar_Square',
     'Zinh': 'Inherited',
diff --git a/Lib/fontTools/unicodedata/__init__.py b/Lib/fontTools/unicodedata/__init__.py
index 8845b82..79462c7 100644
--- a/Lib/fontTools/unicodedata/__init__.py
+++ b/Lib/fontTools/unicodedata/__init__.py
@@ -1,4 +1,6 @@
-from fontTools.misc.py23 import byteord, tostr
+from __future__ import (
+    print_function, division, absolute_import, unicode_literals)
+from fontTools.misc.py23 import *
 
 import re
 from bisect import bisect_right
@@ -50,7 +52,7 @@
     'Latn'
     >>> script(",")
     'Zyyy'
-    >>> script(chr(0x10FFFF))
+    >>> script(unichr(0x10FFFF))
     'Zzzz'
     """
     code = byteord(char)
@@ -73,9 +75,9 @@
 
     >>> script_extension("a") == {'Latn'}
     True
-    >>> script_extension(chr(0x060C)) == {'Rohg', 'Syrc', 'Yezi', 'Arab', 'Thaa'}
+    >>> script_extension(unichr(0x060C)) == {'Arab', 'Rohg', 'Syrc', 'Thaa'}
     True
-    >>> script_extension(chr(0x10FFFF)) == {'Zzzz'}
+    >>> script_extension(unichr(0x10FFFF)) == {'Zzzz'}
     True
     """
     code = byteord(char)
@@ -134,8 +136,10 @@
         return default
 
 
-# The data on script direction is taken from CLDR 37:
-# https://github.com/unicode-org/cldr/blob/release-37/common/properties/scriptMetadata.txt
+# The data on script direction is taken from harfbuzz's "hb-common.cc":
+# https://goo.gl/X5FDXC
+# It matches the CLDR "scriptMetadata.txt as of January 2018:
+# http://unicode.org/repos/cldr/trunk/common/properties/scriptMetadata.txt
 RTL_SCRIPTS = {
     # Unicode-1.1 additions
     'Arab',  # Arabic
@@ -188,18 +192,6 @@
 
     # Unicode-9.0 additions
     'Adlm',  # Adlam
-
-    # Unicode-11.0 additions
-    'Rohg',  # Hanifi Rohingya
-    'Sogo',  # Old Sogdian
-    'Sogd',  # Sogdian
-
-    # Unicode-12.0 additions
-    'Elym',  # Elymaic
-
-    # Unicode-13.0 additions
-    'Chrs',  # Chorasmian
-    'Yezi',  # Yezidi
 }
 
 def script_horizontal_direction(script_code, default=KeyError):
@@ -219,9 +211,9 @@
 
     >>> block("a")
     'Basic Latin'
-    >>> block(chr(0x060C))
+    >>> block(unichr(0x060C))
     'Arabic'
-    >>> block(chr(0xEFFFF))
+    >>> block(unichr(0xEFFFF))
     'No_Block'
     """
     code = byteord(char)
diff --git a/Lib/fontTools/varLib/__init__.py b/Lib/fontTools/varLib/__init__.py
index 36ff0d9..5a88149 100644
--- a/Lib/fontTools/varLib/__init__.py
+++ b/Lib/fontTools/varLib/__init__.py
@@ -18,9 +18,11 @@
 
 API *will* change in near future.
 """
-from fontTools.misc.py23 import Tag, tostr
-from fontTools.misc.roundTools import noRound, otRound
-from fontTools.misc.vector import Vector
+from __future__ import print_function, division, absolute_import
+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
 from fontTools.ttLib.tables._f_v_a_r import Axis, NamedInstance
 from fontTools.ttLib.tables._g_l_y_f import GlyphCoordinates
@@ -34,20 +36,17 @@
 from fontTools.varLib.iup import iup_delta_optimize
 from fontTools.varLib.featureVars import addFeatureVariations
 from fontTools.designspaceLib import DesignSpaceDocument
-from functools import partial
 from collections import OrderedDict, namedtuple
 import os.path
 import logging
 from copy import deepcopy
 from pprint import pformat
-from .errors import VarLibError, VarLibValidationError
 
 log = logging.getLogger("fontTools.varLib")
 
-# This is a lib key for the designspace document. The value should be
-# an OpenType feature tag, to be used as the FeatureVariations feature.
-# If present, the DesignSpace <rules processing="..."> flag is ignored.
-FEAVAR_FEATURETAG_LIB_KEY = "com.github.fonttools.varLib.featureVarsFeatureTag"
+
+class VarLibError(Exception):
+	pass
 
 #
 # Creation routines
@@ -76,7 +75,7 @@
 		axis.axisTag = Tag(a.tag)
 		# TODO Skip axes that have no variation.
 		axis.minValue, axis.defaultValue, axis.maxValue = a.minimum, a.default, a.maximum
-		axis.axisNameID = nameTable.addMultilingualName(a.labelNames, font, minNameID=256)
+		axis.axisNameID = nameTable.addMultilingualName(a.labelNames, font)
 		axis.flags = int(a.hidden)
 		fvar.axes.append(axis)
 
@@ -84,14 +83,9 @@
 		coordinates = instance.location
 
 		if "en" not in instance.localisedStyleName:
-			if not instance.styleName:
-				raise VarLibValidationError(
-					f"Instance at location '{coordinates}' must have a default English "
-					"style name ('stylename' attribute on the instance element or a "
-					"stylename element with an 'xml:lang=\"en\"' attribute)."
-				)
+			assert instance.styleName
 			localisedStyleName = dict(instance.localisedStyleName)
-			localisedStyleName["en"] = tostr(instance.styleName)
+			localisedStyleName["en"] = tounicode(instance.styleName)
 		else:
 			localisedStyleName = instance.localisedStyleName
 
@@ -100,7 +94,7 @@
 		inst = NamedInstance()
 		inst.subfamilyNameID = nameTable.addMultilingualName(localisedStyleName)
 		if psname is not None:
-			psname = tostr(psname)
+			psname = tounicode(psname)
 			inst.postscriptNameID = nameTable.addName(psname)
 		inst.coordinates = {axes[k].tag:axes[k].map_backward(v) for k,v in coordinates.items()}
 		#inst.coordinates = {axes[k].tag:v for k,v in coordinates.items()}
@@ -145,32 +139,14 @@
 		# Current avar requirements.  We don't have to enforce
 		# these on the designer and can deduce some ourselves,
 		# but for now just enforce them.
-		if axis.minimum != min(keys):
-			raise VarLibValidationError(
-				f"Axis '{axis.name}': there must be a mapping for the axis minimum "
-				f"value {axis.minimum} and it must be the lowest input mapping value."
-			)
-		if axis.maximum != max(keys):
-			raise VarLibValidationError(
-				f"Axis '{axis.name}': there must be a mapping for the axis maximum "
-				f"value {axis.maximum} and it must be the highest input mapping value."
-			)
-		if axis.default not in keys:
-			raise VarLibValidationError(
-				f"Axis '{axis.name}': there must be a mapping for the axis default "
-				f"value {axis.default}."
-			)
-		# No duplicate input values (output values can be >= their preceeding value).
-		if len(set(keys)) != len(keys):
-			raise VarLibValidationError(
-				f"Axis '{axis.name}': All axis mapping input='...' values must be "
-				"unique, but we found duplicates."
-			)
+		assert axis.minimum == min(keys)
+		assert axis.maximum == max(keys)
+		assert axis.default in keys
+		# No duplicates
+		assert len(set(keys)) == len(keys)
+		assert len(set(vals)) == len(vals)
 		# Ascending values
-		if sorted(vals) != vals:
-			raise VarLibValidationError(
-				f"Axis '{axis.name}': mapping output values must be in ascending order."
-			)
+		assert sorted(vals) == vals
 
 		keys_triple = (axis.minimum, axis.default, axis.maximum)
 		vals_triple = tuple(axis.map_forward(v) for v in keys_triple)
@@ -207,21 +183,44 @@
 	if "STAT" in font:
 		return
 
-	from ..otlLib.builder import buildStatTable
 	fvarTable = font['fvar']
-	axes = [dict(tag=a.axisTag, name=a.axisNameID) for a in fvarTable.axes]
-	buildStatTable(font, axes)
+
+	STAT = font["STAT"] = newTable('STAT')
+	stat = STAT.table = ot.STAT()
+	stat.Version = 0x00010001
+
+	axisRecords = []
+	for i, a in enumerate(fvarTable.axes):
+		axis = ot.AxisRecord()
+		axis.AxisTag = Tag(a.axisTag)
+		axis.AxisNameID = a.axisNameID
+		axis.AxisOrdering = i
+		axisRecords.append(axis)
+
+	axisRecordArray = ot.AxisRecordArray()
+	axisRecordArray.Axis = axisRecords
+	# XXX these should not be hard-coded but computed automatically
+	stat.DesignAxisRecordSize = 8
+	stat.DesignAxisCount = len(axisRecords)
+	stat.DesignAxisRecord = axisRecordArray
+
+	# for the elided fallback name, we default to the base style name.
+	# TODO make this user-configurable via designspace document
+	stat.ElidedFallbackNameID = 2
 
 
 def _add_gvar(font, masterModel, master_ttfs, tolerance=0.5, optimize=True):
-	if tolerance < 0:
-		raise ValueError("`tolerance` must be a positive number.")
+
+	assert tolerance >= 0
 
 	log.info("Generating gvar")
 	assert "gvar" not in font
 	gvar = font["gvar"] = newTable('gvar')
+	gvar.version = 1
+	gvar.reserved = 0
+	gvar.variations = {}
+
 	glyf = font['glyf']
-	defaultMasterIndex = masterModel.reverseMapping[0]
 
 	# use hhea.ascent of base master as default vertical origin when vmtx is missing
 	baseAscent = font['hhea'].ascent
@@ -233,15 +232,6 @@
 			m["glyf"].getCoordinatesAndControls(glyph, m, defaultVerticalOrigin=baseAscent)
 			for m in master_ttfs
 		]
-
-		if allData[defaultMasterIndex][1].numberOfContours != 0:
-			# If the default master is not empty, interpret empty non-default masters
-			# as missing glyphs from a sparse master
-			allData = [
-				d if d is not None and d[1].numberOfContours != 0 else None
-				for d in allData
-			]
-
 		model, allData = masterModel.getSubModel(allData)
 
 		allCoords = [d[0] for d in allData]
@@ -254,7 +244,7 @@
 
 		# Update gvar
 		gvar.variations[glyph] = []
-		deltas = model.getDeltas(allCoords, round=partial(GlyphCoordinates.__round__, round=round))
+		deltas = model.getDeltas(allCoords)
 		supports = model.supports
 		assert len(deltas) == len(supports)
 
@@ -263,7 +253,7 @@
 		endPts = control.endPts
 
 		for i,(delta,support) in enumerate(zip(deltas[1:], supports[1:])):
-			if all(v == 0 for v in delta.array) and not isComposite:
+			if all(abs(v) <= tolerance for v in delta.array) and not isComposite:
 				continue
 			var = TupleVariation(support, delta)
 			if optimize:
@@ -294,7 +284,6 @@
 
 			gvar.variations[glyph].append(var)
 
-
 def _remove_TTHinting(font):
 	for tag in ("cvar", "cvt ", "fpgm", "prep"):
 		if tag in font:
@@ -305,7 +294,7 @@
 	font["glyf"].removeHinting()
 	# TODO: Modify gasp table to deactivate gridfitting for all ranges?
 
-def _merge_TTHinting(font, masterModel, master_ttfs):
+def _merge_TTHinting(font, masterModel, master_ttfs, tolerance=0.5):
 
 	log.info("Merging TT hinting")
 	assert "cvar" not in font
@@ -363,20 +352,19 @@
 		_remove_TTHinting(font)
 		return
 
-	variations = []
-	deltas, supports = masterModel.getDeltasAndSupports(all_cvs, round=round) # builtin round calls into Vector.__round__, which uses builtin round as we like
+	# We can build the cvar table now.
+
+	cvar = font["cvar"] = newTable('cvar')
+	cvar.version = 1
+	cvar.variations = []
+
+	deltas, supports = masterModel.getDeltasAndSupports(all_cvs)
 	for i,(delta,support) in enumerate(zip(deltas[1:], supports[1:])):
-		if all(v == 0 for v in delta):
+		delta = [otRound(d) for d in delta]
+		if all(abs(v) <= tolerance for v in delta):
 			continue
 		var = TupleVariation(support, delta)
-		variations.append(var)
-
-	# We can build the cvar table now.
-	if variations:
-		cvar = font["cvar"] = newTable('cvar')
-		cvar.version = 1
-		cvar.variations = variations
-
+		cvar.variations.append(var)
 
 _MetricsFields = namedtuple('_MetricsFields',
 	['tableTag', 'metricsTag', 'sb1', 'sb2', 'advMapping', 'vOrigMapping'])
@@ -441,7 +429,7 @@
 	vOrigDeltasAndSupports = {}
 	for glyph in glyphOrder:
 		vhAdvances = [metrics[glyph][0] if glyph in metrics else None for metrics in advMetricses]
-		vhAdvanceDeltasAndSupports[glyph] = masterModel.getDeltasAndSupports(vhAdvances, round=round)
+		vhAdvanceDeltasAndSupports[glyph] = masterModel.getDeltasAndSupports(vhAdvances)
 
 	singleModel = models.allEqual(id(v[1]) for v in vhAdvanceDeltasAndSupports.values())
 
@@ -453,7 +441,7 @@
 			# glyphs which have a non-default vOrig.
 			vOrigs = [metrics[glyph] if glyph in metrics else defaultVOrig
 				for metrics, defaultVOrig in vOrigMetricses]
-			vOrigDeltasAndSupports[glyph] = masterModel.getDeltasAndSupports(vOrigs, round=round)
+			vOrigDeltasAndSupports[glyph] = masterModel.getDeltasAndSupports(vOrigs)
 
 	directStore = None
 	if singleModel:
@@ -463,7 +451,7 @@
 		varTupleIndexes = list(range(len(supports)))
 		varData = builder.buildVarData(varTupleIndexes, [], optimize=False)
 		for glyphName in glyphOrder:
-			varData.addItem(vhAdvanceDeltasAndSupports[glyphName][0], round=noRound)
+			varData.addItem(vhAdvanceDeltasAndSupports[glyphName][0])
 		varData.optimize()
 		directStore = builder.buildVarStore(varTupleList, [varData])
 
@@ -473,14 +461,14 @@
 	for glyphName in glyphOrder:
 		deltas, supports = vhAdvanceDeltasAndSupports[glyphName]
 		storeBuilder.setSupports(supports)
-		advMapping[glyphName] = storeBuilder.storeDeltas(deltas, round=noRound)
+		advMapping[glyphName] = storeBuilder.storeDeltas(deltas)
 
 	if vOrigMetricses:
 		vOrigMap = {}
 		for glyphName in glyphOrder:
 			deltas, supports = vOrigDeltasAndSupports[glyphName]
 			storeBuilder.setSupports(supports)
-			vOrigMap[glyphName] = storeBuilder.storeDeltas(deltas, round=noRound)
+			vOrigMap[glyphName] = storeBuilder.storeDeltas(deltas)
 
 	indirectStore = storeBuilder.finish()
 	mapping2 = indirectStore.optimize()
@@ -595,22 +583,6 @@
 		mvar.ValueRecord = sorted(records, key=lambda r: r.ValueTag)
 
 
-def _add_BASE(font, masterModel, master_ttfs, axisTags):
-
-	log.info("Generating BASE")
-
-	merger = VariationMerger(masterModel, axisTags, font)
-	merger.mergeTables(font, master_ttfs, ['BASE'])
-	store = merger.store_builder.finish()
-
-	if not store.VarData:
-		return
-	base = font['BASE'].table
-	assert base.Version == 0x00010000
-	base.Version = 0x00010001
-	base.VarStore = store
-
-
 def _merge_OTL(font, model, master_fonts, axisTags):
 
 	log.info("Merging OpenType Layout tables")
@@ -643,7 +615,7 @@
 		font['GPOS'].table.remap_device_varidxes(varidx_map)
 
 
-def _add_GSUB_feature_variations(font, axes, internal_axis_supports, rules, featureTag):
+def _add_GSUB_feature_variations(font, axes, internal_axis_supports, rules):
 
 	def normalize(name, value):
 		return models.normalizeLocation(
@@ -678,7 +650,7 @@
 
 		conditional_subs.append((region, subs))
 
-	addFeatureVariations(font, conditional_subs, featureTag)
+	addFeatureVariations(font, conditional_subs)
 
 
 _DesignSpaceData = namedtuple(
@@ -691,18 +663,14 @@
 		"masters",
 		"instances",
 		"rules",
-		"rulesProcessingLast",
-		"lib",
 	],
 )
 
 
 def _add_CFF2(varFont, model, master_fonts):
-	from .cff import merge_region_fonts
+	from .cff import (convertCFFtoCFF2, merge_region_fonts)
 	glyphOrder = varFont.getGlyphOrder()
-	if "CFF2" not in varFont:
-		from .cff import convertCFFtoCFF2
-		convertCFFtoCFF2(varFont)
+	convertCFFtoCFF2(varFont)
 	ordered_fonts_list = model.reorderMasters(master_fonts, model.reverseMapping)
 	# re-ordering the master list simplifies building the CFF2 data item lists.
 	merge_region_fonts(varFont, model, ordered_fonts_list, glyphOrder)
@@ -718,10 +686,9 @@
 
 	masters = ds.sources
 	if not masters:
-		raise VarLibValidationError("Designspace must have at least one source.")
+		raise VarLibError("no sources found in .designspace")
 	instances = ds.instances
 
-	# TODO: Use fontTools.designspaceLib.tagForAxisName instead.
 	standard_axis_map = OrderedDict([
 		('weight',  ('wght', {'en': u'Weight'})),
 		('width',   ('wdth', {'en': u'Width'})),
@@ -731,15 +698,11 @@
 		])
 
 	# Setup axes
-	if not ds.axes:
-		raise VarLibValidationError(f"Designspace must have at least one axis.")
-
 	axes = OrderedDict()
-	for axis_index, axis in enumerate(ds.axes):
+	for axis in ds.axes:
 		axis_name = axis.name
 		if not axis_name:
-			if not axis.tag:
-				raise VarLibValidationError(f"Axis at index {axis_index} needs a tag.")
+			assert axis.tag is not None
 			axis_name = axis.name = axis.tag
 
 		if axis_name in standard_axis_map:
@@ -748,10 +711,9 @@
 			if not axis.labelNames:
 				axis.labelNames.update(standard_axis_map[axis_name][1])
 		else:
-			if not axis.tag:
-				raise VarLibValidationError(f"Axis at index {axis_index} needs a tag.")
+			assert axis.tag is not None
 			if not axis.labelNames:
-				axis.labelNames["en"] = tostr(axis_name)
+				axis.labelNames["en"] = tounicode(axis_name)
 
 		axes[axis_name] = axis
 	log.info("Axes:\n%s", pformat([axis.asdict() for axis in axes.values()]))
@@ -760,28 +722,14 @@
 	for obj in masters+instances:
 		obj_name = obj.name or obj.styleName or ''
 		loc = obj.location
-		if loc is None:
-			raise VarLibValidationError(
-				f"Source or instance '{obj_name}' has no location."
-			)
 		for axis_name in loc.keys():
-			if axis_name not in axes:
-				raise VarLibValidationError(
-					f"Location axis '{axis_name}' unknown for '{obj_name}'."
-				)
+			assert axis_name in axes, "Location axis '%s' unknown for '%s'." % (axis_name, obj_name)
 		for axis_name,axis in axes.items():
 			if axis_name not in loc:
-				# NOTE: `axis.default` is always user-space, but `obj.location` always design-space.
-				loc[axis_name] = axis.map_forward(axis.default)
+				loc[axis_name] = axis.default
 			else:
 				v = axis.map_backward(loc[axis_name])
-				if not (axis.minimum <= v <= axis.maximum):
-					raise VarLibValidationError(
-						f"Source or instance '{obj_name}' has out-of-range location "
-						f"for axis '{axis_name}': is mapped to {v} but must be in "
-						f"mapped range [{axis.minimum}..{axis.maximum}] (NOTE: all "
-						"values are in user-space)."
-					)
+				assert axis.minimum <= v <= axis.maximum, "Location for axis '%s' (mapped to %s) out of range for '%s' [%s..%s]" % (axis_name, v, obj_name, axis.minimum, axis.maximum)
 
 	# Normalize master locations
 
@@ -802,15 +750,9 @@
 	base_idx = None
 	for i,m in enumerate(normalized_master_locs):
 		if all(v == 0 for v in m.values()):
-			if base_idx is not None:
-				raise VarLibValidationError(
-					"More than one base master found in Designspace."
-				)
+			assert base_idx is None
 			base_idx = i
-	if base_idx is None:
-		raise VarLibValidationError(
-			"Base master not found; no master at default location?"
-		)
+	assert base_idx is not None, "Base master not found; no master at default location?"
 	log.info("Index of base master: %s", base_idx)
 
 	return _DesignSpaceData(
@@ -821,8 +763,6 @@
 		masters,
 		instances,
 		ds.rules,
-		ds.rulesProcessingLast,
-		ds.lib,
 	)
 
 
@@ -845,7 +785,7 @@
 		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.usWeightClass = %s", weight_class)
+				log.info("Setting OS/2.usWidthClass = %s", weight_class)
 				font["OS/2"].usWeightClass = weight_class
 
 		if "wdth" in location:
@@ -914,8 +854,6 @@
 	assert 0 == model.mapping[ds.base_idx]
 
 	log.info("Building variations tables")
-	if 'BASE' not in exclude and 'BASE' in vf:
-		_add_BASE(vf, model, master_fonts, axisTags)
 	if 'MVAR' not in exclude:
 		_add_MVAR(vf, model, master_fonts, axisTags)
 	if 'HVAR' not in exclude:
@@ -929,12 +867,8 @@
 	if 'cvar' not in exclude and 'glyf' in vf:
 		_merge_TTHinting(vf, model, master_fonts)
 	if 'GSUB' not in exclude and ds.rules:
-		featureTag = ds.lib.get(
-			FEAVAR_FEATURETAG_LIB_KEY,
-			"rclt" if ds.rulesProcessingLast else "rvrn"
-		)
-		_add_GSUB_feature_variations(vf, ds.axes, ds.internal_axis_supports, ds.rules, featureTag)
-	if 'CFF2' not in exclude and ('CFF ' in vf or 'CFF2' in vf):
+		_add_GSUB_feature_variations(vf, ds.axes, ds.internal_axis_supports, ds.rules)
+	if 'CFF2' not in exclude and 'CFF ' in vf:
 		_add_CFF2(vf, model, master_fonts)
 		if "post" in vf:
 			# set 'post' to format 2 to keep the glyph names dropped from CFF2
@@ -974,7 +908,7 @@
 	elif tp in ("TTF", "OTF", "WOFF", "WOFF2"):
 		font = TTFont(master_path)
 	else:
-		raise VarLibValidationError("Invalid master path: %r" % master_path)
+		raise VarLibError("Invalid master path: %r" % master_path)
 	return font
 
 
@@ -994,10 +928,10 @@
 		# If a SourceDescriptor has a layer name, demand that the compiled TTFont
 		# be supplied by the caller. This spares us from modifying MasterFinder.
 		if master.layerName and master.font is None:
-			raise VarLibValidationError(
-				f"Designspace source '{master.name or '<Unknown>'}' specified a "
-				"layer name but lacks the required TTFont object in the 'font' "
-				"attribute."
+			raise AttributeError(
+				"Designspace source '%s' specified a layer name but lacks the "
+				"required TTFont object in the 'font' attribute."
+				% (master.name or "<Unknown>")
 			)
 
 	return designspace.loadSourceFonts(_open_font, master_finder=master_finder)
@@ -1023,11 +957,10 @@
 
 
 def main(args=None):
-	"""Build a variable font from a designspace file and masters"""
 	from argparse import ArgumentParser
 	from fontTools import configLogger
 
-	parser = ArgumentParser(prog='varLib', description = main.__doc__)
+	parser = ArgumentParser(prog='varLib')
 	parser.add_argument('designspace')
 	parser.add_argument(
 		'-o',
diff --git a/Lib/fontTools/varLib/__main__.py b/Lib/fontTools/varLib/__main__.py
index 4b3a0f5..5cf05e5 100644
--- a/Lib/fontTools/varLib/__main__.py
+++ b/Lib/fontTools/varLib/__main__.py
@@ -1,6 +1,7 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 import sys
 from fontTools.varLib import main
 
-
 if __name__ == '__main__':
 	sys.exit(main())
diff --git a/Lib/fontTools/varLib/builder.py b/Lib/fontTools/varLib/builder.py
index 152336b..43fb92a 100644
--- a/Lib/fontTools/varLib/builder.py
+++ b/Lib/fontTools/varLib/builder.py
@@ -1,3 +1,4 @@
+from __future__ import print_function, division, absolute_import
 from fontTools import ttLib
 from fontTools.ttLib.tables import otTables as ot
 
diff --git a/Lib/fontTools/varLib/cff.py b/Lib/fontTools/varLib/cff.py
index 4eed8b3..aaabf85 100644
--- a/Lib/fontTools/varLib/cff.py
+++ b/Lib/fontTools/varLib/cff.py
@@ -1,4 +1,5 @@
 from collections import namedtuple
+import os
 from fontTools.cffLib import (
 	maxStackLimit,
 	TopDictIndex,
@@ -11,25 +12,14 @@
 	FontDict,
 	VarStoreData
 )
-from io import BytesIO
+from fontTools.misc.py23 import BytesIO
 from fontTools.cffLib.specializer import (
 	specializeCommands, commandsToProgram)
 from fontTools.ttLib import newTable
 from fontTools import varLib
 from fontTools.varLib.models import allEqual
-from fontTools.misc.roundTools import roundFunc
 from fontTools.misc.psCharStrings import T2CharString, T2OutlineExtractor
-from fontTools.pens.t2CharStringPen import T2CharStringPen
-from functools import partial
-
-from .errors import (
-	VarLibCFFDictMergeError, VarLibCFFPointTypeMergeError,
-	VarLibCFFHintTypeMergeError,VarLibMergeError)
-
-
-# Backwards compatibility
-MergeDictError = VarLibCFFDictMergeError
-MergeTypeError = VarLibCFFPointTypeMergeError
+from fontTools.pens.t2CharStringPen import T2CharStringPen, t2c_round
 
 
 def addCFFVarStore(varFont, varModel, varDataList, masterSupports):
@@ -40,11 +30,6 @@
 
 	topDict = varFont['CFF2'].cff.topDictIndex[0]
 	topDict.VarStore = VarStoreData(otVarStore=varStoreCFFV)
-	if topDict.FDArray[0].vstore is None:
-		fdArray = topDict.FDArray
-		for fontDict in fdArray:
-			if hasattr(fontDict, "Private"):
-				fontDict.Private.vstore = topDict.VarStore
 
 
 def lib_convertCFFToCFF2(cff, otFont):
@@ -76,16 +61,15 @@
 		fdArray.append(fontDict)
 		fontDict.Private = privateDict
 		privateOpOrder = buildOrder(privateDictOperators2)
-		if privateDict is not None:
-			for entry in privateDictOperators:
-				key = entry[1]
-				if key not in privateOpOrder:
-					if key in privateDict.rawDict:
-						# print "Removing private dict", key
-						del privateDict.rawDict[key]
-					if hasattr(privateDict, key):
-						delattr(privateDict, key)
-						# print "Removing privateDict attr", key
+		for entry in privateDictOperators:
+			key = entry[1]
+			if key not in privateOpOrder:
+				if key in privateDict.rawDict:
+					# print "Removing private dict", key
+					del privateDict.rawDict[key]
+				if hasattr(privateDict, key):
+					delattr(privateDict, key)
+					# print "Removing privateDict attr", key
 	else:
 		# clean up the PrivateDicts in the fdArray
 		fdArray = topDict.FDArray
@@ -136,6 +120,16 @@
 	del varFont['CFF ']
 
 
+class MergeDictError(TypeError):
+	def __init__(self, key, value, values):
+		error_msg = ["For the Private Dict key '{}', ".format(key),
+					 "the default font value list:",
+					 "\t{}".format(value),
+					 "had a different number of values than a region font:"]
+		error_msg += ["\t{}".format(region_value) for region_value in values]
+		error_msg = os.linesep.join(error_msg)
+
+
 def conv_to_int(num):
 	if isinstance(num, float) and num.is_integer():
 		return int(num)
@@ -219,7 +213,7 @@
 				try:
 					values = zip(*values)
 				except IndexError:
-					raise VarLibCFFDictMergeError(key, value, values)
+					raise MergeDictError(key, value, values)
 				"""
 				Row 0 contains the first  value from each master.
 				Convert each row from absolute values to relative
@@ -271,12 +265,6 @@
 			private_dict.rawDict[key] = dataList
 
 
-def _cff_or_cff2(font):
-	if "CFF " in font:
-		return font["CFF "]
-	return font["CFF2"]
-
-
 def getfd_map(varFont, fonts_list):
 	""" Since a subset source font may have fewer FontDicts in their
 	FDArray than the default font, we have to match up the FontDicts in
@@ -289,7 +277,7 @@
 	default_font = fonts_list[0]
 	region_fonts = fonts_list[1:]
 	num_regions = len(region_fonts)
-	topDict = _cff_or_cff2(default_font).cff.topDictIndex[0]
+	topDict = default_font['CFF '].cff.topDictIndex[0]
 	if not hasattr(topDict, 'FDSelect'):
 		# All glyphs reference only one FontDict.
 		# Map the FD index for regions to index 0.
@@ -305,7 +293,7 @@
 			fd_map[fdIndex] = {}
 	for ri, region_font in enumerate(region_fonts):
 		region_glyphOrder = region_font.getGlyphOrder()
-		region_topDict = _cff_or_cff2(region_font).cff.topDictIndex[0]
+		region_topDict = region_font['CFF '].cff.topDictIndex[0]
 		if not hasattr(region_topDict, 'FDSelect'):
 			# All the glyphs share the same FontDict. Pick any glyph.
 			default_fdIndex = gname_mapping[region_glyphOrder[0]]
@@ -324,7 +312,7 @@
 def merge_region_fonts(varFont, model, ordered_fonts_list, glyphOrder):
 	topDict = varFont['CFF2'].cff.topDictIndex[0]
 	top_dicts = [topDict] + [
-					_cff_or_cff2(ttFont).cff.topDictIndex[0]
+					ttFont['CFF '].cff.topDictIndex[0]
 					for ttFont in ordered_fonts_list[1:]
 					]
 	num_masters = len(model.mapping)
@@ -417,7 +405,7 @@
 	# in the PrivatDict, so we will build the default data for vsindex = 0.
 	if not vsindex_dict:
 		key = (True,) * num_masters
-		_add_new_vsindex(masterModel, key, masterSupports, vsindex_dict,
+		_add_new_vsindex(model, key, masterSupports, vsindex_dict,
 			vsindex_by_key, varDataList)
 	cvData = CVarData(varDataList=varDataList, masterSupports=masterSupports,
 						vsindex_dict=vsindex_dict)
@@ -426,6 +414,31 @@
 	return cvData
 
 
+class MergeTypeError(TypeError):
+	def __init__(self, point_type, pt_index, m_index, default_type, glyphName):
+			self.error_msg = [
+						"In glyph '{gname}' "
+						"'{point_type}' at point index {pt_index} in master "
+						"index {m_index} differs from the default font point "
+						"type '{default_type}'"
+						"".format(
+								gname=glyphName,
+								point_type=point_type, pt_index=pt_index,
+								m_index=m_index, default_type=default_type)
+							][0]
+			super(MergeTypeError, self).__init__(self.error_msg)
+
+
+def makeRoundNumberFunc(tolerance):
+	if tolerance < 0:
+		raise ValueError("Rounding tolerance must be positive")
+
+	def roundNumber(val):
+		return t2c_round(val, tolerance)
+
+	return roundNumber
+
+
 class CFFToCFF2OutlineExtractor(T2OutlineExtractor):
 	""" This class is used to remove the initial width from the CFF
 	charstring without trying to add the width to self.nominalWidthX,
@@ -447,7 +460,7 @@
 
 	def __init__(self, pen, localSubrs, globalSubrs,
 			nominalWidthX, defaultWidthX, private=None):
-		super().__init__(pen, localSubrs,
+		super(CFFToCFF2OutlineExtractor, self).__init__(pen, localSubrs,
 			globalSubrs, nominalWidthX, defaultWidthX, private)
 
 	def countHints(self):
@@ -501,7 +514,9 @@
 	def __init__(
 				self, default_commands, glyphName, num_masters, master_idx,
 				roundTolerance=0.5):
-		super().__init__(
+		super(
+			CFF2CharStringMergePen,
+			self).__init__(
 							width=None,
 							glyphSet=None, CFF2=True,
 							roundTolerance=roundTolerance)
@@ -512,7 +527,7 @@
 		self.prev_move_idx = 0
 		self.seen_moveto = False
 		self.glyphName = glyphName
-		self.round = roundFunc(roundTolerance, round=round)
+		self.roundNumber = makeRoundNumberFunc(roundTolerance)
 
 	def add_point(self, point_type, pt_coords):
 		if self.m_index == 0:
@@ -520,7 +535,7 @@
 		else:
 			cmd = self._commands[self.pt_index]
 			if cmd[0] != point_type:
-				raise VarLibCFFPointTypeMergeError(
+				raise MergeTypeError(
 									point_type,
 									self.pt_index, len(cmd[1]),
 									cmd[0], self.glyphName)
@@ -533,7 +548,7 @@
 		else:
 			cmd = self._commands[self.pt_index]
 			if cmd[0] != hint_type:
-				raise VarLibCFFHintTypeMergeError(hint_type, self.pt_index, len(cmd[1]),
+				raise MergeTypeError(hint_type, self.pt_index, len(cmd[1]),
 					cmd[0], self.glyphName)
 			cmd[1].append(args)
 		self.pt_index += 1
@@ -542,14 +557,14 @@
 		# For hintmask, fonttools.cffLib.specializer.py expects
 		# each of these to be represented by two sequential commands:
 		# first holding only the operator name, with an empty arg list,
-		# second with an empty string as the op name, and the mask arg list.
+		# second with an empty string as the op name, and  the mask arg list.
 		if self.m_index == 0:
 			self._commands.append([hint_type, []])
 			self._commands.append(["", [abs_args]])
 		else:
 			cmd = self._commands[self.pt_index]
 			if cmd[0] != hint_type:
-				raise VarLibCFFHintTypeMergeError(hint_type, self.pt_index, len(cmd[1]),
+				raise MergeTypeError(hint_type, self.pt_index, len(cmd[1]),
 					cmd[0], self.glyphName)
 			self.pt_index += 1
 			cmd = self._commands[self.pt_index]
@@ -588,7 +603,7 @@
 	def getCommands(self):
 		return self._commands
 
-	def reorder_blend_args(self, commands, get_delta_func):
+	def reorder_blend_args(self, commands, get_delta_func, round_func):
 		"""
 		We first re-order the master coordinate values.
 		For a moveto to lineto, the args are now arranged as:
@@ -619,8 +634,8 @@
 			# second has only args.
 			if lastOp in ['hintmask', 'cntrmask']:
 				coord = list(cmd[1])
-				if not allEqual(coord):
-					raise VarLibMergeError("Hintmask values cannot differ between source fonts.")
+				assert allEqual(coord), (
+					"hintmask values cannot differ between source fonts.")
 				cmd[1] = [coord[0][0]]
 			else:
 				coords = cmd[1]
@@ -631,6 +646,8 @@
 					else:
 						# convert to deltas
 						deltas = get_delta_func(coord)[1:]
+						if round_func:
+							deltas = [round_func(delta) for delta in deltas]
 						coord = [coord[0]] + deltas
 						new_coords.append(coord)
 				cmd[1] = new_coords
@@ -641,7 +658,8 @@
 					self, private=None, globalSubrs=None,
 					var_model=None, optimize=True):
 		commands = self._commands
-		commands = self.reorder_blend_args(commands, partial (var_model.getDeltas, round=self.round))
+		commands = self.reorder_blend_args(commands, var_model.getDeltas,
+											self.roundNumber)
 		if optimize:
 			commands = specializeCommands(
 						commands, generalizeFirst=False,
diff --git a/Lib/fontTools/varLib/errors.py b/Lib/fontTools/varLib/errors.py
deleted file mode 100644
index 5840070..0000000
--- a/Lib/fontTools/varLib/errors.py
+++ /dev/null
@@ -1,190 +0,0 @@
-import textwrap
-
-
-class VarLibError(Exception):
-    """Base exception for the varLib module."""
-
-
-class VarLibValidationError(VarLibError):
-    """Raised when input data is invalid from varLib's point of view."""
-
-
-class VarLibMergeError(VarLibError):
-    """Raised when input data cannot be merged into a variable font."""
-
-    def __init__(self, merger, **kwargs):
-        self.merger = merger
-        if not kwargs:
-            kwargs = {}
-        if "stack" in kwargs:
-            self.stack = kwargs["stack"]
-            del kwargs["stack"]
-        else:
-            self.stack = []
-        self.cause = kwargs
-
-    @property
-    def reason(self):
-        return self.__doc__
-
-    def _master_name(self, ix):
-        ttf = self.merger.ttfs[ix]
-        if (
-            "name" in ttf
-            and ttf["name"].getDebugName(1)
-            and ttf["name"].getDebugName(2)
-        ):
-            return ttf["name"].getDebugName(1) + " " + ttf["name"].getDebugName(2)
-        elif hasattr(ttf.reader, "file") and hasattr(ttf.reader.file, "name"):
-            return ttf.reader.file.name
-        else:
-            return "master number %i" % ix
-
-    @property
-    def offender(self):
-        if "expected" in self.cause and "got" in self.cause:
-            index = [x == self.cause["expected"] for x in self.cause["got"]].index(
-                False
-            )
-            return index, self._master_name(index)
-        return None, None
-
-    @property
-    def details(self):
-        if "expected" in self.cause and "got" in self.cause:
-            offender_index, offender = self.offender
-            got = self.cause["got"][offender_index]
-            return f"Expected to see {self.stack[0]}=={self.cause['expected']}, instead saw {got}\n"
-        return ""
-
-    def __str__(self):
-        offender_index, offender = self.offender
-        location = ""
-        if offender:
-            location = f"\n\nThe problem is likely to be in {offender}:\n"
-        context = "".join(reversed(self.stack))
-        basic = textwrap.fill(
-            f"Couldn't merge the fonts, because {self.reason}. "
-            f"This happened while performing the following operation: {context}",
-            width=78,
-        )
-        return "\n\n" + basic + location + self.details
-
-
-class ShouldBeConstant(VarLibMergeError):
-    """some values were different, but should have been the same"""
-
-    @property
-    def details(self):
-        if self.stack[0] != ".FeatureCount":
-            return super().details
-        offender_index, offender = self.offender
-        bad_ttf = self.merger.ttfs[offender_index]
-        good_ttf = self.merger.ttfs[offender_index - 1]
-
-        good_features = [
-            x.FeatureTag
-            for x in good_ttf[self.stack[-1]].table.FeatureList.FeatureRecord
-        ]
-        bad_features = [
-            x.FeatureTag
-            for x in bad_ttf[self.stack[-1]].table.FeatureList.FeatureRecord
-        ]
-        return (
-            "\nIncompatible features between masters.\n"
-            f"Expected: {', '.join(good_features)}.\n"
-            f"Got: {', '.join(bad_features)}.\n"
-        )
-
-
-class FoundANone(VarLibMergeError):
-    """one of the values in a list was empty when it shouldn't have been"""
-
-    @property
-    def offender(self):
-        cause = self.argv[0]
-        index = [x is None for x in cause["got"]].index(True)
-        return index, self._master_name(index)
-
-    @property
-    def details(self):
-        cause, stack = self.args[0], self.args[1:]
-        return f"{stack[0]}=={cause['got']}\n"
-
-
-class MismatchedTypes(VarLibMergeError):
-    """data had inconsistent types"""
-
-
-class LengthsDiffer(VarLibMergeError):
-    """a list of objects had inconsistent lengths"""
-
-
-class KeysDiffer(VarLibMergeError):
-    """a list of objects had different keys"""
-
-
-class InconsistentGlyphOrder(VarLibMergeError):
-    """the glyph order was inconsistent between masters"""
-
-
-class InconsistentExtensions(VarLibMergeError):
-    """the masters use extension lookups in inconsistent ways"""
-
-
-class UnsupportedFormat(VarLibMergeError):
-    """an OpenType subtable (%s) had a format I didn't expect"""
-
-    @property
-    def reason(self):
-        cause, stack = self.args[0], self.args[1:]
-        return self.__doc__ % cause["subtable"]
-
-
-class UnsupportedFormat(UnsupportedFormat):
-    """an OpenType subtable (%s) had inconsistent formats between masters"""
-
-
-class VarLibCFFMergeError(VarLibError):
-    pass
-
-
-class VarLibCFFDictMergeError(VarLibCFFMergeError):
-    """Raised when a CFF PrivateDict cannot be merged."""
-
-    def __init__(self, key, value, values):
-        error_msg = (
-            f"For the Private Dict key '{key}', the default font value list:"
-            f"\n\t{value}\nhad a different number of values than a region font:"
-        )
-        for region_value in values:
-            error_msg += f"\n\t{region_value}"
-        self.args = (error_msg,)
-
-
-class VarLibCFFPointTypeMergeError(VarLibCFFMergeError):
-    """Raised when a CFF glyph cannot be merged because of point type differences."""
-
-    def __init__(self, point_type, pt_index, m_index, default_type, glyph_name):
-        error_msg = (
-            f"Glyph '{glyph_name}': '{point_type}' at point index {pt_index} in "
-            f"master index {m_index} differs from the default font point type "
-            f"'{default_type}'"
-        )
-        self.args = (error_msg,)
-
-
-class VarLibCFFHintTypeMergeError(VarLibCFFMergeError):
-    """Raised when a CFF glyph cannot be merged because of hint type differences."""
-
-    def __init__(self, hint_type, cmd_index, m_index, default_type, glyph_name):
-        error_msg = (
-            f"Glyph '{glyph_name}': '{hint_type}' at index {cmd_index} in "
-            f"master index {m_index} differs from the default font hint type "
-            f"'{default_type}'"
-        )
-        self.args = (error_msg,)
-
-
-class VariationModelError(VarLibError):
-    """Raised when a variation model is faulty."""
diff --git a/Lib/fontTools/varLib/featureVars.py b/Lib/fontTools/varLib/featureVars.py
index 45f3d83..0c6913d 100644
--- a/Lib/fontTools/varLib/featureVars.py
+++ b/Lib/fontTools/varLib/featureVars.py
@@ -3,6 +3,8 @@
 
 NOTE: The API is experimental and subject to change.
 """
+from __future__ import print_function, absolute_import, division
+from fontTools.misc.py23 import *
 from fontTools.misc.dictTools import hashdict
 from fontTools.misc.intTools import popCount
 from fontTools.ttLib import newTable
@@ -10,10 +12,8 @@
 from fontTools.otlLib.builder import buildLookup, buildSingleSubstSubtable
 from collections import OrderedDict
 
-from .errors import VarLibError, VarLibValidationError
 
-
-def addFeatureVariations(font, conditionalSubstitutions, featureTag='rvrn'):
+def addFeatureVariations(font, conditionalSubstitutions):
     """Add conditional substitutions to a Variable Font.
 
     The `conditionalSubstitutions` argument is a list of (Region, Substitutions)
@@ -45,8 +45,7 @@
     """
 
     addFeatureVariationsRaw(font,
-                            overlayFeatureVariations(conditionalSubstitutions),
-                            featureTag)
+                            overlayFeatureVariations(conditionalSubstitutions))
 
 def overlayFeatureVariations(conditionalSubstitutions):
     """Compute overlaps between all conditional substitutions.
@@ -82,7 +81,6 @@
     ...     ([{"wght": (0.5, 1.0)}], {"dollar": "dollar.rvrn"}),
     ...     ([{"wght": (0.5, 1.0)}], {"dollar": "dollar.rvrn"}),
     ...     ([{"wdth": (0.5, 1.0)}], {"cent": "cent.rvrn"}),
-    ...     ([{"wght": (0.5, 1.0), "wdth": (-1, 1.0)}], {"dollar": "dollar.rvrn"}),
     ... ]
     >>> from pprint import pprint
     >>> pprint(overlayFeatureVariations(condSubst))
@@ -137,14 +135,12 @@
                     remainder = hashdict(remainder)
                     newMap[remainder] = newMap.get(remainder, 0) | rank
         boxMap = newMap
+    del boxMap[hashdict()]
 
     # Generate output
     items = []
     for box,rank in sorted(boxMap.items(),
                            key=(lambda BoxAndRank: -popCount(BoxAndRank[1]))):
-        # Skip any box that doesn't have any substitution.
-        if rank == 0:
-            continue
         substsList = []
         i = 0
         while rank:
@@ -261,15 +257,15 @@
 # Low level implementation
 #
 
-def addFeatureVariationsRaw(font, conditionalSubstitutions, featureTag='rvrn'):
+def addFeatureVariationsRaw(font, conditionalSubstitutions):
     """Low level implementation of addFeatureVariations that directly
     models the possibilities of the FeatureVariations table."""
 
     #
-    # if there is no <featureTag> feature:
-    #     make empty <featureTag> feature
-    #     sort features, get <featureTag> feature index
-    #     add <featureTag> feature to all scripts
+    # assert there is no 'rvrn' feature
+    # make dummy 'rvrn' feature with no lookups
+    # sort features, get 'rvrn' feature index
+    # add 'rvrn' feature to all scripts
     # make lookups
     # add feature variations
     #
@@ -284,30 +280,20 @@
 
     gsub.FeatureVariations = None  # delete any existing FeatureVariations
 
-    varFeatureIndices = []
-    for index, feature in enumerate(gsub.FeatureList.FeatureRecord):
-        if feature.FeatureTag == featureTag:
-            varFeatureIndices.append(index)
+    for feature in gsub.FeatureList.FeatureRecord:
+        assert feature.FeatureTag != 'rvrn'
 
-    if not varFeatureIndices:
-        varFeature = buildFeatureRecord(featureTag, [])
-        gsub.FeatureList.FeatureRecord.append(varFeature)
-        gsub.FeatureList.FeatureCount = len(gsub.FeatureList.FeatureRecord)
+    rvrnFeature = buildFeatureRecord('rvrn', [])
+    gsub.FeatureList.FeatureRecord.append(rvrnFeature)
+    gsub.FeatureList.FeatureCount = len(gsub.FeatureList.FeatureRecord)
 
-        sortFeatureList(gsub)
-        varFeatureIndex = gsub.FeatureList.FeatureRecord.index(varFeature)
+    sortFeatureList(gsub)
+    rvrnFeatureIndex = gsub.FeatureList.FeatureRecord.index(rvrnFeature)
 
-        for scriptRecord in gsub.ScriptList.ScriptRecord:
-            if scriptRecord.Script.DefaultLangSys is None:
-                raise VarLibError(
-                    "Feature variations require that the script "
-                    f"'{scriptRecord.ScriptTag}' defines a default language system."
-                )
-            langSystems = [lsr.LangSys for lsr in scriptRecord.Script.LangSysRecord]
-            for langSys in [scriptRecord.Script.DefaultLangSys] + langSystems:
-                langSys.FeatureIndex.append(varFeatureIndex)
-
-        varFeatureIndices = [varFeatureIndex]
+    for scriptRecord in gsub.ScriptList.ScriptRecord:
+        langSystems = [lsr.LangSys for lsr in scriptRecord.Script.LangSysRecord]
+        for langSys in [scriptRecord.Script.DefaultLangSys] + langSystems:
+            langSys.FeatureIndex.append(rvrnFeatureIndex)
 
     # setup lookups
 
@@ -322,19 +308,13 @@
     for conditionSet, substitutions in conditionalSubstitutions:
         conditionTable = []
         for axisTag, (minValue, maxValue) in sorted(conditionSet.items()):
-            if minValue > maxValue:
-                raise VarLibValidationError(
-                    "A condition set has a minimum value above the maximum value."
-                )
+            assert minValue < maxValue
             ct = buildConditionTable(axisIndices[axisTag], minValue, maxValue)
             conditionTable.append(ct)
 
         lookupIndices = [lookupMap[subst] for subst in substitutions]
-        records = []
-        for varFeatureIndex in varFeatureIndices:
-            existingLookupIndices = gsub.FeatureList.FeatureRecord[varFeatureIndex].Feature.LookupListIndex
-            records.append(buildFeatureTableSubstitutionRecord(varFeatureIndex, existingLookupIndices + lookupIndices))
-        featureVariationRecords.append(buildFeatureVariationRecord(conditionTable, records))
+        record = buildFeatureTableSubstitutionRecord(rvrnFeatureIndex, lookupIndices)
+        featureVariationRecords.append(buildFeatureVariationRecord(conditionTable, [record]))
 
     gsub.FeatureVariations = buildFeatureVariations(featureVariationRecords)
 
diff --git a/Lib/fontTools/varLib/instancer.py b/Lib/fontTools/varLib/instancer.py
new file mode 100644
index 0000000..52d62c9
--- /dev/null
+++ b/Lib/fontTools/varLib/instancer.py
@@ -0,0 +1,1037 @@
+""" Partially instantiate a variable font.
+
+The module exports an `instantiateVariableFont` function and CLI that allow to
+create full instances (i.e. static fonts) from variable fonts, as well as "partial"
+variable fonts that only contain a subset of the original variation space.
+
+For example, if you wish to pin the width axis to a given location while keeping
+the rest of the axes, you can do:
+
+$ fonttools varLib.instancer ./NotoSans-VF.ttf wdth=85
+
+See `fonttools varLib.instancer --help` for more info on the CLI options.
+
+The module's entry point is the `instantiateVariableFont` function, which takes
+a TTFont object and a dict specifying a location along either some or all the axes,
+and returns a new TTFont representing respectively a partial or a full instance.
+
+E.g. here's how to pin the wght axis at a given location in a wght+wdth variable
+font, keeping only the deltas associated with the wdth axis:
+
+| >>> from fontTools import ttLib
+| >>> from fontTools.varLib import instancer
+| >>> varfont = ttLib.TTFont("path/to/MyVariableFont.ttf")
+| >>> [a.axisTag for a in partial["fvar"].axes]  # the varfont's current axes
+| ['wght', 'wdth']
+| >>> partial = instancer.instantiateVariableFont(varfont, {"wght": 300})
+| >>> [a.axisTag for a in partial["fvar"].axes]  # axes left after pinning 'wght'
+| ['wdth']
+
+If the input location specifies all the axes, the resulting instance is no longer
+'variable' (same as using fontools varLib.mutator):
+
+| >>> instance = instancer.instantiateVariableFont(
+| ...     varfont, {"wght": 700, "wdth": 67.5}
+| ... )
+| >>> "fvar" not in instance
+| True
+
+If one just want to drop an axis at the default location, without knowing in
+advance what the default value for that axis is, one can pass a `None` value:
+
+| >>> instance = instancer.instantiateVariableFont(varfont, {"wght": None})
+| >>> len(varfont["fvar"].axes)
+| 1
+
+From the console script, this is equivalent to passing `wght=drop` as input.
+
+This module is similar to fontTools.varLib.mutator, which it's intended to supersede.
+Note that, unlike varLib.mutator, when an axis is not mentioned in the input
+location, the varLib.instancer will keep the axis and the corresponding deltas,
+whereas mutator implicitly drops the axis at its default coordinate.
+
+The module currently supports only the first two "levels" of partial instancing,
+with the rest planned to be implemented in the future, namely:
+L1) dropping one or more axes while leaving the default tables unmodified;
+L2) dropping one or more axes while pinning them at non-default locations;
+L3) restricting the range of variation of one or more axes, by setting either
+    a new minimum or maximum, potentially -- though not necessarily -- dropping
+    entire regions of variations that fall completely outside this new range.
+L4) moving the default location of an axis.
+
+Currently only TrueType-flavored variable fonts (i.e. containing 'glyf' table)
+are supported, but support for CFF2 variable fonts will be added soon.
+
+The discussion and implementation of these features are tracked at
+https://github.com/fonttools/fonttools/issues/1537
+"""
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools.misc.fixedTools import floatToFixedToFloat, otRound
+from fontTools.varLib.models import supportScalar, normalizeValue, piecewiseLinearMap
+from fontTools.ttLib import TTFont
+from fontTools.ttLib.tables.TupleVariation import TupleVariation
+from fontTools.ttLib.tables import _g_l_y_f
+from fontTools import varLib
+
+# we import the `subset` module because we use the `prune_lookups` method on the GSUB
+# table class, and that method is only defined dynamically upon importing `subset`
+from fontTools import subset  # noqa: F401
+from fontTools.varLib import builder
+from fontTools.varLib.mvar import MVAR_ENTRIES
+from fontTools.varLib.merger import MutatorMerger
+from contextlib import contextmanager
+import collections
+from copy import deepcopy
+import logging
+from itertools import islice
+import os
+import re
+
+
+log = logging.getLogger("fontTools.varLib.instancer")
+
+
+def instantiateTupleVariationStore(variations, location, origCoords=None, endPts=None):
+    """Instantiate TupleVariation list at the given location.
+
+    The 'variations' list of TupleVariation objects is modified in-place.
+    The input location can describe either a full instance (all the axes are assigned an
+    explicit coordinate) or partial (some of the axes are omitted).
+    Tuples that do not participate are kept as they are. Those that have 0 influence
+    at the given location are removed from the variation store.
+    Those that are fully instantiated (i.e. all their axes are being pinned) are also
+    removed from the variation store, their scaled deltas accummulated and returned, so
+    that they can be added by the caller to the default instance's coordinates.
+    Tuples that are only partially instantiated (i.e. not all the axes that they
+    participate in are being pinned) are kept in the store, and their deltas multiplied
+    by the scalar support of the axes to be pinned at the desired location.
+
+    Args:
+        variations: List[TupleVariation] from either 'gvar' or 'cvar'.
+        location: Dict[str, float]: axes coordinates for the full or partial instance.
+        origCoords: GlyphCoordinates: default instance's coordinates for computing 'gvar'
+            inferred points (cf. table__g_l_y_f.getCoordinatesAndControls).
+        endPts: List[int]: indices of contour end points, for inferring 'gvar' deltas.
+
+    Returns:
+        List[float]: the overall delta adjustment after applicable deltas were summed.
+    """
+    newVariations = collections.OrderedDict()
+    for var in variations:
+        # Compute the scalar support of the axes to be pinned at the desired location,
+        # excluding any axes that we are not pinning.
+        # If a TupleVariation doesn't mention an axis, it implies that the axis peak
+        # is 0 (i.e. the axis does not participate).
+        support = {axis: var.axes.pop(axis, (-1, 0, +1)) for axis in location}
+        scalar = supportScalar(location, support)
+        if scalar == 0.0:
+            # no influence, drop the TupleVariation
+            continue
+
+        # compute inferred deltas only for gvar ('origCoords' is None for cvar)
+        if origCoords is not None:
+            var.calcInferredDeltas(origCoords, endPts)
+
+        var.scaleDeltas(scalar)
+
+        # merge TupleVariations with overlapping "tents"
+        axes = tuple(var.axes.items())
+        if axes in newVariations:
+            newVariations[axes] += var
+        else:
+            newVariations[axes] = var
+
+    # drop TupleVariation if all axes have been pinned (var.axes.items() is empty);
+    # its deltas will be added to the default instance's coordinates
+    defaultVar = newVariations.pop(tuple(), None)
+
+    for var in newVariations.values():
+        var.roundDeltas()
+    variations[:] = list(newVariations.values())
+
+    return defaultVar.coordinates if defaultVar is not None else []
+
+
+def instantiateGvarGlyph(varfont, glyphname, location, optimize=True):
+    glyf = varfont["glyf"]
+    coordinates, ctrl = glyf.getCoordinatesAndControls(glyphname, varfont)
+    endPts = ctrl.endPts
+
+    gvar = varfont["gvar"]
+    # when exporting to TTX, a glyph with no variations is omitted; thus when loading
+    # a TTFont from TTX, a glyph that's present in glyf table may be missing from gvar.
+    tupleVarStore = gvar.variations.get(glyphname)
+
+    if tupleVarStore:
+        defaultDeltas = instantiateTupleVariationStore(
+            tupleVarStore, location, coordinates, endPts
+        )
+
+        if defaultDeltas:
+            coordinates += _g_l_y_f.GlyphCoordinates(defaultDeltas)
+
+    # setCoordinates also sets the hmtx/vmtx advance widths and sidebearings from
+    # the four phantom points and glyph bounding boxes.
+    # We call it unconditionally even if a glyph has no variations or no deltas are
+    # applied at this location, in case the glyph's xMin and in turn its sidebearing
+    # have changed. E.g. a composite glyph has no deltas for the component's (x, y)
+    # offset nor for the 4 phantom points (e.g. it's monospaced). Thus its entry in
+    # gvar table is empty; however, the composite's base glyph may have deltas
+    # applied, hence the composite's bbox and left/top sidebearings may need updating
+    # in the instanced font.
+    glyf.setCoordinates(glyphname, coordinates, varfont)
+
+    if not tupleVarStore:
+        if glyphname in gvar.variations:
+            del gvar.variations[glyphname]
+        return
+
+    if optimize:
+        isComposite = glyf[glyphname].isComposite()
+        for var in tupleVarStore:
+            var.optimize(coordinates, endPts, isComposite)
+
+
+def instantiateGvar(varfont, location, optimize=True):
+    log.info("Instantiating glyf/gvar tables")
+
+    gvar = varfont["gvar"]
+    glyf = varfont["glyf"]
+    # Get list of glyph names sorted by component depth.
+    # If a composite glyph is processed before its base glyph, the bounds may
+    # be calculated incorrectly because deltas haven't been applied to the
+    # base glyph yet.
+    glyphnames = sorted(
+        glyf.glyphOrder,
+        key=lambda name: (
+            glyf[name].getCompositeMaxpValues(glyf).maxComponentDepth
+            if glyf[name].isComposite()
+            else 0,
+            name,
+        ),
+    )
+    for glyphname in glyphnames:
+        instantiateGvarGlyph(varfont, glyphname, location, optimize=optimize)
+
+    if not gvar.variations:
+        del varfont["gvar"]
+
+
+def setCvarDeltas(cvt, deltas):
+    for i, delta in enumerate(deltas):
+        if delta:
+            cvt[i] += otRound(delta)
+
+
+def instantiateCvar(varfont, location):
+    log.info("Instantiating cvt/cvar tables")
+
+    cvar = varfont["cvar"]
+
+    defaultDeltas = instantiateTupleVariationStore(cvar.variations, location)
+
+    if defaultDeltas:
+        setCvarDeltas(varfont["cvt "], defaultDeltas)
+
+    if not cvar.variations:
+        del varfont["cvar"]
+
+
+def setMvarDeltas(varfont, deltas):
+    mvar = varfont["MVAR"].table
+    records = mvar.ValueRecord
+    for rec in records:
+        mvarTag = rec.ValueTag
+        if mvarTag not in MVAR_ENTRIES:
+            continue
+        tableTag, itemName = MVAR_ENTRIES[mvarTag]
+        delta = deltas[rec.VarIdx]
+        if delta != 0:
+            setattr(
+                varfont[tableTag],
+                itemName,
+                getattr(varfont[tableTag], itemName) + otRound(delta),
+            )
+
+
+def instantiateMVAR(varfont, location):
+    log.info("Instantiating MVAR table")
+
+    mvar = varfont["MVAR"].table
+    fvarAxes = varfont["fvar"].axes
+    varStore = mvar.VarStore
+    defaultDeltas = instantiateItemVariationStore(varStore, fvarAxes, location)
+    setMvarDeltas(varfont, defaultDeltas)
+
+    if varStore.VarRegionList.Region:
+        varIndexMapping = varStore.optimize()
+        for rec in mvar.ValueRecord:
+            rec.VarIdx = varIndexMapping[rec.VarIdx]
+    else:
+        del varfont["MVAR"]
+
+
+def _remapVarIdxMap(table, attrName, varIndexMapping, glyphOrder):
+    oldMapping = getattr(table, attrName).mapping
+    newMapping = [varIndexMapping[oldMapping[glyphName]] for glyphName in glyphOrder]
+    setattr(table, attrName, builder.buildVarIdxMap(newMapping, glyphOrder))
+
+
+# TODO(anthrotype) Add support for HVAR/VVAR in CFF2
+def _instantiateVHVAR(varfont, location, tableFields):
+    tableTag = tableFields.tableTag
+    fvarAxes = varfont["fvar"].axes
+    # Deltas from gvar table have already been applied to the hmtx/vmtx. For full
+    # instances (i.e. all axes pinned), we can simply drop HVAR/VVAR and return
+    if set(location).issuperset(axis.axisTag for axis in fvarAxes):
+        log.info("Dropping %s table", tableTag)
+        del varfont[tableTag]
+        return
+
+    log.info("Instantiating %s table", tableTag)
+    vhvar = varfont[tableTag].table
+    varStore = vhvar.VarStore
+    # since deltas were already applied, the return value here is ignored
+    instantiateItemVariationStore(varStore, fvarAxes, location)
+
+    if varStore.VarRegionList.Region:
+        # Only re-optimize VarStore if the HVAR/VVAR already uses indirect AdvWidthMap
+        # or AdvHeightMap. If a direct, implicit glyphID->VariationIndex mapping is
+        # used for advances, skip re-optimizing and maintain original VariationIndex.
+        if getattr(vhvar, tableFields.advMapping):
+            varIndexMapping = varStore.optimize()
+            glyphOrder = varfont.getGlyphOrder()
+            _remapVarIdxMap(vhvar, tableFields.advMapping, varIndexMapping, glyphOrder)
+            if getattr(vhvar, tableFields.sb1):  # left or top sidebearings
+                _remapVarIdxMap(vhvar, tableFields.sb1, varIndexMapping, glyphOrder)
+            if getattr(vhvar, tableFields.sb2):  # right or bottom sidebearings
+                _remapVarIdxMap(vhvar, tableFields.sb2, varIndexMapping, glyphOrder)
+            if tableTag == "VVAR" and getattr(vhvar, tableFields.vOrigMapping):
+                _remapVarIdxMap(
+                    vhvar, tableFields.vOrigMapping, varIndexMapping, glyphOrder
+                )
+    else:
+        del varfont[tableTag]
+
+
+def instantiateHVAR(varfont, location):
+    return _instantiateVHVAR(varfont, location, varLib.HVAR_FIELDS)
+
+
+def instantiateVVAR(varfont, location):
+    return _instantiateVHVAR(varfont, location, varLib.VVAR_FIELDS)
+
+
+class _TupleVarStoreAdapter(object):
+    def __init__(self, regions, axisOrder, tupleVarData, itemCounts):
+        self.regions = regions
+        self.axisOrder = axisOrder
+        self.tupleVarData = tupleVarData
+        self.itemCounts = itemCounts
+
+    @classmethod
+    def fromItemVarStore(cls, itemVarStore, fvarAxes):
+        axisOrder = [axis.axisTag for axis in fvarAxes]
+        regions = [
+            region.get_support(fvarAxes) for region in itemVarStore.VarRegionList.Region
+        ]
+        tupleVarData = []
+        itemCounts = []
+        for varData in itemVarStore.VarData:
+            variations = []
+            varDataRegions = (regions[i] for i in varData.VarRegionIndex)
+            for axes, coordinates in zip(varDataRegions, zip(*varData.Item)):
+                variations.append(TupleVariation(axes, list(coordinates)))
+            tupleVarData.append(variations)
+            itemCounts.append(varData.ItemCount)
+        return cls(regions, axisOrder, tupleVarData, itemCounts)
+
+    def dropAxes(self, axes):
+        prunedRegions = (
+            frozenset(
+                (axisTag, support)
+                for axisTag, support in region.items()
+                if axisTag not in axes
+            )
+            for region in self.regions
+        )
+        # dedup regions while keeping original order
+        uniqueRegions = collections.OrderedDict.fromkeys(prunedRegions)
+        self.regions = [dict(items) for items in uniqueRegions if items]
+        self.axisOrder = [axisTag for axisTag in self.axisOrder if axisTag not in axes]
+
+    def instantiate(self, location):
+        defaultDeltaArray = []
+        for variations, itemCount in zip(self.tupleVarData, self.itemCounts):
+            defaultDeltas = instantiateTupleVariationStore(variations, location)
+            if not defaultDeltas:
+                defaultDeltas = [0] * itemCount
+            defaultDeltaArray.append(defaultDeltas)
+
+        # remove pinned axes from all the regions
+        self.dropAxes(location.keys())
+
+        return defaultDeltaArray
+
+    def asItemVarStore(self):
+        regionOrder = [frozenset(axes.items()) for axes in self.regions]
+        varDatas = []
+        for variations, itemCount in zip(self.tupleVarData, self.itemCounts):
+            if variations:
+                assert len(variations[0].coordinates) == itemCount
+                varRegionIndices = [
+                    regionOrder.index(frozenset(var.axes.items())) for var in variations
+                ]
+                varDataItems = list(zip(*(var.coordinates for var in variations)))
+                varDatas.append(
+                    builder.buildVarData(varRegionIndices, varDataItems, optimize=False)
+                )
+            else:
+                varDatas.append(
+                    builder.buildVarData([], [[] for _ in range(itemCount)])
+                )
+        regionList = builder.buildVarRegionList(self.regions, self.axisOrder)
+        itemVarStore = builder.buildVarStore(regionList, varDatas)
+        # remove unused regions from VarRegionList
+        itemVarStore.prune_regions()
+        return itemVarStore
+
+
+def instantiateItemVariationStore(itemVarStore, fvarAxes, location):
+    """ Compute deltas at partial location, and update varStore in-place.
+
+    Remove regions in which all axes were instanced, and scale the deltas of
+    the remaining regions where only some of the axes were instanced.
+
+    The number of VarData subtables, and the number of items within each, are
+    not modified, in order to keep the existing VariationIndex valid.
+    One may call VarStore.optimize() method after this to further optimize those.
+
+    Args:
+        varStore: An otTables.VarStore object (Item Variation Store)
+        fvarAxes: list of fvar's Axis objects
+        location: Dict[str, float] mapping axis tags to normalized axis coordinates.
+            May not specify coordinates for all the fvar axes.
+
+    Returns:
+        defaultDeltas: to be added to the default instance, of type dict of floats
+            keyed by VariationIndex compound values: i.e. (outer << 16) + inner.
+    """
+    tupleVarStore = _TupleVarStoreAdapter.fromItemVarStore(itemVarStore, fvarAxes)
+    defaultDeltaArray = tupleVarStore.instantiate(location)
+    newItemVarStore = tupleVarStore.asItemVarStore()
+
+    itemVarStore.VarRegionList = newItemVarStore.VarRegionList
+    assert itemVarStore.VarDataCount == newItemVarStore.VarDataCount
+    itemVarStore.VarData = newItemVarStore.VarData
+
+    defaultDeltas = {
+        ((major << 16) + minor): delta
+        for major, deltas in enumerate(defaultDeltaArray)
+        for minor, delta in enumerate(deltas)
+    }
+    return defaultDeltas
+
+
+def instantiateOTL(varfont, location):
+    # TODO(anthrotype) Support partial instancing of JSTF and BASE tables
+
+    if (
+        "GDEF" not in varfont
+        or varfont["GDEF"].table.Version < 0x00010003
+        or not varfont["GDEF"].table.VarStore
+    ):
+        return
+
+    if "GPOS" in varfont:
+        msg = "Instantiating GDEF and GPOS tables"
+    else:
+        msg = "Instantiating GDEF table"
+    log.info(msg)
+
+    gdef = varfont["GDEF"].table
+    varStore = gdef.VarStore
+    fvarAxes = varfont["fvar"].axes
+
+    defaultDeltas = instantiateItemVariationStore(varStore, fvarAxes, location)
+
+    # When VF are built, big lookups may overflow and be broken into multiple
+    # subtables. MutatorMerger (which inherits from AligningMerger) reattaches
+    # them upon instancing, in case they can now fit a single subtable (if not,
+    # they will be split again upon compilation).
+    # This 'merger' also works as a 'visitor' that traverses the OTL tables and
+    # calls specific methods when instances of a given type are found.
+    # Specifically, it adds default deltas to GPOS Anchors/ValueRecords and GDEF
+    # LigatureCarets, and optionally deletes all VariationIndex tables if the
+    # VarStore is fully instanced.
+    merger = MutatorMerger(
+        varfont, defaultDeltas, deleteVariations=(not varStore.VarRegionList.Region)
+    )
+    merger.mergeTables(varfont, [varfont], ["GDEF", "GPOS"])
+
+    if varStore.VarRegionList.Region:
+        varIndexMapping = varStore.optimize()
+        gdef.remap_device_varidxes(varIndexMapping)
+        if "GPOS" in varfont:
+            varfont["GPOS"].table.remap_device_varidxes(varIndexMapping)
+    else:
+        # Downgrade GDEF.
+        del gdef.VarStore
+        gdef.Version = 0x00010002
+        if gdef.MarkGlyphSetsDef is None:
+            del gdef.MarkGlyphSetsDef
+            gdef.Version = 0x00010000
+
+        if not (
+            gdef.LigCaretList
+            or gdef.MarkAttachClassDef
+            or gdef.GlyphClassDef
+            or gdef.AttachList
+            or (gdef.Version >= 0x00010002 and gdef.MarkGlyphSetsDef)
+        ):
+            del varfont["GDEF"]
+
+
+def instantiateFeatureVariations(varfont, location):
+    for tableTag in ("GPOS", "GSUB"):
+        if tableTag not in varfont or not hasattr(
+            varfont[tableTag].table, "FeatureVariations"
+        ):
+            continue
+        log.info("Instantiating FeatureVariations of %s table", tableTag)
+        _instantiateFeatureVariations(
+            varfont[tableTag].table, varfont["fvar"].axes, location
+        )
+        # remove unreferenced lookups
+        varfont[tableTag].prune_lookups()
+
+
+def _featureVariationRecordIsUnique(rec, seen):
+    conditionSet = []
+    for cond in rec.ConditionSet.ConditionTable:
+        if cond.Format != 1:
+            # can't tell whether this is duplicate, assume is unique
+            return True
+        conditionSet.append(
+            (cond.AxisIndex, cond.FilterRangeMinValue, cond.FilterRangeMaxValue)
+        )
+    # besides the set of conditions, we also include the FeatureTableSubstitution
+    # version to identify unique FeatureVariationRecords, even though only one
+    # version is currently defined. It's theoretically possible that multiple
+    # records with same conditions but different substitution table version be
+    # present in the same font for backward compatibility.
+    recordKey = frozenset([rec.FeatureTableSubstitution.Version] + conditionSet)
+    if recordKey in seen:
+        return False
+    else:
+        seen.add(recordKey)  # side effect
+        return True
+
+
+def _instantiateFeatureVariationRecord(
+    record, recIdx, location, fvarAxes, axisIndexMap
+):
+    shouldKeep = False
+    applies = True
+    newConditions = []
+    for i, condition in enumerate(record.ConditionSet.ConditionTable):
+        if condition.Format == 1:
+            axisIdx = condition.AxisIndex
+            axisTag = fvarAxes[axisIdx].axisTag
+            if axisTag in location:
+                minValue = condition.FilterRangeMinValue
+                maxValue = condition.FilterRangeMaxValue
+                v = location[axisTag]
+                if not (minValue <= v <= maxValue):
+                    # condition not met so remove entire record
+                    applies = False
+                    newConditions = None
+                    break
+            else:
+                # axis not pinned, keep condition with remapped axis index
+                applies = False
+                condition.AxisIndex = axisIndexMap[axisTag]
+                newConditions.append(condition)
+        else:
+            log.warning(
+                "Condition table {0} of FeatureVariationRecord {1} has "
+                "unsupported format ({2}); ignored".format(i, recIdx, condition.Format)
+            )
+            applies = False
+            newConditions.append(condition)
+
+    if newConditions:
+        record.ConditionSet.ConditionTable = newConditions
+        shouldKeep = True
+
+    return applies, shouldKeep
+
+
+def _instantiateFeatureVariations(table, fvarAxes, location):
+    pinnedAxes = set(location.keys())
+    axisOrder = [axis.axisTag for axis in fvarAxes if axis.axisTag not in pinnedAxes]
+    axisIndexMap = {axisTag: axisOrder.index(axisTag) for axisTag in axisOrder}
+
+    featureVariationApplied = False
+    uniqueRecords = set()
+    newRecords = []
+
+    for i, record in enumerate(table.FeatureVariations.FeatureVariationRecord):
+        applies, shouldKeep = _instantiateFeatureVariationRecord(
+            record, i, location, fvarAxes, axisIndexMap
+        )
+        if shouldKeep:
+            if _featureVariationRecordIsUnique(record, uniqueRecords):
+                newRecords.append(record)
+
+        if applies and not featureVariationApplied:
+            assert record.FeatureTableSubstitution.Version == 0x00010000
+            for rec in record.FeatureTableSubstitution.SubstitutionRecord:
+                table.FeatureList.FeatureRecord[rec.FeatureIndex].Feature = rec.Feature
+            # Set variations only once
+            featureVariationApplied = True
+
+    if newRecords:
+        table.FeatureVariations.FeatureVariationRecord = newRecords
+        table.FeatureVariations.FeatureVariationCount = len(newRecords)
+    else:
+        del table.FeatureVariations
+
+
+def instantiateAvar(varfont, location):
+    segments = varfont["avar"].segments
+
+    # drop table if we instantiate all the axes
+    if set(location).issuperset(segments):
+        log.info("Dropping avar table")
+        del varfont["avar"]
+        return
+
+    log.info("Instantiating avar table")
+    for axis in location:
+        if axis in segments:
+            del segments[axis]
+
+
+def instantiateFvar(varfont, location):
+    # 'location' dict must contain user-space (non-normalized) coordinates
+
+    fvar = varfont["fvar"]
+
+    # drop table if we instantiate all the axes
+    if set(location).issuperset(axis.axisTag for axis in fvar.axes):
+        log.info("Dropping fvar table")
+        del varfont["fvar"]
+        return
+
+    log.info("Instantiating fvar table")
+
+    fvar.axes = [axis for axis in fvar.axes if axis.axisTag not in location]
+
+    # only keep NamedInstances whose coordinates == pinned axis location
+    instances = []
+    for instance in fvar.instances:
+        if any(instance.coordinates[axis] != value for axis, value in location.items()):
+            continue
+        for axis in location:
+            del instance.coordinates[axis]
+        instances.append(instance)
+    fvar.instances = instances
+
+
+def instantiateSTAT(varfont, location):
+    pinnedAxes = set(location.keys())
+
+    stat = varfont["STAT"].table
+    if not stat.DesignAxisRecord:
+        return  # skip empty STAT table
+
+    designAxes = stat.DesignAxisRecord.Axis
+    pinnedAxisIndices = {
+        i for i, axis in enumerate(designAxes) if axis.AxisTag in pinnedAxes
+    }
+
+    if len(pinnedAxisIndices) == len(designAxes):
+        log.info("Dropping STAT table")
+        del varfont["STAT"]
+        return
+
+    log.info("Instantiating STAT table")
+
+    # only keep DesignAxis that were not instanced, and build a mapping from old
+    # to new axis indices
+    newDesignAxes = []
+    axisIndexMap = {}
+    for i, axis in enumerate(designAxes):
+        if i not in pinnedAxisIndices:
+            axisIndexMap[i] = len(newDesignAxes)
+            newDesignAxes.append(axis)
+
+    if stat.AxisValueArray and stat.AxisValueArray.AxisValue:
+        # drop all AxisValue tables that reference any of the pinned axes
+        newAxisValueTables = []
+        for axisValueTable in stat.AxisValueArray.AxisValue:
+            if axisValueTable.Format in (1, 2, 3):
+                if axisValueTable.AxisIndex in pinnedAxisIndices:
+                    continue
+                axisValueTable.AxisIndex = axisIndexMap[axisValueTable.AxisIndex]
+                newAxisValueTables.append(axisValueTable)
+            elif axisValueTable.Format == 4:
+                if any(
+                    rec.AxisIndex in pinnedAxisIndices
+                    for rec in axisValueTable.AxisValueRecord
+                ):
+                    continue
+                for rec in axisValueTable.AxisValueRecord:
+                    rec.AxisIndex = axisIndexMap[rec.AxisIndex]
+                newAxisValueTables.append(axisValueTable)
+            else:
+                raise NotImplementedError(axisValueTable.Format)
+        stat.AxisValueArray.AxisValue = newAxisValueTables
+        stat.AxisValueCount = len(stat.AxisValueArray.AxisValue)
+
+    stat.DesignAxisRecord.Axis[:] = newDesignAxes
+    stat.DesignAxisCount = len(stat.DesignAxisRecord.Axis)
+
+
+def getVariationNameIDs(varfont):
+    used = []
+    if "fvar" in varfont:
+        fvar = varfont["fvar"]
+        for axis in fvar.axes:
+            used.append(axis.axisNameID)
+        for instance in fvar.instances:
+            used.append(instance.subfamilyNameID)
+            if instance.postscriptNameID != 0xFFFF:
+                used.append(instance.postscriptNameID)
+    if "STAT" in varfont:
+        stat = varfont["STAT"].table
+        for axis in stat.DesignAxisRecord.Axis if stat.DesignAxisRecord else ():
+            used.append(axis.AxisNameID)
+        for value in stat.AxisValueArray.AxisValue if stat.AxisValueArray else ():
+            used.append(value.ValueNameID)
+    # nameIDs <= 255 are reserved by OT spec so we don't touch them
+    return {nameID for nameID in used if nameID > 255}
+
+
+@contextmanager
+def pruningUnusedNames(varfont):
+    origNameIDs = getVariationNameIDs(varfont)
+
+    yield
+
+    log.info("Pruning name table")
+    exclude = origNameIDs - getVariationNameIDs(varfont)
+    varfont["name"].names[:] = [
+        record for record in varfont["name"].names if record.nameID not in exclude
+    ]
+    if "ltag" in varfont:
+        # Drop the whole 'ltag' table if all the language-dependent Unicode name
+        # records that reference it have been dropped.
+        # TODO: Only prune unused ltag tags, renumerating langIDs accordingly.
+        # Note ltag can also be used by feat or morx tables, so check those too.
+        if not any(
+            record
+            for record in varfont["name"].names
+            if record.platformID == 0 and record.langID != 0xFFFF
+        ):
+            del varfont["ltag"]
+
+
+def setMacOverlapFlags(glyfTable):
+    flagOverlapCompound = _g_l_y_f.OVERLAP_COMPOUND
+    flagOverlapSimple = _g_l_y_f.flagOverlapSimple
+    for glyphName in glyfTable.keys():
+        glyph = glyfTable[glyphName]
+        # Set OVERLAP_COMPOUND bit for compound glyphs
+        if glyph.isComposite():
+            glyph.components[0].flags |= flagOverlapCompound
+        # Set OVERLAP_SIMPLE bit for simple glyphs
+        elif glyph.numberOfContours > 0:
+            glyph.flags[0] |= flagOverlapSimple
+
+
+def normalize(value, triple, avarMapping):
+    value = normalizeValue(value, triple)
+    if avarMapping:
+        value = piecewiseLinearMap(value, avarMapping)
+    # Quantize to F2Dot14, to avoid surprise interpolations.
+    return floatToFixedToFloat(value, 14)
+
+
+def normalizeAxisLimits(varfont, axisLimits):
+    fvar = varfont["fvar"]
+    badLimits = set(axisLimits.keys()).difference(a.axisTag for a in fvar.axes)
+    if badLimits:
+        raise ValueError("Cannot limit: {} not present in fvar".format(badLimits))
+
+    axes = {
+        a.axisTag: (a.minValue, a.defaultValue, a.maxValue)
+        for a in fvar.axes
+        if a.axisTag in axisLimits
+    }
+
+    avarSegments = {}
+    if "avar" in varfont:
+        avarSegments = varfont["avar"].segments
+    normalizedLimits = {}
+    for axis_tag, triple in axes.items():
+        avarMapping = avarSegments.get(axis_tag, None)
+        value = axisLimits[axis_tag]
+        if isinstance(value, tuple):
+            normalizedLimits[axis_tag] = tuple(
+                normalize(v, triple, avarMapping) for v in axisLimits[axis_tag]
+            )
+        else:
+            normalizedLimits[axis_tag] = normalize(value, triple, avarMapping)
+    return normalizedLimits
+
+
+def sanityCheckVariableTables(varfont):
+    if "fvar" not in varfont:
+        raise ValueError("Missing required table fvar")
+    if "gvar" in varfont:
+        if "glyf" not in varfont:
+            raise ValueError("Can't have gvar without glyf")
+    # TODO(anthrotype) Remove once we do support partial instancing CFF2
+    if "CFF2" in varfont:
+        raise NotImplementedError("Instancing CFF2 variable fonts is not supported yet")
+
+
+def populateAxisDefaults(varfont, axisLimits):
+    if any(value is None for value in axisLimits.values()):
+        fvar = varfont["fvar"]
+        defaultValues = {a.axisTag: a.defaultValue for a in fvar.axes}
+        return {
+            axisTag: defaultValues[axisTag] if value is None else value
+            for axisTag, value in axisLimits.items()
+        }
+    return axisLimits
+
+
+def instantiateVariableFont(
+    varfont, axisLimits, inplace=False, optimize=True, overlap=True
+):
+    """ Instantiate variable font, either fully or partially.
+
+    Depending on whether the `axisLimits` dictionary references all or some of the
+    input varfont's axes, the output font will either be a full instance (static
+    font) or a variable font with possibly less variation data.
+
+    Args:
+        varfont: a TTFont instance, which must contain at least an 'fvar' table.
+            Note that variable fonts with 'CFF2' table are not supported yet.
+        axisLimits: a dict keyed by axis tags (str) containing the coordinates (float)
+            along one or more axes where the desired instance will be located.
+            If the value is `None`, the default coordinate as per 'fvar' table for
+            that axis is used.
+            The limit values can also be (min, max) tuples for restricting an
+            axis's variation range, but this is not implemented yet.
+        inplace (bool): whether to modify input TTFont object in-place instead of
+            returning a distinct object.
+        optimize (bool): if False, do not perform IUP-delta optimization on the
+            remaining 'gvar' table's deltas. Possibly faster, and might work around
+            rendering issues in some buggy environments, at the cost of a slightly
+            larger file size.
+        overlap (bool): variable fonts usually contain overlapping contours, and some
+            font rendering engines on Apple platforms require that the `OVERLAP_SIMPLE`
+            and `OVERLAP_COMPOUND` flags in the 'glyf' table be set to force rendering
+            using a non-zero fill rule. Thus we always set these flags on all glyphs
+            to maximise cross-compatibility of the generated instance. You can disable
+            this by setting `overalap` to False.
+    """
+    sanityCheckVariableTables(varfont)
+
+    if not inplace:
+        varfont = deepcopy(varfont)
+
+    axisLimits = populateAxisDefaults(varfont, axisLimits)
+
+    normalizedLimits = normalizeAxisLimits(varfont, axisLimits)
+
+    log.info("Normalized limits: %s", normalizedLimits)
+
+    # TODO Remove this check once ranges are supported
+    if any(isinstance(v, tuple) for v in axisLimits.values()):
+        raise NotImplementedError("Axes range limits are not supported yet")
+
+    if "gvar" in varfont:
+        instantiateGvar(varfont, normalizedLimits, optimize=optimize)
+
+    if "cvar" in varfont:
+        instantiateCvar(varfont, normalizedLimits)
+
+    if "MVAR" in varfont:
+        instantiateMVAR(varfont, normalizedLimits)
+
+    if "HVAR" in varfont:
+        instantiateHVAR(varfont, normalizedLimits)
+
+    if "VVAR" in varfont:
+        instantiateVVAR(varfont, normalizedLimits)
+
+    instantiateOTL(varfont, normalizedLimits)
+
+    instantiateFeatureVariations(varfont, normalizedLimits)
+
+    if "avar" in varfont:
+        instantiateAvar(varfont, normalizedLimits)
+
+    with pruningUnusedNames(varfont):
+        if "STAT" in varfont:
+            instantiateSTAT(varfont, axisLimits)
+
+        instantiateFvar(varfont, axisLimits)
+
+    if "fvar" not in varfont:
+        if "glyf" in varfont and overlap:
+            setMacOverlapFlags(varfont["glyf"])
+
+    varLib.set_default_weight_width_slant(
+        varfont,
+        location={
+            axisTag: limit
+            for axisTag, limit in axisLimits.items()
+            if not isinstance(limit, tuple)
+        },
+    )
+
+    return varfont
+
+
+def parseLimits(limits):
+    result = {}
+    for limitString in limits:
+        match = re.match(r"^(\w{1,4})=(?:(drop)|(?:([^:]+)(?:[:](.+))?))$", limitString)
+        if not match:
+            raise ValueError("invalid location format: %r" % limitString)
+        tag = match.group(1).ljust(4)
+        if match.group(2):  # 'drop'
+            lbound = None
+        else:
+            lbound = float(match.group(3))
+        ubound = lbound
+        if match.group(4):
+            ubound = float(match.group(4))
+        if lbound != ubound:
+            result[tag] = (lbound, ubound)
+        else:
+            result[tag] = lbound
+    return result
+
+
+def parseArgs(args):
+    """Parse argv.
+
+    Returns:
+        3-tuple (infile, axisLimits, options)
+        axisLimits is either a Dict[str, Optional[float]], for pinning variation axes
+        to specific coordinates along those axes (with `None` as a placeholder for an
+        axis' default value); or a Dict[str, Tuple(float, float)], meaning limit this
+        axis to min/max range.
+        Axes locations are in user-space coordinates, as defined in the "fvar" table.
+    """
+    from fontTools import configLogger
+    import argparse
+
+    parser = argparse.ArgumentParser(
+        "fonttools varLib.instancer",
+        description="Partially instantiate a variable font",
+    )
+    parser.add_argument("input", metavar="INPUT.ttf", help="Input variable TTF file.")
+    parser.add_argument(
+        "locargs",
+        metavar="AXIS=LOC",
+        nargs="*",
+        help="List of space separated locations. A location consist in "
+        "the tag of a variation axis, followed by '=' and one of number, "
+        "number:number or the literal string 'drop'. "
+        "E.g.: wdth=100 or wght=75.0:125.0 or wght=drop",
+    )
+    parser.add_argument(
+        "-o",
+        "--output",
+        metavar="OUTPUT.ttf",
+        default=None,
+        help="Output instance TTF file (default: INPUT-instance.ttf).",
+    )
+    parser.add_argument(
+        "--no-optimize",
+        dest="optimize",
+        action="store_false",
+        help="Don't perform IUP optimization on the remaining gvar TupleVariations",
+    )
+    parser.add_argument(
+        "--no-overlap-flag",
+        dest="overlap",
+        action="store_false",
+        help="Don't set OVERLAP_SIMPLE/OVERLAP_COMPOUND glyf flags (only applicable "
+        "when generating a full instance)",
+    )
+    loggingGroup = parser.add_mutually_exclusive_group(required=False)
+    loggingGroup.add_argument(
+        "-v", "--verbose", action="store_true", help="Run more verbosely."
+    )
+    loggingGroup.add_argument(
+        "-q", "--quiet", action="store_true", help="Turn verbosity off."
+    )
+    options = parser.parse_args(args)
+
+    infile = options.input
+    if not os.path.isfile(infile):
+        parser.error("No such file '{}'".format(infile))
+
+    configLogger(
+        level=("DEBUG" if options.verbose else "ERROR" if options.quiet else "INFO")
+    )
+
+    try:
+        axisLimits = parseLimits(options.locargs)
+    except ValueError as e:
+        parser.error(e)
+
+    if len(axisLimits) != len(options.locargs):
+        parser.error("Specified multiple limits for the same axis")
+
+    return (infile, axisLimits, options)
+
+
+def main(args=None):
+    infile, axisLimits, options = parseArgs(args)
+    log.info("Restricting axes: %s", axisLimits)
+
+    log.info("Loading variable font")
+    varfont = TTFont(infile)
+
+    isFullInstance = {
+        axisTag for axisTag, limit in axisLimits.items() if not isinstance(limit, tuple)
+    }.issuperset(axis.axisTag for axis in varfont["fvar"].axes)
+
+    instantiateVariableFont(
+        varfont,
+        axisLimits,
+        inplace=True,
+        optimize=options.optimize,
+        overlap=options.overlap,
+    )
+
+    outfile = (
+        os.path.splitext(infile)[0]
+        + "-{}.ttf".format("instance" if isFullInstance else "partial")
+        if not options.output
+        else options.output
+    )
+
+    log.info(
+        "Saving %s font %s",
+        "instance" if isFullInstance else "partial variable",
+        outfile,
+    )
+    varfont.save(outfile)
+
+
+if __name__ == "__main__":
+    import sys
+
+    sys.exit(main())
diff --git a/Lib/fontTools/varLib/instancer/__init__.py b/Lib/fontTools/varLib/instancer/__init__.py
deleted file mode 100644
index 9bd30f1..0000000
--- a/Lib/fontTools/varLib/instancer/__init__.py
+++ /dev/null
@@ -1,1422 +0,0 @@
-""" Partially instantiate a variable font.
-
-The module exports an `instantiateVariableFont` function and CLI that allow to
-create full instances (i.e. static fonts) from variable fonts, as well as "partial"
-variable fonts that only contain a subset of the original variation space.
-
-For example, if you wish to pin the width axis to a given location while also
-restricting the weight axis to 400..700 range, you can do:
-
-$ fonttools varLib.instancer ./NotoSans-VF.ttf wdth=85 wght=400:700
-
-See `fonttools varLib.instancer --help` for more info on the CLI options.
-
-The module's entry point is the `instantiateVariableFont` function, which takes
-a TTFont object and a dict specifying either axis coodinates or (min, max) ranges,
-and returns a new TTFont representing either a partial VF, or full instance if all
-the VF axes were given an explicit coordinate.
-
-E.g. here's how to pin the wght axis at a given location in a wght+wdth variable
-font, keeping only the deltas associated with the wdth axis:
-
-| >>> from fontTools import ttLib
-| >>> from fontTools.varLib import instancer
-| >>> varfont = ttLib.TTFont("path/to/MyVariableFont.ttf")
-| >>> [a.axisTag for a in varfont["fvar"].axes]  # the varfont's current axes
-| ['wght', 'wdth']
-| >>> partial = instancer.instantiateVariableFont(varfont, {"wght": 300})
-| >>> [a.axisTag for a in partial["fvar"].axes]  # axes left after pinning 'wght'
-| ['wdth']
-
-If the input location specifies all the axes, the resulting instance is no longer
-'variable' (same as using fontools varLib.mutator):
-
-| >>> instance = instancer.instantiateVariableFont(
-| ...     varfont, {"wght": 700, "wdth": 67.5}
-| ... )
-| >>> "fvar" not in instance
-| True
-
-If one just want to drop an axis at the default location, without knowing in
-advance what the default value for that axis is, one can pass a `None` value:
-
-| >>> instance = instancer.instantiateVariableFont(varfont, {"wght": None})
-| >>> len(varfont["fvar"].axes)
-| 1
-
-From the console script, this is equivalent to passing `wght=drop` as input.
-
-This module is similar to fontTools.varLib.mutator, which it's intended to supersede.
-Note that, unlike varLib.mutator, when an axis is not mentioned in the input
-location, the varLib.instancer will keep the axis and the corresponding deltas,
-whereas mutator implicitly drops the axis at its default coordinate.
-
-The module currently supports only the first three "levels" of partial instancing,
-with the rest planned to be implemented in the future, namely:
-L1) dropping one or more axes while leaving the default tables unmodified;
-L2) dropping one or more axes while pinning them at non-default locations;
-L3) restricting the range of variation of one or more axes, by setting either
-    a new minimum or maximum, potentially -- though not necessarily -- dropping
-    entire regions of variations that fall completely outside this new range.
-L4) moving the default location of an axis.
-
-Currently only TrueType-flavored variable fonts (i.e. containing 'glyf' table)
-are supported, but support for CFF2 variable fonts will be added soon.
-
-The discussion and implementation of these features are tracked at
-https://github.com/fonttools/fonttools/issues/1537
-"""
-from fontTools.misc.fixedTools import (
-    floatToFixedToFloat,
-    strToFixedToFloat,
-    otRound,
-    MAX_F2DOT14,
-)
-from fontTools.varLib.models import supportScalar, normalizeValue, piecewiseLinearMap
-from fontTools.ttLib import TTFont
-from fontTools.ttLib.tables.TupleVariation import TupleVariation
-from fontTools.ttLib.tables import _g_l_y_f
-from fontTools import varLib
-
-# we import the `subset` module because we use the `prune_lookups` method on the GSUB
-# table class, and that method is only defined dynamically upon importing `subset`
-from fontTools import subset  # noqa: F401
-from fontTools.varLib import builder
-from fontTools.varLib.mvar import MVAR_ENTRIES
-from fontTools.varLib.merger import MutatorMerger
-from fontTools.varLib.instancer import names
-from contextlib import contextmanager
-import collections
-from copy import deepcopy
-from enum import IntEnum
-import logging
-from itertools import islice
-import os
-import re
-
-
-log = logging.getLogger("fontTools.varLib.instancer")
-
-
-class AxisRange(collections.namedtuple("AxisRange", "minimum maximum")):
-    def __new__(cls, *args, **kwargs):
-        self = super().__new__(cls, *args, **kwargs)
-        if self.minimum > self.maximum:
-            raise ValueError(
-                f"Range minimum ({self.minimum:g}) must be <= maximum ({self.maximum:g})"
-            )
-        return self
-
-    def __repr__(self):
-        return f"{type(self).__name__}({self.minimum:g}, {self.maximum:g})"
-
-
-class NormalizedAxisRange(AxisRange):
-    def __new__(cls, *args, **kwargs):
-        self = super().__new__(cls, *args, **kwargs)
-        if self.minimum < -1.0 or self.maximum > 1.0:
-            raise ValueError("Axis range values must be normalized to -1..+1 range")
-        if self.minimum > 0:
-            raise ValueError(f"Expected axis range minimum <= 0; got {self.minimum}")
-        if self.maximum < 0:
-            raise ValueError(f"Expected axis range maximum >= 0; got {self.maximum}")
-        return self
-
-
-class OverlapMode(IntEnum):
-    KEEP_AND_DONT_SET_FLAGS = 0
-    KEEP_AND_SET_FLAGS = 1
-    REMOVE = 2
-
-
-def instantiateTupleVariationStore(
-    variations, axisLimits, origCoords=None, endPts=None
-):
-    """Instantiate TupleVariation list at the given location, or limit axes' min/max.
-
-    The 'variations' list of TupleVariation objects is modified in-place.
-    The 'axisLimits' (dict) maps axis tags (str) to either a single coordinate along the
-    axis (float), or to minimum/maximum coordinates (NormalizedAxisRange).
-
-    A 'full' instance (i.e. static font) is produced when all the axes are pinned to
-    single coordinates; a 'partial' instance (i.e. a less variable font) is produced
-    when some of the axes are omitted, or restricted with a new range.
-
-    Tuples that do not participate are kept as they are. Those that have 0 influence
-    at the given location are removed from the variation store.
-    Those that are fully instantiated (i.e. all their axes are being pinned) are also
-    removed from the variation store, their scaled deltas accummulated and returned, so
-    that they can be added by the caller to the default instance's coordinates.
-    Tuples that are only partially instantiated (i.e. not all the axes that they
-    participate in are being pinned) are kept in the store, and their deltas multiplied
-    by the scalar support of the axes to be pinned at the desired location.
-
-    Args:
-        variations: List[TupleVariation] from either 'gvar' or 'cvar'.
-        axisLimits: Dict[str, Union[float, NormalizedAxisRange]]: axes' coordinates for
-            the full or partial instance, or ranges for restricting an axis' min/max.
-        origCoords: GlyphCoordinates: default instance's coordinates for computing 'gvar'
-            inferred points (cf. table__g_l_y_f.getCoordinatesAndControls).
-        endPts: List[int]: indices of contour end points, for inferring 'gvar' deltas.
-
-    Returns:
-        List[float]: the overall delta adjustment after applicable deltas were summed.
-    """
-    pinnedLocation, axisRanges = splitAxisLocationAndRanges(
-        axisLimits, rangeType=NormalizedAxisRange
-    )
-
-    newVariations = variations
-
-    if pinnedLocation:
-        newVariations = pinTupleVariationAxes(variations, pinnedLocation)
-
-    if axisRanges:
-        newVariations = limitTupleVariationAxisRanges(newVariations, axisRanges)
-
-    mergedVariations = collections.OrderedDict()
-    for var in newVariations:
-        # compute inferred deltas only for gvar ('origCoords' is None for cvar)
-        if origCoords is not None:
-            var.calcInferredDeltas(origCoords, endPts)
-
-        # merge TupleVariations with overlapping "tents"
-        axes = frozenset(var.axes.items())
-        if axes in mergedVariations:
-            mergedVariations[axes] += var
-        else:
-            mergedVariations[axes] = var
-
-    # drop TupleVariation if all axes have been pinned (var.axes.items() is empty);
-    # its deltas will be added to the default instance's coordinates
-    defaultVar = mergedVariations.pop(frozenset(), None)
-
-    for var in mergedVariations.values():
-        var.roundDeltas()
-    variations[:] = list(mergedVariations.values())
-
-    return defaultVar.coordinates if defaultVar is not None else []
-
-
-def pinTupleVariationAxes(variations, location):
-    newVariations = []
-    for var in variations:
-        # Compute the scalar support of the axes to be pinned at the desired location,
-        # excluding any axes that we are not pinning.
-        # If a TupleVariation doesn't mention an axis, it implies that the axis peak
-        # is 0 (i.e. the axis does not participate).
-        support = {axis: var.axes.pop(axis, (-1, 0, +1)) for axis in location}
-        scalar = supportScalar(location, support)
-        if scalar == 0.0:
-            # no influence, drop the TupleVariation
-            continue
-
-        var.scaleDeltas(scalar)
-        newVariations.append(var)
-    return newVariations
-
-
-def limitTupleVariationAxisRanges(variations, axisRanges):
-    for axisTag, axisRange in sorted(axisRanges.items()):
-        newVariations = []
-        for var in variations:
-            newVariations.extend(limitTupleVariationAxisRange(var, axisTag, axisRange))
-        variations = newVariations
-    return variations
-
-
-def _negate(*values):
-    yield from (-1 * v for v in values)
-
-
-def limitTupleVariationAxisRange(var, axisTag, axisRange):
-    if not isinstance(axisRange, NormalizedAxisRange):
-        axisRange = NormalizedAxisRange(*axisRange)
-
-    # skip when current axis is missing (i.e. doesn't participate), or when the
-    # 'tent' isn't fully on either the negative or positive side
-    lower, peak, upper = var.axes.get(axisTag, (-1, 0, 1))
-    if peak == 0 or lower > peak or peak > upper or (lower < 0 and upper > 0):
-        return [var]
-
-    negative = lower < 0
-    if negative:
-        if axisRange.minimum == -1.0:
-            return [var]
-        elif axisRange.minimum == 0.0:
-            return []
-    else:
-        if axisRange.maximum == 1.0:
-            return [var]
-        elif axisRange.maximum == 0.0:
-            return []
-
-    limit = axisRange.minimum if negative else axisRange.maximum
-
-    # Rebase axis bounds onto the new limit, which then becomes the new -1.0 or +1.0.
-    # The results are always positive, because both dividend and divisor are either
-    # all positive or all negative.
-    newLower = lower / limit
-    newPeak = peak / limit
-    newUpper = upper / limit
-    # for negative TupleVariation, swap lower and upper to simplify procedure
-    if negative:
-        newLower, newUpper = newUpper, newLower
-
-    # special case when innermost bound == peak == limit
-    if newLower == newPeak == 1.0:
-        var.axes[axisTag] = (-1.0, -1.0, -1.0) if negative else (1.0, 1.0, 1.0)
-        return [var]
-
-    # case 1: the whole deltaset falls outside the new limit; we can drop it
-    elif newLower >= 1.0:
-        return []
-
-    # case 2: only the peak and outermost bound fall outside the new limit;
-    # we keep the deltaset, update peak and outermost bound and and scale deltas
-    # by the scalar value for the restricted axis at the new limit.
-    elif newPeak >= 1.0:
-        scalar = supportScalar({axisTag: limit}, {axisTag: (lower, peak, upper)})
-        var.scaleDeltas(scalar)
-        newPeak = 1.0
-        newUpper = 1.0
-        if negative:
-            newLower, newPeak, newUpper = _negate(newUpper, newPeak, newLower)
-        var.axes[axisTag] = (newLower, newPeak, newUpper)
-        return [var]
-
-    # case 3: peak falls inside but outermost limit still fits within F2Dot14 bounds;
-    # we keep deltas as is and only scale the axes bounds. Deltas beyond -1.0
-    # or +1.0 will never be applied as implementations must clamp to that range.
-    elif newUpper <= 2.0:
-        if negative:
-            newLower, newPeak, newUpper = _negate(newUpper, newPeak, newLower)
-        elif MAX_F2DOT14 < newUpper <= 2.0:
-            # we clamp +2.0 to the max F2Dot14 (~1.99994) for convenience
-            newUpper = MAX_F2DOT14
-        var.axes[axisTag] = (newLower, newPeak, newUpper)
-        return [var]
-
-    # case 4: new limit doesn't fit; we need to chop the deltaset into two 'tents',
-    # because the shape of a triangle with part of one side cut off cannot be
-    # represented as a triangle itself. It can be represented as sum of two triangles.
-    # NOTE: This increases the file size!
-    else:
-        # duplicate the tent, then adjust lower/peak/upper so that the outermost limit
-        # of the original tent is +/-2.0, whereas the new tent's starts as the old
-        # one peaks and maxes out at +/-1.0.
-        newVar = TupleVariation(var.axes, var.coordinates)
-        if negative:
-            var.axes[axisTag] = (-2.0, -1 * newPeak, -1 * newLower)
-            newVar.axes[axisTag] = (-1.0, -1.0, -1 * newPeak)
-        else:
-            var.axes[axisTag] = (newLower, newPeak, MAX_F2DOT14)
-            newVar.axes[axisTag] = (newPeak, 1.0, 1.0)
-        # the new tent's deltas are scaled by the difference between the scalar value
-        # for the old tent at the desired limit...
-        scalar1 = supportScalar({axisTag: limit}, {axisTag: (lower, peak, upper)})
-        # ... and the scalar value for the clamped tent (with outer limit +/-2.0),
-        # which can be simplified like this:
-        scalar2 = 1 / (2 - newPeak)
-        newVar.scaleDeltas(scalar1 - scalar2)
-
-        return [var, newVar]
-
-
-def instantiateGvarGlyph(varfont, glyphname, axisLimits, optimize=True):
-    glyf = varfont["glyf"]
-    coordinates, ctrl = glyf.getCoordinatesAndControls(glyphname, varfont)
-    endPts = ctrl.endPts
-
-    gvar = varfont["gvar"]
-    # when exporting to TTX, a glyph with no variations is omitted; thus when loading
-    # a TTFont from TTX, a glyph that's present in glyf table may be missing from gvar.
-    tupleVarStore = gvar.variations.get(glyphname)
-
-    if tupleVarStore:
-        defaultDeltas = instantiateTupleVariationStore(
-            tupleVarStore, axisLimits, coordinates, endPts
-        )
-
-        if defaultDeltas:
-            coordinates += _g_l_y_f.GlyphCoordinates(defaultDeltas)
-
-    # setCoordinates also sets the hmtx/vmtx advance widths and sidebearings from
-    # the four phantom points and glyph bounding boxes.
-    # We call it unconditionally even if a glyph has no variations or no deltas are
-    # applied at this location, in case the glyph's xMin and in turn its sidebearing
-    # have changed. E.g. a composite glyph has no deltas for the component's (x, y)
-    # offset nor for the 4 phantom points (e.g. it's monospaced). Thus its entry in
-    # gvar table is empty; however, the composite's base glyph may have deltas
-    # applied, hence the composite's bbox and left/top sidebearings may need updating
-    # in the instanced font.
-    glyf.setCoordinates(glyphname, coordinates, varfont)
-
-    if not tupleVarStore:
-        if glyphname in gvar.variations:
-            del gvar.variations[glyphname]
-        return
-
-    if optimize:
-        isComposite = glyf[glyphname].isComposite()
-        for var in tupleVarStore:
-            var.optimize(coordinates, endPts, isComposite)
-
-
-def instantiateGvar(varfont, axisLimits, optimize=True):
-    log.info("Instantiating glyf/gvar tables")
-
-    gvar = varfont["gvar"]
-    glyf = varfont["glyf"]
-    # Get list of glyph names sorted by component depth.
-    # If a composite glyph is processed before its base glyph, the bounds may
-    # be calculated incorrectly because deltas haven't been applied to the
-    # base glyph yet.
-    glyphnames = sorted(
-        glyf.glyphOrder,
-        key=lambda name: (
-            glyf[name].getCompositeMaxpValues(glyf).maxComponentDepth
-            if glyf[name].isComposite()
-            else 0,
-            name,
-        ),
-    )
-    for glyphname in glyphnames:
-        instantiateGvarGlyph(varfont, glyphname, axisLimits, optimize=optimize)
-
-    if not gvar.variations:
-        del varfont["gvar"]
-
-
-def setCvarDeltas(cvt, deltas):
-    for i, delta in enumerate(deltas):
-        if delta:
-            cvt[i] += otRound(delta)
-
-
-def instantiateCvar(varfont, axisLimits):
-    log.info("Instantiating cvt/cvar tables")
-
-    cvar = varfont["cvar"]
-
-    defaultDeltas = instantiateTupleVariationStore(cvar.variations, axisLimits)
-
-    if defaultDeltas:
-        setCvarDeltas(varfont["cvt "], defaultDeltas)
-
-    if not cvar.variations:
-        del varfont["cvar"]
-
-
-def setMvarDeltas(varfont, deltas):
-    mvar = varfont["MVAR"].table
-    records = mvar.ValueRecord
-    for rec in records:
-        mvarTag = rec.ValueTag
-        if mvarTag not in MVAR_ENTRIES:
-            continue
-        tableTag, itemName = MVAR_ENTRIES[mvarTag]
-        delta = deltas[rec.VarIdx]
-        if delta != 0:
-            setattr(
-                varfont[tableTag],
-                itemName,
-                getattr(varfont[tableTag], itemName) + otRound(delta),
-            )
-
-
-def instantiateMVAR(varfont, axisLimits):
-    log.info("Instantiating MVAR table")
-
-    mvar = varfont["MVAR"].table
-    fvarAxes = varfont["fvar"].axes
-    varStore = mvar.VarStore
-    defaultDeltas = instantiateItemVariationStore(varStore, fvarAxes, axisLimits)
-    setMvarDeltas(varfont, defaultDeltas)
-
-    if varStore.VarRegionList.Region:
-        varIndexMapping = varStore.optimize()
-        for rec in mvar.ValueRecord:
-            rec.VarIdx = varIndexMapping[rec.VarIdx]
-    else:
-        del varfont["MVAR"]
-
-
-def _remapVarIdxMap(table, attrName, varIndexMapping, glyphOrder):
-    oldMapping = getattr(table, attrName).mapping
-    newMapping = [varIndexMapping[oldMapping[glyphName]] for glyphName in glyphOrder]
-    setattr(table, attrName, builder.buildVarIdxMap(newMapping, glyphOrder))
-
-
-# TODO(anthrotype) Add support for HVAR/VVAR in CFF2
-def _instantiateVHVAR(varfont, axisLimits, tableFields):
-    tableTag = tableFields.tableTag
-    fvarAxes = varfont["fvar"].axes
-    # Deltas from gvar table have already been applied to the hmtx/vmtx. For full
-    # instances (i.e. all axes pinned), we can simply drop HVAR/VVAR and return
-    if set(
-        axisTag for axisTag, value in axisLimits.items() if not isinstance(value, tuple)
-    ).issuperset(axis.axisTag for axis in fvarAxes):
-        log.info("Dropping %s table", tableTag)
-        del varfont[tableTag]
-        return
-
-    log.info("Instantiating %s table", tableTag)
-    vhvar = varfont[tableTag].table
-    varStore = vhvar.VarStore
-    # since deltas were already applied, the return value here is ignored
-    instantiateItemVariationStore(varStore, fvarAxes, axisLimits)
-
-    if varStore.VarRegionList.Region:
-        # Only re-optimize VarStore if the HVAR/VVAR already uses indirect AdvWidthMap
-        # or AdvHeightMap. If a direct, implicit glyphID->VariationIndex mapping is
-        # used for advances, skip re-optimizing and maintain original VariationIndex.
-        if getattr(vhvar, tableFields.advMapping):
-            varIndexMapping = varStore.optimize()
-            glyphOrder = varfont.getGlyphOrder()
-            _remapVarIdxMap(vhvar, tableFields.advMapping, varIndexMapping, glyphOrder)
-            if getattr(vhvar, tableFields.sb1):  # left or top sidebearings
-                _remapVarIdxMap(vhvar, tableFields.sb1, varIndexMapping, glyphOrder)
-            if getattr(vhvar, tableFields.sb2):  # right or bottom sidebearings
-                _remapVarIdxMap(vhvar, tableFields.sb2, varIndexMapping, glyphOrder)
-            if tableTag == "VVAR" and getattr(vhvar, tableFields.vOrigMapping):
-                _remapVarIdxMap(
-                    vhvar, tableFields.vOrigMapping, varIndexMapping, glyphOrder
-                )
-
-
-def instantiateHVAR(varfont, axisLimits):
-    return _instantiateVHVAR(varfont, axisLimits, varLib.HVAR_FIELDS)
-
-
-def instantiateVVAR(varfont, axisLimits):
-    return _instantiateVHVAR(varfont, axisLimits, varLib.VVAR_FIELDS)
-
-
-class _TupleVarStoreAdapter(object):
-    def __init__(self, regions, axisOrder, tupleVarData, itemCounts):
-        self.regions = regions
-        self.axisOrder = axisOrder
-        self.tupleVarData = tupleVarData
-        self.itemCounts = itemCounts
-
-    @classmethod
-    def fromItemVarStore(cls, itemVarStore, fvarAxes):
-        axisOrder = [axis.axisTag for axis in fvarAxes]
-        regions = [
-            region.get_support(fvarAxes) for region in itemVarStore.VarRegionList.Region
-        ]
-        tupleVarData = []
-        itemCounts = []
-        for varData in itemVarStore.VarData:
-            variations = []
-            varDataRegions = (regions[i] for i in varData.VarRegionIndex)
-            for axes, coordinates in zip(varDataRegions, zip(*varData.Item)):
-                variations.append(TupleVariation(axes, list(coordinates)))
-            tupleVarData.append(variations)
-            itemCounts.append(varData.ItemCount)
-        return cls(regions, axisOrder, tupleVarData, itemCounts)
-
-    def rebuildRegions(self):
-        # Collect the set of all unique region axes from the current TupleVariations.
-        # We use an OrderedDict to de-duplicate regions while keeping the order.
-        uniqueRegions = collections.OrderedDict.fromkeys(
-            (
-                frozenset(var.axes.items())
-                for variations in self.tupleVarData
-                for var in variations
-            )
-        )
-        # Maintain the original order for the regions that pre-existed, appending
-        # the new regions at the end of the region list.
-        newRegions = []
-        for region in self.regions:
-            regionAxes = frozenset(region.items())
-            if regionAxes in uniqueRegions:
-                newRegions.append(region)
-                del uniqueRegions[regionAxes]
-        if uniqueRegions:
-            newRegions.extend(dict(region) for region in uniqueRegions)
-        self.regions = newRegions
-
-    def instantiate(self, axisLimits):
-        defaultDeltaArray = []
-        for variations, itemCount in zip(self.tupleVarData, self.itemCounts):
-            defaultDeltas = instantiateTupleVariationStore(variations, axisLimits)
-            if not defaultDeltas:
-                defaultDeltas = [0] * itemCount
-            defaultDeltaArray.append(defaultDeltas)
-
-        # rebuild regions whose axes were dropped or limited
-        self.rebuildRegions()
-
-        pinnedAxes = {
-            axisTag
-            for axisTag, value in axisLimits.items()
-            if not isinstance(value, tuple)
-        }
-        self.axisOrder = [
-            axisTag for axisTag in self.axisOrder if axisTag not in pinnedAxes
-        ]
-
-        return defaultDeltaArray
-
-    def asItemVarStore(self):
-        regionOrder = [frozenset(axes.items()) for axes in self.regions]
-        varDatas = []
-        for variations, itemCount in zip(self.tupleVarData, self.itemCounts):
-            if variations:
-                assert len(variations[0].coordinates) == itemCount
-                varRegionIndices = [
-                    regionOrder.index(frozenset(var.axes.items())) for var in variations
-                ]
-                varDataItems = list(zip(*(var.coordinates for var in variations)))
-                varDatas.append(
-                    builder.buildVarData(varRegionIndices, varDataItems, optimize=False)
-                )
-            else:
-                varDatas.append(
-                    builder.buildVarData([], [[] for _ in range(itemCount)])
-                )
-        regionList = builder.buildVarRegionList(self.regions, self.axisOrder)
-        itemVarStore = builder.buildVarStore(regionList, varDatas)
-        # remove unused regions from VarRegionList
-        itemVarStore.prune_regions()
-        return itemVarStore
-
-
-def instantiateItemVariationStore(itemVarStore, fvarAxes, axisLimits):
-    """Compute deltas at partial location, and update varStore in-place.
-
-    Remove regions in which all axes were instanced, or fall outside the new axis
-    limits. Scale the deltas of the remaining regions where only some of the axes
-    were instanced.
-
-    The number of VarData subtables, and the number of items within each, are
-    not modified, in order to keep the existing VariationIndex valid.
-    One may call VarStore.optimize() method after this to further optimize those.
-
-    Args:
-        varStore: An otTables.VarStore object (Item Variation Store)
-        fvarAxes: list of fvar's Axis objects
-        axisLimits: Dict[str, float] mapping axis tags to normalized axis coordinates
-            (float) or ranges for restricting an axis' min/max (NormalizedAxisRange).
-            May not specify coordinates/ranges for all the fvar axes.
-
-    Returns:
-        defaultDeltas: to be added to the default instance, of type dict of floats
-            keyed by VariationIndex compound values: i.e. (outer << 16) + inner.
-    """
-    tupleVarStore = _TupleVarStoreAdapter.fromItemVarStore(itemVarStore, fvarAxes)
-    defaultDeltaArray = tupleVarStore.instantiate(axisLimits)
-    newItemVarStore = tupleVarStore.asItemVarStore()
-
-    itemVarStore.VarRegionList = newItemVarStore.VarRegionList
-    assert itemVarStore.VarDataCount == newItemVarStore.VarDataCount
-    itemVarStore.VarData = newItemVarStore.VarData
-
-    defaultDeltas = {
-        ((major << 16) + minor): delta
-        for major, deltas in enumerate(defaultDeltaArray)
-        for minor, delta in enumerate(deltas)
-    }
-    return defaultDeltas
-
-
-def instantiateOTL(varfont, axisLimits):
-    # TODO(anthrotype) Support partial instancing of JSTF and BASE tables
-
-    if (
-        "GDEF" not in varfont
-        or varfont["GDEF"].table.Version < 0x00010003
-        or not varfont["GDEF"].table.VarStore
-    ):
-        return
-
-    if "GPOS" in varfont:
-        msg = "Instantiating GDEF and GPOS tables"
-    else:
-        msg = "Instantiating GDEF table"
-    log.info(msg)
-
-    gdef = varfont["GDEF"].table
-    varStore = gdef.VarStore
-    fvarAxes = varfont["fvar"].axes
-
-    defaultDeltas = instantiateItemVariationStore(varStore, fvarAxes, axisLimits)
-
-    # When VF are built, big lookups may overflow and be broken into multiple
-    # subtables. MutatorMerger (which inherits from AligningMerger) reattaches
-    # them upon instancing, in case they can now fit a single subtable (if not,
-    # they will be split again upon compilation).
-    # This 'merger' also works as a 'visitor' that traverses the OTL tables and
-    # calls specific methods when instances of a given type are found.
-    # Specifically, it adds default deltas to GPOS Anchors/ValueRecords and GDEF
-    # LigatureCarets, and optionally deletes all VariationIndex tables if the
-    # VarStore is fully instanced.
-    merger = MutatorMerger(
-        varfont, defaultDeltas, deleteVariations=(not varStore.VarRegionList.Region)
-    )
-    merger.mergeTables(varfont, [varfont], ["GDEF", "GPOS"])
-
-    if varStore.VarRegionList.Region:
-        varIndexMapping = varStore.optimize()
-        gdef.remap_device_varidxes(varIndexMapping)
-        if "GPOS" in varfont:
-            varfont["GPOS"].table.remap_device_varidxes(varIndexMapping)
-    else:
-        # Downgrade GDEF.
-        del gdef.VarStore
-        gdef.Version = 0x00010002
-        if gdef.MarkGlyphSetsDef is None:
-            del gdef.MarkGlyphSetsDef
-            gdef.Version = 0x00010000
-
-        if not (
-            gdef.LigCaretList
-            or gdef.MarkAttachClassDef
-            or gdef.GlyphClassDef
-            or gdef.AttachList
-            or (gdef.Version >= 0x00010002 and gdef.MarkGlyphSetsDef)
-        ):
-            del varfont["GDEF"]
-
-
-def instantiateFeatureVariations(varfont, axisLimits):
-    for tableTag in ("GPOS", "GSUB"):
-        if tableTag not in varfont or not getattr(
-            varfont[tableTag].table, "FeatureVariations", None
-        ):
-            continue
-        log.info("Instantiating FeatureVariations of %s table", tableTag)
-        _instantiateFeatureVariations(
-            varfont[tableTag].table, varfont["fvar"].axes, axisLimits
-        )
-        # remove unreferenced lookups
-        varfont[tableTag].prune_lookups()
-
-
-def _featureVariationRecordIsUnique(rec, seen):
-    conditionSet = []
-    for cond in rec.ConditionSet.ConditionTable:
-        if cond.Format != 1:
-            # can't tell whether this is duplicate, assume is unique
-            return True
-        conditionSet.append(
-            (cond.AxisIndex, cond.FilterRangeMinValue, cond.FilterRangeMaxValue)
-        )
-    # besides the set of conditions, we also include the FeatureTableSubstitution
-    # version to identify unique FeatureVariationRecords, even though only one
-    # version is currently defined. It's theoretically possible that multiple
-    # records with same conditions but different substitution table version be
-    # present in the same font for backward compatibility.
-    recordKey = frozenset([rec.FeatureTableSubstitution.Version] + conditionSet)
-    if recordKey in seen:
-        return False
-    else:
-        seen.add(recordKey)  # side effect
-        return True
-
-
-def _limitFeatureVariationConditionRange(condition, axisRange):
-    minValue = condition.FilterRangeMinValue
-    maxValue = condition.FilterRangeMaxValue
-
-    if (
-        minValue > maxValue
-        or minValue > axisRange.maximum
-        or maxValue < axisRange.minimum
-    ):
-        # condition invalid or out of range
-        return
-
-    values = [minValue, maxValue]
-    for i, value in enumerate(values):
-        if value < 0:
-            if axisRange.minimum == 0:
-                newValue = 0
-            else:
-                newValue = value / abs(axisRange.minimum)
-                if newValue <= -1.0:
-                    newValue = -1.0
-        elif value > 0:
-            if axisRange.maximum == 0:
-                newValue = 0
-            else:
-                newValue = value / axisRange.maximum
-                if newValue >= 1.0:
-                    newValue = 1.0
-        else:
-            newValue = 0
-        values[i] = newValue
-
-    return AxisRange(*values)
-
-
-def _instantiateFeatureVariationRecord(
-    record, recIdx, location, fvarAxes, axisIndexMap
-):
-    applies = True
-    newConditions = []
-    for i, condition in enumerate(record.ConditionSet.ConditionTable):
-        if condition.Format == 1:
-            axisIdx = condition.AxisIndex
-            axisTag = fvarAxes[axisIdx].axisTag
-            if axisTag in location:
-                minValue = condition.FilterRangeMinValue
-                maxValue = condition.FilterRangeMaxValue
-                v = location[axisTag]
-                if not (minValue <= v <= maxValue):
-                    # condition not met so remove entire record
-                    applies = False
-                    newConditions = None
-                    break
-            else:
-                # axis not pinned, keep condition with remapped axis index
-                applies = False
-                condition.AxisIndex = axisIndexMap[axisTag]
-                newConditions.append(condition)
-        else:
-            log.warning(
-                "Condition table {0} of FeatureVariationRecord {1} has "
-                "unsupported format ({2}); ignored".format(i, recIdx, condition.Format)
-            )
-            applies = False
-            newConditions.append(condition)
-
-    if newConditions:
-        record.ConditionSet.ConditionTable = newConditions
-        shouldKeep = True
-    else:
-        shouldKeep = False
-
-    return applies, shouldKeep
-
-
-def _limitFeatureVariationRecord(record, axisRanges, fvarAxes):
-    newConditions = []
-    for i, condition in enumerate(record.ConditionSet.ConditionTable):
-        if condition.Format == 1:
-            axisIdx = condition.AxisIndex
-            axisTag = fvarAxes[axisIdx].axisTag
-            if axisTag in axisRanges:
-                axisRange = axisRanges[axisTag]
-                newRange = _limitFeatureVariationConditionRange(condition, axisRange)
-                if newRange:
-                    # keep condition with updated limits and remapped axis index
-                    condition.FilterRangeMinValue = newRange.minimum
-                    condition.FilterRangeMaxValue = newRange.maximum
-                    newConditions.append(condition)
-                else:
-                    # condition out of range, remove entire record
-                    newConditions = None
-                    break
-            else:
-                newConditions.append(condition)
-        else:
-            newConditions.append(condition)
-
-    if newConditions:
-        record.ConditionSet.ConditionTable = newConditions
-        shouldKeep = True
-    else:
-        shouldKeep = False
-
-    return shouldKeep
-
-
-def _instantiateFeatureVariations(table, fvarAxes, axisLimits):
-    location, axisRanges = splitAxisLocationAndRanges(
-        axisLimits, rangeType=NormalizedAxisRange
-    )
-    pinnedAxes = set(location.keys())
-    axisOrder = [axis.axisTag for axis in fvarAxes if axis.axisTag not in pinnedAxes]
-    axisIndexMap = {axisTag: axisOrder.index(axisTag) for axisTag in axisOrder}
-
-    featureVariationApplied = False
-    uniqueRecords = set()
-    newRecords = []
-
-    for i, record in enumerate(table.FeatureVariations.FeatureVariationRecord):
-        applies, shouldKeep = _instantiateFeatureVariationRecord(
-            record, i, location, fvarAxes, axisIndexMap
-        )
-        if shouldKeep:
-            shouldKeep = _limitFeatureVariationRecord(record, axisRanges, fvarAxes)
-
-        if shouldKeep and _featureVariationRecordIsUnique(record, uniqueRecords):
-            newRecords.append(record)
-
-        if applies and not featureVariationApplied:
-            assert record.FeatureTableSubstitution.Version == 0x00010000
-            for rec in record.FeatureTableSubstitution.SubstitutionRecord:
-                table.FeatureList.FeatureRecord[rec.FeatureIndex].Feature = rec.Feature
-            # Set variations only once
-            featureVariationApplied = True
-
-    if newRecords:
-        table.FeatureVariations.FeatureVariationRecord = newRecords
-        table.FeatureVariations.FeatureVariationCount = len(newRecords)
-    else:
-        del table.FeatureVariations
-
-
-def _isValidAvarSegmentMap(axisTag, segmentMap):
-    if not segmentMap:
-        return True
-    if not {(-1.0, -1.0), (0, 0), (1.0, 1.0)}.issubset(segmentMap.items()):
-        log.warning(
-            f"Invalid avar SegmentMap record for axis '{axisTag}': does not "
-            "include all required value maps {-1.0: -1.0, 0: 0, 1.0: 1.0}"
-        )
-        return False
-    previousValue = None
-    for fromCoord, toCoord in sorted(segmentMap.items()):
-        if previousValue is not None and previousValue > toCoord:
-            log.warning(
-                f"Invalid avar AxisValueMap({fromCoord}, {toCoord}) record "
-                f"for axis '{axisTag}': the toCoordinate value must be >= to "
-                f"the toCoordinate value of the preceding record ({previousValue})."
-            )
-            return False
-        previousValue = toCoord
-    return True
-
-
-def instantiateAvar(varfont, axisLimits):
-    # 'axisLimits' dict must contain user-space (non-normalized) coordinates.
-
-    location, axisRanges = splitAxisLocationAndRanges(axisLimits)
-
-    segments = varfont["avar"].segments
-
-    # drop table if we instantiate all the axes
-    pinnedAxes = set(location.keys())
-    if pinnedAxes.issuperset(segments):
-        log.info("Dropping avar table")
-        del varfont["avar"]
-        return
-
-    log.info("Instantiating avar table")
-    for axis in pinnedAxes:
-        if axis in segments:
-            del segments[axis]
-
-    # First compute the default normalization for axisRanges coordinates: i.e.
-    # min = -1.0, default = 0, max = +1.0, and in between values interpolated linearly,
-    # without using the avar table's mappings.
-    # Then, for each SegmentMap, if we are restricting its axis, compute the new
-    # mappings by dividing the key/value pairs by the desired new min/max values,
-    # dropping any mappings that fall outside the restricted range.
-    # The keys ('fromCoord') are specified in default normalized coordinate space,
-    # whereas the values ('toCoord') are "mapped forward" using the SegmentMap.
-    normalizedRanges = normalizeAxisLimits(varfont, axisRanges, usingAvar=False)
-    newSegments = {}
-    for axisTag, mapping in segments.items():
-        if not _isValidAvarSegmentMap(axisTag, mapping):
-            continue
-        if mapping and axisTag in normalizedRanges:
-            axisRange = normalizedRanges[axisTag]
-            mappedMin = floatToFixedToFloat(
-                piecewiseLinearMap(axisRange.minimum, mapping), 14
-            )
-            mappedMax = floatToFixedToFloat(
-                piecewiseLinearMap(axisRange.maximum, mapping), 14
-            )
-            newMapping = {}
-            for fromCoord, toCoord in mapping.items():
-                if fromCoord < 0:
-                    if axisRange.minimum == 0 or fromCoord < axisRange.minimum:
-                        continue
-                    else:
-                        fromCoord /= abs(axisRange.minimum)
-                elif fromCoord > 0:
-                    if axisRange.maximum == 0 or fromCoord > axisRange.maximum:
-                        continue
-                    else:
-                        fromCoord /= axisRange.maximum
-                if toCoord < 0:
-                    assert mappedMin != 0
-                    assert toCoord >= mappedMin
-                    toCoord /= abs(mappedMin)
-                elif toCoord > 0:
-                    assert mappedMax != 0
-                    assert toCoord <= mappedMax
-                    toCoord /= mappedMax
-                fromCoord = floatToFixedToFloat(fromCoord, 14)
-                toCoord = floatToFixedToFloat(toCoord, 14)
-                newMapping[fromCoord] = toCoord
-            newMapping.update({-1.0: -1.0, 1.0: 1.0})
-            newSegments[axisTag] = newMapping
-        else:
-            newSegments[axisTag] = mapping
-    varfont["avar"].segments = newSegments
-
-
-def isInstanceWithinAxisRanges(location, axisRanges):
-    for axisTag, coord in location.items():
-        if axisTag in axisRanges:
-            axisRange = axisRanges[axisTag]
-            if coord < axisRange.minimum or coord > axisRange.maximum:
-                return False
-    return True
-
-
-def instantiateFvar(varfont, axisLimits):
-    # 'axisLimits' dict must contain user-space (non-normalized) coordinates
-
-    location, axisRanges = splitAxisLocationAndRanges(axisLimits, rangeType=AxisRange)
-
-    fvar = varfont["fvar"]
-
-    # drop table if we instantiate all the axes
-    if set(location).issuperset(axis.axisTag for axis in fvar.axes):
-        log.info("Dropping fvar table")
-        del varfont["fvar"]
-        return
-
-    log.info("Instantiating fvar table")
-
-    axes = []
-    for axis in fvar.axes:
-        axisTag = axis.axisTag
-        if axisTag in location:
-            continue
-        if axisTag in axisRanges:
-            axis.minValue, axis.maxValue = axisRanges[axisTag]
-        axes.append(axis)
-    fvar.axes = axes
-
-    # only keep NamedInstances whose coordinates == pinned axis location
-    instances = []
-    for instance in fvar.instances:
-        if any(instance.coordinates[axis] != value for axis, value in location.items()):
-            continue
-        for axisTag in location:
-            del instance.coordinates[axisTag]
-        if not isInstanceWithinAxisRanges(instance.coordinates, axisRanges):
-            continue
-        instances.append(instance)
-    fvar.instances = instances
-
-
-def instantiateSTAT(varfont, axisLimits):
-    # 'axisLimits' dict must contain user-space (non-normalized) coordinates
-
-    stat = varfont["STAT"].table
-    if not stat.DesignAxisRecord or not (
-        stat.AxisValueArray and stat.AxisValueArray.AxisValue
-    ):
-        return  # STAT table empty, nothing to do
-
-    log.info("Instantiating STAT table")
-    newAxisValueTables = axisValuesFromAxisLimits(stat, axisLimits)
-    stat.AxisValueArray.AxisValue = newAxisValueTables
-    stat.AxisValueCount = len(stat.AxisValueArray.AxisValue)
-
-
-def axisValuesFromAxisLimits(stat, axisLimits):
-    location, axisRanges = splitAxisLocationAndRanges(axisLimits, rangeType=AxisRange)
-
-    def isAxisValueOutsideLimits(axisTag, axisValue):
-        if axisTag in location and axisValue != location[axisTag]:
-            return True
-        elif axisTag in axisRanges:
-            axisRange = axisRanges[axisTag]
-            if axisValue < axisRange.minimum or axisValue > axisRange.maximum:
-                return True
-        return False
-
-    # only keep AxisValues whose axis is not pinned nor restricted, or is pinned at the
-    # exact (nominal) value, or is restricted but the value is within the new range
-    designAxes = stat.DesignAxisRecord.Axis
-    newAxisValueTables = []
-    for axisValueTable in stat.AxisValueArray.AxisValue:
-        axisValueFormat = axisValueTable.Format
-        if axisValueFormat in (1, 2, 3):
-            axisTag = designAxes[axisValueTable.AxisIndex].AxisTag
-            if axisValueFormat == 2:
-                axisValue = axisValueTable.NominalValue
-            else:
-                axisValue = axisValueTable.Value
-            if isAxisValueOutsideLimits(axisTag, axisValue):
-                continue
-        elif axisValueFormat == 4:
-            # drop 'non-analytic' AxisValue if _any_ AxisValueRecord doesn't match
-            # the pinned location or is outside range
-            dropAxisValueTable = False
-            for rec in axisValueTable.AxisValueRecord:
-                axisTag = designAxes[rec.AxisIndex].AxisTag
-                axisValue = rec.Value
-                if isAxisValueOutsideLimits(axisTag, axisValue):
-                    dropAxisValueTable = True
-                    break
-            if dropAxisValueTable:
-                continue
-        else:
-            log.warning("Unknown AxisValue table format (%s); ignored", axisValueFormat)
-        newAxisValueTables.append(axisValueTable)
-    return newAxisValueTables
-
-
-def setMacOverlapFlags(glyfTable):
-    flagOverlapCompound = _g_l_y_f.OVERLAP_COMPOUND
-    flagOverlapSimple = _g_l_y_f.flagOverlapSimple
-    for glyphName in glyfTable.keys():
-        glyph = glyfTable[glyphName]
-        # Set OVERLAP_COMPOUND bit for compound glyphs
-        if glyph.isComposite():
-            glyph.components[0].flags |= flagOverlapCompound
-        # Set OVERLAP_SIMPLE bit for simple glyphs
-        elif glyph.numberOfContours > 0:
-            glyph.flags[0] |= flagOverlapSimple
-
-
-def normalize(value, triple, avarMapping):
-    value = normalizeValue(value, triple)
-    if avarMapping:
-        value = piecewiseLinearMap(value, avarMapping)
-    # Quantize to F2Dot14, to avoid surprise interpolations.
-    return floatToFixedToFloat(value, 14)
-
-
-def normalizeAxisLimits(varfont, axisLimits, usingAvar=True):
-    fvar = varfont["fvar"]
-    badLimits = set(axisLimits.keys()).difference(a.axisTag for a in fvar.axes)
-    if badLimits:
-        raise ValueError("Cannot limit: {} not present in fvar".format(badLimits))
-
-    axes = {
-        a.axisTag: (a.minValue, a.defaultValue, a.maxValue)
-        for a in fvar.axes
-        if a.axisTag in axisLimits
-    }
-
-    avarSegments = {}
-    if usingAvar and "avar" in varfont:
-        avarSegments = varfont["avar"].segments
-
-    for axis_tag, (_, default, _) in axes.items():
-        value = axisLimits[axis_tag]
-        if isinstance(value, tuple):
-            minV, maxV = value
-            if minV > default or maxV < default:
-                raise NotImplementedError(
-                    f"Unsupported range {axis_tag}={minV:g}:{maxV:g}; "
-                    f"can't change default position ({axis_tag}={default:g})"
-                )
-
-    normalizedLimits = {}
-    for axis_tag, triple in axes.items():
-        avarMapping = avarSegments.get(axis_tag, None)
-        value = axisLimits[axis_tag]
-        if isinstance(value, tuple):
-            normalizedLimits[axis_tag] = NormalizedAxisRange(
-                *(normalize(v, triple, avarMapping) for v in value)
-            )
-        else:
-            normalizedLimits[axis_tag] = normalize(value, triple, avarMapping)
-    return normalizedLimits
-
-
-def sanityCheckVariableTables(varfont):
-    if "fvar" not in varfont:
-        raise ValueError("Missing required table fvar")
-    if "gvar" in varfont:
-        if "glyf" not in varfont:
-            raise ValueError("Can't have gvar without glyf")
-    # TODO(anthrotype) Remove once we do support partial instancing CFF2
-    if "CFF2" in varfont:
-        raise NotImplementedError("Instancing CFF2 variable fonts is not supported yet")
-
-
-def populateAxisDefaults(varfont, axisLimits):
-    if any(value is None for value in axisLimits.values()):
-        fvar = varfont["fvar"]
-        defaultValues = {a.axisTag: a.defaultValue for a in fvar.axes}
-        return {
-            axisTag: defaultValues[axisTag] if value is None else value
-            for axisTag, value in axisLimits.items()
-        }
-    return axisLimits
-
-
-def instantiateVariableFont(
-    varfont,
-    axisLimits,
-    inplace=False,
-    optimize=True,
-    overlap=OverlapMode.KEEP_AND_SET_FLAGS,
-    updateFontNames=False,
-):
-    """Instantiate variable font, either fully or partially.
-
-    Depending on whether the `axisLimits` dictionary references all or some of the
-    input varfont's axes, the output font will either be a full instance (static
-    font) or a variable font with possibly less variation data.
-
-    Args:
-        varfont: a TTFont instance, which must contain at least an 'fvar' table.
-            Note that variable fonts with 'CFF2' table are not supported yet.
-        axisLimits: a dict keyed by axis tags (str) containing the coordinates (float)
-            along one or more axes where the desired instance will be located.
-            If the value is `None`, the default coordinate as per 'fvar' table for
-            that axis is used.
-            The limit values can also be (min, max) tuples for restricting an
-            axis's variation range, but this is not implemented yet.
-        inplace (bool): whether to modify input TTFont object in-place instead of
-            returning a distinct object.
-        optimize (bool): if False, do not perform IUP-delta optimization on the
-            remaining 'gvar' table's deltas. Possibly faster, and might work around
-            rendering issues in some buggy environments, at the cost of a slightly
-            larger file size.
-        overlap (OverlapMode): variable fonts usually contain overlapping contours, and
-            some font rendering engines on Apple platforms require that the
-            `OVERLAP_SIMPLE` and `OVERLAP_COMPOUND` flags in the 'glyf' table be set to
-            force rendering using a non-zero fill rule. Thus we always set these flags
-            on all glyphs to maximise cross-compatibility of the generated instance.
-            You can disable this by passing OverlapMode.KEEP_AND_DONT_SET_FLAGS.
-            If you want to remove the overlaps altogether and merge overlapping
-            contours and components, you can pass OverlapMode.REMOVE. Note that this
-            requires the skia-pathops package (available to pip install).
-            The overlap parameter only has effect when generating full static instances.
-        updateFontNames (bool): if True, update the instantiated font's name table using
-            the Axis Value Tables from the STAT table. The name table will be updated so
-            it conforms to the R/I/B/BI model. If the STAT table is missing or
-            an Axis Value table is missing for a given axis coordinate, a ValueError will
-            be raised.
-    """
-    # 'overlap' used to be bool and is now enum; for backward compat keep accepting bool
-    overlap = OverlapMode(int(overlap))
-
-    sanityCheckVariableTables(varfont)
-
-    axisLimits = populateAxisDefaults(varfont, axisLimits)
-
-    normalizedLimits = normalizeAxisLimits(varfont, axisLimits)
-
-    log.info("Normalized limits: %s", normalizedLimits)
-
-    if not inplace:
-        varfont = deepcopy(varfont)
-
-    if updateFontNames:
-        log.info("Updating name table")
-        names.updateNameTable(varfont, axisLimits)
-
-    if "gvar" in varfont:
-        instantiateGvar(varfont, normalizedLimits, optimize=optimize)
-
-    if "cvar" in varfont:
-        instantiateCvar(varfont, normalizedLimits)
-
-    if "MVAR" in varfont:
-        instantiateMVAR(varfont, normalizedLimits)
-
-    if "HVAR" in varfont:
-        instantiateHVAR(varfont, normalizedLimits)
-
-    if "VVAR" in varfont:
-        instantiateVVAR(varfont, normalizedLimits)
-
-    instantiateOTL(varfont, normalizedLimits)
-
-    instantiateFeatureVariations(varfont, normalizedLimits)
-
-    if "avar" in varfont:
-        instantiateAvar(varfont, axisLimits)
-
-    with names.pruningUnusedNames(varfont):
-        if "STAT" in varfont:
-            instantiateSTAT(varfont, axisLimits)
-
-        instantiateFvar(varfont, axisLimits)
-
-    if "fvar" not in varfont:
-        if "glyf" in varfont:
-            if overlap == OverlapMode.KEEP_AND_SET_FLAGS:
-                setMacOverlapFlags(varfont["glyf"])
-            elif overlap == OverlapMode.REMOVE:
-                from fontTools.ttLib.removeOverlaps import removeOverlaps
-
-                log.info("Removing overlaps from glyf table")
-                removeOverlaps(varfont)
-
-    varLib.set_default_weight_width_slant(
-        varfont,
-        location={
-            axisTag: limit
-            for axisTag, limit in axisLimits.items()
-            if not isinstance(limit, tuple)
-        },
-    )
-
-    return varfont
-
-
-def splitAxisLocationAndRanges(axisLimits, rangeType=AxisRange):
-    location, axisRanges = {}, {}
-    for axisTag, value in axisLimits.items():
-        if isinstance(value, rangeType):
-            axisRanges[axisTag] = value
-        elif isinstance(value, (int, float)):
-            location[axisTag] = value
-        elif isinstance(value, tuple):
-            axisRanges[axisTag] = rangeType(*value)
-        else:
-            raise TypeError(
-                f"Expected number or {rangeType.__name__}, "
-                f"got {type(value).__name__}: {value!r}"
-            )
-    return location, axisRanges
-
-
-def parseLimits(limits):
-    result = {}
-    for limitString in limits:
-        match = re.match(r"^(\w{1,4})=(?:(drop)|(?:([^:]+)(?:[:](.+))?))$", limitString)
-        if not match:
-            raise ValueError("invalid location format: %r" % limitString)
-        tag = match.group(1).ljust(4)
-        if match.group(2):  # 'drop'
-            lbound = None
-        else:
-            lbound = strToFixedToFloat(match.group(3), precisionBits=16)
-        ubound = lbound
-        if match.group(4):
-            ubound = strToFixedToFloat(match.group(4), precisionBits=16)
-        if lbound != ubound:
-            result[tag] = AxisRange(lbound, ubound)
-        else:
-            result[tag] = lbound
-    return result
-
-
-def parseArgs(args):
-    """Parse argv.
-
-    Returns:
-        3-tuple (infile, axisLimits, options)
-        axisLimits is either a Dict[str, Optional[float]], for pinning variation axes
-        to specific coordinates along those axes (with `None` as a placeholder for an
-        axis' default value); or a Dict[str, Tuple(float, float)], meaning limit this
-        axis to min/max range.
-        Axes locations are in user-space coordinates, as defined in the "fvar" table.
-    """
-    from fontTools import configLogger
-    import argparse
-
-    parser = argparse.ArgumentParser(
-        "fonttools varLib.instancer",
-        description="Partially instantiate a variable font",
-    )
-    parser.add_argument("input", metavar="INPUT.ttf", help="Input variable TTF file.")
-    parser.add_argument(
-        "locargs",
-        metavar="AXIS=LOC",
-        nargs="*",
-        help="List of space separated locations. A location consists of "
-        "the tag of a variation axis, followed by '=' and one of number, "
-        "number:number or the literal string 'drop'. "
-        "E.g.: wdth=100 or wght=75.0:125.0 or wght=drop",
-    )
-    parser.add_argument(
-        "-o",
-        "--output",
-        metavar="OUTPUT.ttf",
-        default=None,
-        help="Output instance TTF file (default: INPUT-instance.ttf).",
-    )
-    parser.add_argument(
-        "--no-optimize",
-        dest="optimize",
-        action="store_false",
-        help="Don't perform IUP optimization on the remaining gvar TupleVariations",
-    )
-    parser.add_argument(
-        "--no-overlap-flag",
-        dest="overlap",
-        action="store_false",
-        help="Don't set OVERLAP_SIMPLE/OVERLAP_COMPOUND glyf flags (only applicable "
-        "when generating a full instance)",
-    )
-    parser.add_argument(
-        "--remove-overlaps",
-        dest="remove_overlaps",
-        action="store_true",
-        help="Merge overlapping contours and components (only applicable "
-        "when generating a full instance). Requires skia-pathops",
-    )
-    parser.add_argument(
-        "--update-name-table",
-        action="store_true",
-        help="Update the instantiated font's `name` table. Input font must have "
-        "a STAT table with Axis Value Tables",
-    )
-    loggingGroup = parser.add_mutually_exclusive_group(required=False)
-    loggingGroup.add_argument(
-        "-v", "--verbose", action="store_true", help="Run more verbosely."
-    )
-    loggingGroup.add_argument(
-        "-q", "--quiet", action="store_true", help="Turn verbosity off."
-    )
-    options = parser.parse_args(args)
-
-    if options.remove_overlaps:
-        options.overlap = OverlapMode.REMOVE
-    else:
-        options.overlap = OverlapMode(int(options.overlap))
-
-    infile = options.input
-    if not os.path.isfile(infile):
-        parser.error("No such file '{}'".format(infile))
-
-    configLogger(
-        level=("DEBUG" if options.verbose else "ERROR" if options.quiet else "INFO")
-    )
-
-    try:
-        axisLimits = parseLimits(options.locargs)
-    except ValueError as e:
-        parser.error(str(e))
-
-    if len(axisLimits) != len(options.locargs):
-        parser.error("Specified multiple limits for the same axis")
-
-    return (infile, axisLimits, options)
-
-
-def main(args=None):
-    """Partially instantiate a variable font."""
-    infile, axisLimits, options = parseArgs(args)
-    log.info("Restricting axes: %s", axisLimits)
-
-    log.info("Loading variable font")
-    varfont = TTFont(infile)
-
-    isFullInstance = {
-        axisTag for axisTag, limit in axisLimits.items() if not isinstance(limit, tuple)
-    }.issuperset(axis.axisTag for axis in varfont["fvar"].axes)
-
-    instantiateVariableFont(
-        varfont,
-        axisLimits,
-        inplace=True,
-        optimize=options.optimize,
-        overlap=options.overlap,
-        updateFontNames=options.update_name_table,
-    )
-
-    outfile = (
-        os.path.splitext(infile)[0]
-        + "-{}.ttf".format("instance" if isFullInstance else "partial")
-        if not options.output
-        else options.output
-    )
-
-    log.info(
-        "Saving %s font %s",
-        "instance" if isFullInstance else "partial variable",
-        outfile,
-    )
-    varfont.save(outfile)
diff --git a/Lib/fontTools/varLib/instancer/__main__.py b/Lib/fontTools/varLib/instancer/__main__.py
deleted file mode 100644
index 64ffff2..0000000
--- a/Lib/fontTools/varLib/instancer/__main__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-import sys
-from fontTools.varLib.instancer import main
-
-if __name__ == "__main__":
-    sys.exit(main())
diff --git a/Lib/fontTools/varLib/instancer/names.py b/Lib/fontTools/varLib/instancer/names.py
deleted file mode 100644
index cfe12a9..0000000
--- a/Lib/fontTools/varLib/instancer/names.py
+++ /dev/null
@@ -1,379 +0,0 @@
-"""Helpers for instantiating name table records."""
-
-from contextlib import contextmanager
-from copy import deepcopy
-from enum import IntEnum
-import re
-
-
-class NameID(IntEnum):
-    FAMILY_NAME = 1
-    SUBFAMILY_NAME = 2
-    UNIQUE_FONT_IDENTIFIER = 3
-    FULL_FONT_NAME = 4
-    VERSION_STRING = 5
-    POSTSCRIPT_NAME = 6
-    TYPOGRAPHIC_FAMILY_NAME = 16
-    TYPOGRAPHIC_SUBFAMILY_NAME = 17
-    VARIATIONS_POSTSCRIPT_NAME_PREFIX = 25
-
-
-ELIDABLE_AXIS_VALUE_NAME = 2
-
-
-def getVariationNameIDs(varfont):
-    used = []
-    if "fvar" in varfont:
-        fvar = varfont["fvar"]
-        for axis in fvar.axes:
-            used.append(axis.axisNameID)
-        for instance in fvar.instances:
-            used.append(instance.subfamilyNameID)
-            if instance.postscriptNameID != 0xFFFF:
-                used.append(instance.postscriptNameID)
-    if "STAT" in varfont:
-        stat = varfont["STAT"].table
-        for axis in stat.DesignAxisRecord.Axis if stat.DesignAxisRecord else ():
-            used.append(axis.AxisNameID)
-        for value in stat.AxisValueArray.AxisValue if stat.AxisValueArray else ():
-            used.append(value.ValueNameID)
-    # nameIDs <= 255 are reserved by OT spec so we don't touch them
-    return {nameID for nameID in used if nameID > 255}
-
-
-@contextmanager
-def pruningUnusedNames(varfont):
-    from . import log
-
-    origNameIDs = getVariationNameIDs(varfont)
-
-    yield
-
-    log.info("Pruning name table")
-    exclude = origNameIDs - getVariationNameIDs(varfont)
-    varfont["name"].names[:] = [
-        record for record in varfont["name"].names if record.nameID not in exclude
-    ]
-    if "ltag" in varfont:
-        # Drop the whole 'ltag' table if all the language-dependent Unicode name
-        # records that reference it have been dropped.
-        # TODO: Only prune unused ltag tags, renumerating langIDs accordingly.
-        # Note ltag can also be used by feat or morx tables, so check those too.
-        if not any(
-            record
-            for record in varfont["name"].names
-            if record.platformID == 0 and record.langID != 0xFFFF
-        ):
-            del varfont["ltag"]
-
-
-def updateNameTable(varfont, axisLimits):
-    """Update instatiated variable font's name table using STAT AxisValues.
-
-    Raises ValueError if the STAT table is missing or an Axis Value table is
-    missing for requested axis locations.
-
-    First, collect all STAT AxisValues that match the new default axis locations
-    (excluding "elided" ones); concatenate the strings in design axis order,
-    while giving priority to "synthetic" values (Format 4), to form the
-    typographic subfamily name associated with the new default instance.
-    Finally, update all related records in the name table, making sure that
-    legacy family/sub-family names conform to the the R/I/B/BI (Regular, Italic,
-    Bold, Bold Italic) naming model.
-
-    Example: Updating a partial variable font:
-    | >>> ttFont = TTFont("OpenSans[wdth,wght].ttf")
-    | >>> updateNameTable(ttFont, {"wght": AxisRange(400, 900), "wdth": 75})
-
-    The name table records will be updated in the following manner:
-    NameID 1 familyName: "Open Sans" --> "Open Sans Condensed"
-    NameID 2 subFamilyName: "Regular" --> "Regular"
-    NameID 3 Unique font identifier: "3.000;GOOG;OpenSans-Regular" --> \
-        "3.000;GOOG;OpenSans-Condensed"
-    NameID 4 Full font name: "Open Sans Regular" --> "Open Sans Condensed"
-    NameID 6 PostScript name: "OpenSans-Regular" --> "OpenSans-Condensed"
-    NameID 16 Typographic Family name: None --> "Open Sans"
-    NameID 17 Typographic Subfamily name: None --> "Condensed"
-
-    References:
-    https://docs.microsoft.com/en-us/typography/opentype/spec/stat
-    https://docs.microsoft.com/en-us/typography/opentype/spec/name#name-ids
-    """
-    from . import AxisRange, axisValuesFromAxisLimits
-
-    if "STAT" not in varfont:
-        raise ValueError("Cannot update name table since there is no STAT table.")
-    stat = varfont["STAT"].table
-    if not stat.AxisValueArray:
-        raise ValueError("Cannot update name table since there are no STAT Axis Values")
-    fvar = varfont["fvar"]
-
-    # The updated name table will reflect the new 'zero origin' of the font.
-    # If we're instantiating a partial font, we will populate the unpinned
-    # axes with their default axis values.
-    fvarDefaults = {a.axisTag: a.defaultValue for a in fvar.axes}
-    defaultAxisCoords = deepcopy(axisLimits)
-    for axisTag, val in fvarDefaults.items():
-        if axisTag not in defaultAxisCoords or isinstance(
-            defaultAxisCoords[axisTag], AxisRange
-        ):
-            defaultAxisCoords[axisTag] = val
-
-    axisValueTables = axisValuesFromAxisLimits(stat, defaultAxisCoords)
-    checkAxisValuesExist(stat, axisValueTables, defaultAxisCoords)
-
-    # ignore "elidable" axis values, should be omitted in application font menus.
-    axisValueTables = [
-        v for v in axisValueTables if not v.Flags & ELIDABLE_AXIS_VALUE_NAME
-    ]
-    axisValueTables = _sortAxisValues(axisValueTables)
-    _updateNameRecords(varfont, axisValueTables)
-
-
-def checkAxisValuesExist(stat, axisValues, axisCoords):
-    seen = set()
-    designAxes = stat.DesignAxisRecord.Axis
-    for axisValueTable in axisValues:
-        axisValueFormat = axisValueTable.Format
-        if axisValueTable.Format in (1, 2, 3):
-            axisTag = designAxes[axisValueTable.AxisIndex].AxisTag
-            if axisValueFormat == 2:
-                axisValue = axisValueTable.NominalValue
-            else:
-                axisValue = axisValueTable.Value
-            if axisTag in axisCoords and axisValue == axisCoords[axisTag]:
-                seen.add(axisTag)
-        elif axisValueTable.Format == 4:
-            for rec in axisValueTable.AxisValueRecord:
-                axisTag = designAxes[rec.AxisIndex].AxisTag
-                if axisTag in axisCoords and rec.Value == axisCoords[axisTag]:
-                    seen.add(axisTag)
-
-    missingAxes = set(axisCoords) - seen
-    if missingAxes:
-        missing = ", ".join(f"'{i}={axisCoords[i]}'" for i in missingAxes)
-        raise ValueError(f"Cannot find Axis Values [{missing}]")
-
-
-def _sortAxisValues(axisValues):
-    # Sort by axis index, remove duplicates and ensure that format 4 AxisValues
-    # are dominant.
-    # The MS Spec states: "if a format 1, format 2 or format 3 table has a
-    # (nominal) value used in a format 4 table that also has values for
-    # other axes, the format 4 table, being the more specific match, is used",
-    # https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-4
-    results = []
-    seenAxes = set()
-    # Sort format 4 axes so the tables with the most AxisValueRecords are first
-    format4 = sorted(
-        [v for v in axisValues if v.Format == 4],
-        key=lambda v: len(v.AxisValueRecord),
-        reverse=True,
-    )
-
-    for val in format4:
-        axisIndexes = set(r.AxisIndex for r in val.AxisValueRecord)
-        minIndex = min(axisIndexes)
-        if not seenAxes & axisIndexes:
-            seenAxes |= axisIndexes
-            results.append((minIndex, val))
-
-    for val in axisValues:
-        if val in format4:
-            continue
-        axisIndex = val.AxisIndex
-        if axisIndex not in seenAxes:
-            seenAxes.add(axisIndex)
-            results.append((axisIndex, val))
-
-    return [axisValue for _, axisValue in sorted(results)]
-
-
-def _updateNameRecords(varfont, axisValues):
-    # Update nametable based on the axisValues using the R/I/B/BI model.
-    nametable = varfont["name"]
-    stat = varfont["STAT"].table
-
-    axisValueNameIDs = [a.ValueNameID for a in axisValues]
-    ribbiNameIDs = [n for n in axisValueNameIDs if _isRibbi(nametable, n)]
-    nonRibbiNameIDs = [n for n in axisValueNameIDs if n not in ribbiNameIDs]
-    elidedNameID = stat.ElidedFallbackNameID
-    elidedNameIsRibbi = _isRibbi(nametable, elidedNameID)
-
-    getName = nametable.getName
-    platforms = set((r.platformID, r.platEncID, r.langID) for r in nametable.names)
-    for platform in platforms:
-        if not all(getName(i, *platform) for i in (1, 2, elidedNameID)):
-            # Since no family name and subfamily name records were found,
-            # we cannot update this set of name Records.
-            continue
-
-        subFamilyName = " ".join(
-            getName(n, *platform).toUnicode() for n in ribbiNameIDs
-        )
-        if nonRibbiNameIDs:
-            typoSubFamilyName = " ".join(
-                getName(n, *platform).toUnicode() for n in axisValueNameIDs
-            )
-        else:
-            typoSubFamilyName = None
-
-        # If neither subFamilyName and typographic SubFamilyName exist,
-        # we will use the STAT's elidedFallbackName
-        if not typoSubFamilyName and not subFamilyName:
-            if elidedNameIsRibbi:
-                subFamilyName = getName(elidedNameID, *platform).toUnicode()
-            else:
-                typoSubFamilyName = getName(elidedNameID, *platform).toUnicode()
-
-        familyNameSuffix = " ".join(
-            getName(n, *platform).toUnicode() for n in nonRibbiNameIDs
-        )
-
-        _updateNameTableStyleRecords(
-            varfont,
-            familyNameSuffix,
-            subFamilyName,
-            typoSubFamilyName,
-            *platform,
-        )
-
-
-def _isRibbi(nametable, nameID):
-    englishRecord = nametable.getName(nameID, 3, 1, 0x409)
-    return (
-        True
-        if englishRecord is not None
-        and englishRecord.toUnicode() in ("Regular", "Italic", "Bold", "Bold Italic")
-        else False
-    )
-
-
-def _updateNameTableStyleRecords(
-    varfont,
-    familyNameSuffix,
-    subFamilyName,
-    typoSubFamilyName,
-    platformID=3,
-    platEncID=1,
-    langID=0x409,
-):
-    # TODO (Marc F) It may be nice to make this part a standalone
-    # font renamer in the future.
-    nametable = varfont["name"]
-    platform = (platformID, platEncID, langID)
-
-    currentFamilyName = nametable.getName(
-        NameID.TYPOGRAPHIC_FAMILY_NAME, *platform
-    ) or nametable.getName(NameID.FAMILY_NAME, *platform)
-
-    currentStyleName = nametable.getName(
-        NameID.TYPOGRAPHIC_SUBFAMILY_NAME, *platform
-    ) or nametable.getName(NameID.SUBFAMILY_NAME, *platform)
-
-    if not all([currentFamilyName, currentStyleName]):
-        raise ValueError(f"Missing required NameIDs 1 and 2 for platform {platform}")
-
-    currentFamilyName = currentFamilyName.toUnicode()
-    currentStyleName = currentStyleName.toUnicode()
-
-    nameIDs = {
-        NameID.FAMILY_NAME: currentFamilyName,
-        NameID.SUBFAMILY_NAME: subFamilyName or "Regular",
-    }
-    if typoSubFamilyName:
-        nameIDs[NameID.FAMILY_NAME] = f"{currentFamilyName} {familyNameSuffix}".strip()
-        nameIDs[NameID.TYPOGRAPHIC_FAMILY_NAME] = currentFamilyName
-        nameIDs[NameID.TYPOGRAPHIC_SUBFAMILY_NAME] = typoSubFamilyName
-    else:
-        # Remove previous Typographic Family and SubFamily names since they're
-        # no longer required
-        for nameID in (
-            NameID.TYPOGRAPHIC_FAMILY_NAME,
-            NameID.TYPOGRAPHIC_SUBFAMILY_NAME,
-        ):
-            nametable.removeNames(nameID=nameID)
-
-    newFamilyName = (
-        nameIDs.get(NameID.TYPOGRAPHIC_FAMILY_NAME) or nameIDs[NameID.FAMILY_NAME]
-    )
-    newStyleName = (
-        nameIDs.get(NameID.TYPOGRAPHIC_SUBFAMILY_NAME) or nameIDs[NameID.SUBFAMILY_NAME]
-    )
-
-    nameIDs[NameID.FULL_FONT_NAME] = f"{newFamilyName} {newStyleName}"
-    nameIDs[NameID.POSTSCRIPT_NAME] = _updatePSNameRecord(
-        varfont, newFamilyName, newStyleName, platform
-    )
-
-    uniqueID = _updateUniqueIdNameRecord(varfont, nameIDs, platform)
-    if uniqueID:
-        nameIDs[NameID.UNIQUE_FONT_IDENTIFIER] = uniqueID
-
-    for nameID, string in nameIDs.items():
-        assert string, nameID
-        nametable.setName(string, nameID, *platform)
-
-    if "fvar" not in varfont:
-        nametable.removeNames(NameID.VARIATIONS_POSTSCRIPT_NAME_PREFIX)
-
-
-def _updatePSNameRecord(varfont, familyName, styleName, platform):
-    # Implementation based on Adobe Technical Note #5902 :
-    # https://wwwimages2.adobe.com/content/dam/acom/en/devnet/font/pdfs/5902.AdobePSNameGeneration.pdf
-    nametable = varfont["name"]
-
-    family_prefix = nametable.getName(
-        NameID.VARIATIONS_POSTSCRIPT_NAME_PREFIX, *platform
-    )
-    if family_prefix:
-        family_prefix = family_prefix.toUnicode()
-    else:
-        family_prefix = familyName
-
-    psName = f"{family_prefix}-{styleName}"
-    # Remove any characters other than uppercase Latin letters, lowercase
-    # Latin letters, digits and hyphens.
-    psName = re.sub(r"[^A-Za-z0-9-]", r"", psName)
-
-    if len(psName) > 127:
-        # Abbreviating the stylename so it fits within 127 characters whilst
-        # conforming to every vendor's specification is too complex. Instead
-        # we simply truncate the psname and add the required "..."
-        return f"{psName[:124]}..."
-    return psName
-
-
-def _updateUniqueIdNameRecord(varfont, nameIDs, platform):
-    nametable = varfont["name"]
-    currentRecord = nametable.getName(NameID.UNIQUE_FONT_IDENTIFIER, *platform)
-    if not currentRecord:
-        return None
-
-    # Check if full name and postscript name are a substring of currentRecord
-    for nameID in (NameID.FULL_FONT_NAME, NameID.POSTSCRIPT_NAME):
-        nameRecord = nametable.getName(nameID, *platform)
-        if not nameRecord:
-            continue
-        if nameRecord.toUnicode() in currentRecord.toUnicode():
-            return currentRecord.toUnicode().replace(
-                nameRecord.toUnicode(), nameIDs[nameRecord.nameID]
-            )
-
-    # Create a new string since we couldn't find any substrings.
-    fontVersion = _fontVersion(varfont, platform)
-    achVendID = varfont["OS/2"].achVendID
-    # Remove non-ASCII characers and trailing spaces
-    vendor = re.sub(r"[^\x00-\x7F]", "", achVendID).strip()
-    psName = nameIDs[NameID.POSTSCRIPT_NAME]
-    return f"{fontVersion};{vendor};{psName}"
-
-
-def _fontVersion(font, platform=(3, 1, 0x409)):
-    nameRecord = font["name"].getName(NameID.VERSION_STRING, *platform)
-    if nameRecord is None:
-        return f'{font["head"].fontRevision:.3f}'
-    # "Version 1.101; ttfautohint (v1.8.1.43-b0c9)" --> "1.101"
-    # Also works fine with inputs "Version 1.101" or "1.101" etc
-    versionNumber = nameRecord.toUnicode().split(";")[0]
-    return versionNumber.lstrip("Version ").strip()
diff --git a/Lib/fontTools/varLib/interpolatable.py b/Lib/fontTools/varLib/interpolatable.py
index cff76ec..d4feed2 100644
--- a/Lib/fontTools/varLib/interpolatable.py
+++ b/Lib/fontTools/varLib/interpolatable.py
@@ -6,367 +6,176 @@
 $ fonttools varLib.interpolatable font1 font2 ...
 """
 
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+
 from fontTools.pens.basePen import AbstractPen, BasePen
 from fontTools.pens.recordingPen import RecordingPen
 from fontTools.pens.statisticsPen import StatisticsPen
-from fontTools.pens.momentsPen import OpenContourError
-from collections import OrderedDict
 import itertools
-import sys
 
 
 class PerContourPen(BasePen):
-    def __init__(self, Pen, glyphset=None):
-        BasePen.__init__(self, glyphset)
-        self._glyphset = glyphset
-        self._Pen = Pen
-        self._pen = None
-        self.value = []
+	def __init__(self, Pen, glyphset=None):
+		BasePen.__init__(self, glyphset)
+		self._glyphset = glyphset
+		self._Pen = Pen
+		self._pen = None
+		self.value = []
+	def _moveTo(self, p0):
+		self._newItem()
+		self._pen.moveTo(p0)
+	def _lineTo(self, p1):
+		self._pen.lineTo(p1)
+	def _qCurveToOne(self, p1, p2):
+		self._pen.qCurveTo(p1, p2)
+	def _curveToOne(self, p1, p2, p3):
+		self._pen.curveTo(p1, p2, p3)
+	def _closePath(self):
+		self._pen.closePath()
+		self._pen = None
+	def _endPath(self):
+		self._pen.endPath()
+		self._pen = None
 
-    def _moveTo(self, p0):
-        self._newItem()
-        self._pen.moveTo(p0)
-
-    def _lineTo(self, p1):
-        self._pen.lineTo(p1)
-
-    def _qCurveToOne(self, p1, p2):
-        self._pen.qCurveTo(p1, p2)
-
-    def _curveToOne(self, p1, p2, p3):
-        self._pen.curveTo(p1, p2, p3)
-
-    def _closePath(self):
-        self._pen.closePath()
-        self._pen = None
-
-    def _endPath(self):
-        self._pen.endPath()
-        self._pen = None
-
-    def _newItem(self):
-        self._pen = pen = self._Pen()
-        self.value.append(pen)
-
+	def _newItem(self):
+		self._pen = pen = self._Pen()
+		self.value.append(pen)
 
 class PerContourOrComponentPen(PerContourPen):
-    def addComponent(self, glyphName, transformation):
-        self._newItem()
-        self.value[-1].addComponent(glyphName, transformation)
+
+	def addComponent(self, glyphName, transformation):
+		self._newItem()
+		self.value[-1].addComponent(glyphName, transformation)
 
 
 def _vdiff(v0, v1):
-    return tuple(b - a for a, b in zip(v0, v1))
-
-
+	return tuple(b-a for a,b in zip(v0,v1))
 def _vlen(vec):
-    v = 0
-    for x in vec:
-        v += x * x
-    return v
-
+	v = 0
+	for x in vec:
+		v += x*x
+	return v
 
 def _matching_cost(G, matching):
-    return sum(G[i][j] for i, j in enumerate(matching))
-
+	return sum(G[i][j] for i,j in enumerate(matching))
 
 def min_cost_perfect_bipartite_matching(G):
-    n = len(G)
-    try:
-        from scipy.optimize import linear_sum_assignment
+	n = len(G)
+	try:
+		from scipy.optimize import linear_sum_assignment
+		rows, cols = linear_sum_assignment(G)
+		assert (rows == list(range(n))).all()
+		return list(cols), _matching_cost(G, cols)
+	except ImportError:
+		pass
 
-        rows, cols = linear_sum_assignment(G)
-        assert (rows == list(range(n))).all()
-        return list(cols), _matching_cost(G, cols)
-    except ImportError:
-        pass
+	try:
+		from munkres import Munkres
+		cols = [None] * n
+		for row,col in Munkres().compute(G):
+			cols[row] = col
+		return cols, _matching_cost(G, cols)
+	except ImportError:
+		pass
 
-    try:
-        from munkres import Munkres
+	if n > 6:
+		raise Exception("Install Python module 'munkres' or 'scipy >= 0.17.0'")
 
-        cols = [None] * n
-        for row, col in Munkres().compute(G):
-            cols[row] = col
-        return cols, _matching_cost(G, cols)
-    except ImportError:
-        pass
-
-    if n > 6:
-        raise Exception("Install Python module 'munkres' or 'scipy >= 0.17.0'")
-
-    # Otherwise just brute-force
-    permutations = itertools.permutations(range(n))
-    best = list(next(permutations))
-    best_cost = _matching_cost(G, best)
-    for p in permutations:
-        cost = _matching_cost(G, p)
-        if cost < best_cost:
-            best, best_cost = list(p), cost
-    return best, best_cost
+	# Otherwise just brute-force
+	permutations = itertools.permutations(range(n))
+	best = list(next(permutations))
+	best_cost = _matching_cost(G, best)
+	for p in permutations:
+		cost = _matching_cost(G, p)
+		if cost < best_cost:
+			best, best_cost = list(p), cost
+	return best, best_cost
 
 
 def test(glyphsets, glyphs=None, names=None):
 
-    if names is None:
-        names = glyphsets
-    if glyphs is None:
-        glyphs = glyphsets[0].keys()
+	if names is None:
+		names = glyphsets
+	if glyphs is None:
+		glyphs = glyphsets[0].keys()
 
-    hist = []
-    problems = OrderedDict()
+	hist = []
+	for glyph_name in glyphs:
+		#print()
+		#print(glyph_name)
 
-    def add_problem(glyphname, problem):
-        problems.setdefault(glyphname, []).append(problem)
+		try:
+			allVectors = []
+			for glyphset,name in zip(glyphsets, names):
+				#print('.', end='')
+				glyph = glyphset[glyph_name]
 
-    for glyph_name in glyphs:
-        # print()
-        # print(glyph_name)
+				perContourPen = PerContourOrComponentPen(RecordingPen, glyphset=glyphset)
+				glyph.draw(perContourPen)
+				contourPens = perContourPen.value
+				del perContourPen
 
-        try:
-            allVectors = []
-            allNodeTypes = []
-            for glyphset, name in zip(glyphsets, names):
-                # print('.', end='')
-                if glyph_name not in glyphset:
-                    add_problem(glyph_name, {"type": "missing", "master": name})
-                    continue
-                glyph = glyphset[glyph_name]
+				contourVectors = []
+				allVectors.append(contourVectors)
+				for contour in contourPens:
+					stats = StatisticsPen(glyphset=glyphset)
+					contour.replay(stats)
+					size = abs(stats.area) ** .5 * .5
+					vector = (
+						int(size),
+						int(stats.meanX),
+						int(stats.meanY),
+						int(stats.stddevX * 2),
+						int(stats.stddevY * 2),
+						int(stats.correlation * size),
+					)
+					contourVectors.append(vector)
+					#print(vector)
 
-                perContourPen = PerContourOrComponentPen(
-                    RecordingPen, glyphset=glyphset
-                )
-                glyph.draw(perContourPen)
-                contourPens = perContourPen.value
-                del perContourPen
-
-                contourVectors = []
-                nodeTypes = []
-                allNodeTypes.append(nodeTypes)
-                allVectors.append(contourVectors)
-                for ix, contour in enumerate(contourPens):
-                    nodeTypes.append(
-                        tuple(instruction[0] for instruction in contour.value)
-                    )
-                    stats = StatisticsPen(glyphset=glyphset)
-                    try:
-                        contour.replay(stats)
-                    except OpenContourError as e:
-                        add_problem(
-                            glyph_name,
-                            {"master": name, "contour": ix, "type": "open_path"},
-                        )
-                        continue
-                    size = abs(stats.area) ** 0.5 * 0.5
-                    vector = (
-                        int(size),
-                        int(stats.meanX),
-                        int(stats.meanY),
-                        int(stats.stddevX * 2),
-                        int(stats.stddevY * 2),
-                        int(stats.correlation * size),
-                    )
-                    contourVectors.append(vector)
-                    # print(vector)
-
-            # Check each master against the next one in the list.
-            for i, (m0, m1) in enumerate(zip(allNodeTypes[:-1], allNodeTypes[1:])):
-                if len(m0) != len(m1):
-                    add_problem(
-                        glyph_name,
-                        {
-                            "type": "path_count",
-                            "master_1": names[i],
-                            "master_2": names[i + 1],
-                            "value_1": len(m0),
-                            "value_2": len(m1),
-                        },
-                    )
-                if m0 == m1:
-                    continue
-                for pathIx, (nodes1, nodes2) in enumerate(zip(m0, m1)):
-                    if nodes1 == nodes2:
-                        continue
-                    if len(nodes1) != len(nodes2):
-                        add_problem(
-                            glyph_name,
-                            {
-                                "type": "node_count",
-                                "path": pathIx,
-                                "master_1": names[i],
-                                "master_2": names[i + 1],
-                                "value_1": len(nodes1),
-                                "value_2": len(nodes2),
-                            },
-                        )
-                        continue
-                    for nodeIx, (n1, n2) in enumerate(zip(nodes1, nodes2)):
-                        if n1 != n2:
-                            add_problem(
-                                glyph_name,
-                                {
-                                    "type": "node_incompatibility",
-                                    "path": pathIx,
-                                    "node": nodeIx,
-                                    "master_1": names[i],
-                                    "master_2": names[i + 1],
-                                    "value_1": n1,
-                                    "value_2": n2,
-                                },
-                            )
-                            continue
-
-            for i, (m0, m1) in enumerate(zip(allVectors[:-1], allVectors[1:])):
-                if len(m0) != len(m1):
-                    # We already reported this
-                    continue
-                if not m0:
-                    continue
-                costs = [[_vlen(_vdiff(v0, v1)) for v1 in m1] for v0 in m0]
-                matching, matching_cost = min_cost_perfect_bipartite_matching(costs)
-                if matching != list(range(len(m0))):
-                    add_problem(
-                        glyph_name,
-                        {
-                            "type": "contour_order",
-                            "master_1": names[i],
-                            "master_2": names[i + 1],
-                            "value_1": list(range(len(m0))),
-                            "value_2": matching,
-                        },
-                    )
-                    break
-                upem = 2048
-                item_cost = round(
-                    (matching_cost / len(m0) / len(m0[0])) ** 0.5 / upem * 100
-                )
-                hist.append(item_cost)
-                threshold = 7
-                if item_cost >= threshold:
-                    add_problem(
-                        glyph_name,
-                        {
-                            "type": "high_cost",
-                            "master_1": names[i],
-                            "master_2": names[i + 1],
-                            "value_1": item_cost,
-                            "value_2": threshold,
-                        },
-                    )
-
-        except ValueError as e:
-            add_problem(
-                glyph_name,
-                {"type": "math_error", "master": name, "error": e},
-            )
-    return problems
+			# Check each master against the next one in the list.
+			for i,(m0,m1) in enumerate(zip(allVectors[:-1],allVectors[1:])):
+				if len(m0) != len(m1):
+					print('%s: %s+%s: Glyphs not compatible!!!!!' % (glyph_name, names[i], names[i+1]))
+					continue
+				if not m0:
+					continue
+				costs = [[_vlen(_vdiff(v0,v1)) for v1 in m1] for v0 in m0]
+				matching, matching_cost = min_cost_perfect_bipartite_matching(costs)
+				if matching != list(range(len(m0))):
+					print('%s: %s+%s: Glyph has wrong contour/component order: %s' % (glyph_name, names[i], names[i+1], matching)) #, m0, m1)
+					break
+				upem = 2048
+				item_cost = round((matching_cost / len(m0) / len(m0[0])) ** .5 / upem * 100)
+				hist.append(item_cost)
+				threshold = 7
+				if item_cost >= threshold:
+					print('%s: %s+%s: Glyph has very high cost: %d%%' % (glyph_name, names[i], names[i+1], item_cost))
 
 
-def main(args=None):
-    """Test for interpolatability issues between fonts"""
-    import argparse
+		except ValueError as e:
+			print('%s: %s: math error %s; skipping glyph.' % (glyph_name, name, e))
+			print(contour.value)
+			#raise
+	#for x in hist:
+	#	print(x)
 
-    parser = argparse.ArgumentParser(
-        "fonttools varLib.interpolatable",
-        description=main.__doc__,
-    )
-    parser.add_argument(
-        "--json",
-        action="store_true",
-        help="Output report in JSON format",
-    )
-    parser.add_argument(
-        "inputs", metavar="FILE", type=str, nargs="+", help="Input TTF/UFO files"
-    )
+def main(args):
+	filenames = args
+	glyphs = None
+	#glyphs = ['uni08DB', 'uniFD76']
+	#glyphs = ['uni08DE', 'uni0034']
+	#glyphs = ['uni08DE', 'uni0034', 'uni0751', 'uni0753', 'uni0754', 'uni08A4', 'uni08A4.fina', 'uni08A5.fina']
 
-    args = parser.parse_args(args)
-    glyphs = None
-    # glyphs = ['uni08DB', 'uniFD76']
-    # glyphs = ['uni08DE', 'uni0034']
-    # glyphs = ['uni08DE', 'uni0034', 'uni0751', 'uni0753', 'uni0754', 'uni08A4', 'uni08A4.fina', 'uni08A5.fina']
+	from os.path import basename
+	names = [basename(filename).rsplit('.', 1)[0] for filename in filenames]
 
-    from os.path import basename
+	from fontTools.ttLib import TTFont
+	fonts = [TTFont(filename) for filename in filenames]
 
-    names = [basename(filename).rsplit(".", 1)[0] for filename in args.inputs]
+	glyphsets = [font.getGlyphSet() for font in fonts]
+	test(glyphsets, glyphs=glyphs, names=names)
 
-    fonts = []
-    for filename in args.inputs:
-        if filename.endswith(".ufo"):
-            from fontTools.ufoLib import UFOReader
-
-            fonts.append(UFOReader(filename))
-        else:
-            from fontTools.ttLib import TTFont
-
-            fonts.append(TTFont(filename))
-
-    glyphsets = [font.getGlyphSet() for font in fonts]
-    problems = test(glyphsets, glyphs=glyphs, names=names)
-    if args.json:
-        import json
-
-        print(json.dumps(problems))
-    else:
-        for glyph, glyph_problems in problems.items():
-            print(f"Glyph {glyph} was not compatible: ")
-            for p in glyph_problems:
-                if p["type"] == "missing":
-                    print("    Glyph was missing in master %s" % p["master"])
-                if p["type"] == "open_path":
-                    print("    Glyph has an open path in master %s" % p["master"])
-                if p["type"] == "path_count":
-                    print(
-                        "    Path count differs: %i in %s, %i in %s"
-                        % (p["value_1"], p["master_1"], p["value_2"], p["master_2"])
-                    )
-                if p["type"] == "node_count":
-                    print(
-                        "    Node count differs in path %i: %i in %s, %i in %s"
-                        % (
-                            p["path"],
-                            p["value_1"],
-                            p["master_1"],
-                            p["value_2"],
-                            p["master_2"],
-                        )
-                    )
-                if p["type"] == "node_incompatibility":
-                    print(
-                        "    Node %o incompatible in path %i: %s in %s, %s in %s"
-                        % (
-                            p["node"],
-                            p["path"],
-                            p["value_1"],
-                            p["master_1"],
-                            p["value_2"],
-                            p["master_2"],
-                        )
-                    )
-                if p["type"] == "contour_order":
-                    print(
-                        "    Contour order differs: %s in %s, %s in %s"
-                        % (
-                            p["value_1"],
-                            p["master_1"],
-                            p["value_2"],
-                            p["master_2"],
-                        )
-                    )
-                if p["type"] == "high_cost":
-                    print(
-                        "    Interpolation has high cost: cost of %s to %s = %i, threshold %i"
-                        % (
-                            p["master_1"],
-                            p["master_2"],
-                            p["value_1"],
-                            p["value_2"],
-                        )
-                    )
-    if problems:
-        return problems
-
-
-if __name__ == "__main__":
-    import sys
-
-    problems = main()
-    sys.exit(int(bool(problems)))
+if __name__ == '__main__':
+	import sys
+	main(sys.argv[1:])
diff --git a/Lib/fontTools/varLib/interpolate_layout.py b/Lib/fontTools/varLib/interpolate_layout.py
index 6d0385d..f252149 100644
--- a/Lib/fontTools/varLib/interpolate_layout.py
+++ b/Lib/fontTools/varLib/interpolate_layout.py
@@ -1,6 +1,8 @@
 """
 Interpolate OpenType Layout tables (GDEF / GPOS / GSUB).
 """
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.ttLib import TTFont
 from fontTools.varLib import models, VarLibError, load_designspace, load_masters
 from fontTools.varLib.merger import InstancerMerger
@@ -58,42 +60,29 @@
 
 
 def main(args=None):
-	"""Interpolate GDEF/GPOS/GSUB tables for a point on a designspace"""
 	from fontTools import configLogger
-	import argparse
+
 	import sys
+	if args is None:
+		args = sys.argv[1:]
 
-	parser = argparse.ArgumentParser(
-		"fonttools varLib.interpolate_layout",
-		description=main.__doc__,
-	)
-	parser.add_argument('designspace_filename', metavar='DESIGNSPACE',
-		help="Input TTF files")
-	parser.add_argument('locations', metavar='LOCATION', type=str, nargs='+',
-		help="Axis locations (e.g. wdth=120")
-	parser.add_argument('-o', '--output', metavar='OUTPUT',
-		help="Output font file (defaults to <designspacename>-instance.ttf)")
-	parser.add_argument('-l', '--loglevel', metavar='LEVEL', default="INFO",
-		help="Logging level (defaults to INFO)")
+	designspace_filename = args[0]
+	locargs = args[1:]
+	outfile = os.path.splitext(designspace_filename)[0] + '-instance.ttf'
 
-
-	args = parser.parse_args(args)
-
-	if not args.output:
-		args.output = os.path.splitext(args.designspace_filename)[0] + '-instance.ttf'
-
-	configLogger(level=args.loglevel)
+	# TODO: allow user to configure logging via command-line options
+	configLogger(level="INFO")
 
 	finder = lambda s: s.replace('master_ufo', 'master_ttf_interpolatable').replace('.ufo', '.ttf')
 
 	loc = {}
-	for arg in args.locations:
+	for arg in locargs:
 		tag,val = arg.split('=')
 		loc[tag] = float(val)
 
-	font = interpolate_layout(args.designspace_filename, loc, finder)
-	log.info("Saving font %s", args.output)
-	font.save(args.output)
+	font = interpolate_layout(designspace_filename, loc, finder)
+	log.info("Saving font %s", outfile)
+	font.save(outfile)
 
 
 if __name__ == "__main__":
diff --git a/Lib/fontTools/varLib/iup.py b/Lib/fontTools/varLib/iup.py
index 45a7a5e..fc36a9f 100644
--- a/Lib/fontTools/varLib/iup.py
+++ b/Lib/fontTools/varLib/iup.py
@@ -1,3 +1,8 @@
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
+from fontTools.misc.py23 import *
+
+
 def iup_segment(coords, rc1, rd1, rc2, rd2):
 	# rc1 = reference coord 1
 	# rd1 = reference delta 1
diff --git a/Lib/fontTools/varLib/merger.py b/Lib/fontTools/varLib/merger.py
index c9d1438..9b5af5c 100644
--- a/Lib/fontTools/varLib/merger.py
+++ b/Lib/fontTools/varLib/merger.py
@@ -1,10 +1,12 @@
 """
 Merge OpenType Layout tables (GDEF / GPOS / GSUB).
 """
+from __future__ import print_function, division, absolute_import
 import copy
 from operator import ior
+from fontTools.misc.py23 import *
+from fontTools.misc.fixedTools import otRound
 from fontTools.misc import classifyTools
-from fontTools.misc.roundTools import otRound
 from fontTools.ttLib.tables import otTables as ot
 from fontTools.ttLib.tables import otBase as otBase
 from fontTools.ttLib.tables.DefaultTable import DefaultTable
@@ -14,18 +16,6 @@
 from functools import reduce
 from fontTools.otlLib.builder import buildSinglePos
 
-from .errors import (
-    ShouldBeConstant,
-    FoundANone,
-    MismatchedTypes,
-    LengthsDiffer,
-    KeysDiffer,
-    InconsistentGlyphOrder,
-    InconsistentExtensions,
-    UnsupportedFormat,
-    UnsupportedFormat,
-    VarLibMergeError,
-)
 
 class Merger(object):
 
@@ -72,16 +62,9 @@
 		return _default
 
 	def mergeObjects(self, out, lst, exclude=()):
-		if hasattr(out, "ensureDecompiled"):
-			out.ensureDecompiled()
-		for item in lst:
-			if hasattr(item, "ensureDecompiled"):
-				item.ensureDecompiled()
 		keys = sorted(vars(out).keys())
-		if not all(keys == sorted(vars(v).keys()) for v in lst):
-			raise KeysDiffer(self, expected=keys,
-				got=[sorted(vars(v).keys()) for v in lst]
-			)
+		assert all(keys == sorted(vars(v).keys()) for v in lst), \
+			(keys, [sorted(vars(v).keys()) for v in lst])
 		mergers = self.mergersFor(out)
 		defaultMerger = mergers.get('*', self.__class__.mergeThings)
 		try:
@@ -91,47 +74,41 @@
 				values = [getattr(table, key) for table in lst]
 				mergerFunc = mergers.get(key, defaultMerger)
 				mergerFunc(self, value, values)
-		except VarLibMergeError as e:
-			e.stack.append('.'+key)
+		except Exception as e:
+			e.args = e.args + ('.'+key,)
 			raise
 
 	def mergeLists(self, out, lst):
-		if not allEqualTo(out, lst, len):
-			raise LengthsDiffer(self, expected=len(out), got=[len(x) for x in lst])
+		assert allEqualTo(out, lst, len), (len(out), [len(v) for v in lst])
 		for i,(value,values) in enumerate(zip(out, zip(*lst))):
 			try:
 				self.mergeThings(value, values)
-			except VarLibMergeError as e:
-				e.stack.append('[%d]' % i)
+			except Exception as e:
+				e.args = e.args + ('[%d]' % i,)
 				raise
 
 	def mergeThings(self, out, lst):
-		if not allEqualTo(out, lst, type):
-			raise MismatchedTypes(self,
-					expected=type(out).__name__,
-					got=[type(x).__name__ for x in lst]
-			)
-		mergerFunc = self.mergersFor(out).get(None, None)
-		if mergerFunc is not None:
-			mergerFunc(self, out, lst)
-		elif hasattr(out, '__dict__'):
-			self.mergeObjects(out, lst)
-		elif isinstance(out, list):
-			self.mergeLists(out, lst)
-		else:
-			if not allEqualTo(out, lst):
-				raise ShouldBeConstant(self, expected=out, got=lst)
+		try:
+			assert allEqualTo(out, lst, type), (out, lst)
+			mergerFunc = self.mergersFor(out).get(None, None)
+			if mergerFunc is not None:
+				mergerFunc(self, out, lst)
+			elif hasattr(out, '__dict__'):
+				self.mergeObjects(out, lst)
+			elif isinstance(out, list):
+				self.mergeLists(out, lst)
+			else:
+				assert allEqualTo(out, lst), (out, lst)
+		except Exception as e:
+			e.args = e.args + (type(out).__name__,)
+			raise
 
 	def mergeTables(self, font, master_ttfs, tableTags):
+
 		for tag in tableTags:
 			if tag not in font: continue
-			try:
-				self.ttfs = [m for m in master_ttfs if tag in m]
-				self.mergeThings(font[tag], [m[tag] if tag in m else None
-							     for m in master_ttfs])
-			except VarLibMergeError as e:
-				e.stack.append(tag)
-				raise
+			self.mergeThings(font[tag], [m[tag] if tag in m else None
+						     for m in master_ttfs])
 
 #
 # Aligning merger
@@ -142,8 +119,7 @@
 @AligningMerger.merger(ot.GDEF, "GlyphClassDef")
 def merge(merger, self, lst):
 	if self is None:
-		if not allNone(lst):
-			raise NotANone(self, expected=None, got=lst)
+		assert allNone(lst), (lst)
 		return
 
 	lst = [l.classDefs for l in lst]
@@ -155,8 +131,7 @@
 	allKeys.update(*[l.keys() for l in lst])
 	for k in allKeys:
 		allValues = nonNone(l.get(k) for l in lst)
-		if not allEqual(allValues):
-			raise ShouldBeConstant(self, expected=allValues[0], got=lst, stack="."+k)
+		assert allEqual(allValues), allValues
 		if not allValues:
 			self[k] = None
 		else:
@@ -169,7 +144,7 @@
 	ret.Format = 2
 	ret.Coverage = self.Coverage
 	ret.ValueFormat = self.ValueFormat
-	ret.Value = [self.Value for _ in ret.Coverage.glyphs]
+	ret.Value = [self.Value for g in ret.Coverage.glyphs]
 	ret.ValueCount = len(ret.Value)
 
 	return ret
@@ -192,8 +167,7 @@
 	sortKey = font.getReverseGlyphMap().__getitem__
 	order = sorted(combined, key=sortKey)
 	# Make sure all input glyphsets were in proper order
-	if not all(sorted(vs, key=sortKey) == vs for vs in lst):
-		raise InconsistentGlyphOrder(self)
+	assert all(sorted(vs, key=sortKey) == vs for vs in lst)
 	del combined
 
 	paddedValues = None
@@ -220,7 +194,7 @@
 		elif self.Format == 2:
 			return self.Value[self.Coverage.glyphs.index(glyph)]
 		else:
-			raise UnsupportedFormat(self, subtable="single positioning lookup")
+			assert 0
 	return None
 
 def _Lookup_PairPos_get_effective_value_pair(subtables, firstGlyph, secondGlyph):
@@ -242,14 +216,13 @@
 			klass2 = self.ClassDef2.classDefs.get(secondGlyph, 0)
 			return self.Class1Record[klass1].Class2Record[klass2]
 		else:
-			raise UnsupportedFormat(self, subtable="pair positioning lookup")
+			assert 0
 	return None
 
 @AligningMerger.merger(ot.SinglePos)
 def merge(merger, self, lst):
 	self.ValueFormat = valueFormat = reduce(int.__or__, [l.ValueFormat for l in lst], 0)
-	if not (len(lst) == 1 or (valueFormat & ~0xF == 0)):
-		raise UnsupportedFormat(self, subtable="single positioning lookup")
+	assert len(lst) == 1 or (valueFormat & ~0xF == 0), valueFormat
 
 	# If all have same coverage table and all are format 1,
 	coverageGlyphs = self.Coverage.glyphs
@@ -269,7 +242,7 @@
 					    [v.Value for v in lst])
 
 	self.Coverage.glyphs = glyphs
-	self.Value = [otBase.ValueRecord(valueFormat) for _ in glyphs]
+	self.Value = [otBase.ValueRecord(valueFormat) for g in glyphs]
 	self.ValueCount = len(self.Value)
 
 	for i,values in enumerate(padded):
@@ -348,7 +321,7 @@
 					    default=empty)
 
 	self.Coverage.glyphs = glyphs
-	self.PairSet = [ot.PairSet() for _ in glyphs]
+	self.PairSet = [ot.PairSet() for g in glyphs]
 	self.PairSetCount = len(self.PairSet)
 	for glyph, ps in zip(glyphs, self.PairSet):
 		ps._firstGlyph = glyph
@@ -409,12 +382,28 @@
 
 	return self, classes
 
+# It's stupid that we need to do this here.  Just need to, to match test
+# expecatation results, since ttx prints out format of ClassDef (and Coverage)
+# even though it should not.
+def _ClassDef_calculate_Format(self, font):
+	fmt = 2
+	ranges = self._getClassRanges(font)
+	if ranges:
+		startGlyph = ranges[0][1]
+		endGlyph = ranges[-1][3]
+		glyphCount = endGlyph - startGlyph + 1
+		if len(ranges) * 3 >= glyphCount + 1:
+			# Format 1 is more compact
+			fmt = 1
+	self.Format = fmt
+
 def _PairPosFormat2_align_matrices(self, lst, font, transparent=False):
 
 	matrices = [l.Class1Record for l in lst]
 
 	# Align first classes
 	self.ClassDef1, classes = _ClassDef_merge_classify([l.ClassDef1 for l in lst], [l.Coverage.glyphs for l in lst])
+	_ClassDef_calculate_Format(self.ClassDef1, font)
 	self.Class1Count = len(classes)
 	new_matrices = []
 	for l,matrix in zip(lst, matrices):
@@ -453,6 +442,7 @@
 
 	# Align second classes
 	self.ClassDef2, classes = _ClassDef_merge_classify([l.ClassDef2 for l in lst])
+	_ClassDef_calculate_Format(self.ClassDef2, font)
 	self.Class2Count = len(classes)
 	new_matrices = []
 	for l,matrix in zip(lst, matrices):
@@ -518,7 +508,7 @@
 	elif self.Format == 2:
 		_PairPosFormat2_merge(self, lst, merger)
 	else:
-		raise UnsupportedFormat(self, subtable="pair positioning lookup")
+		assert False
 
 	del merger.valueFormat1, merger.valueFormat2
 
@@ -583,8 +573,8 @@
 		# failures in that case will probably signify mistakes in the
 		# input masters.
 
-		if not allEqual(allClasses):
-			raise allClasses(self, allClasses)
+		assert allEqual(allClasses), allClasses
+		if not allClasses:
 			rec = None
 		else:
 			rec = ot.MarkRecord()
@@ -632,33 +622,25 @@
 
 @AligningMerger.merger(ot.MarkBasePos)
 def merge(merger, self, lst):
-	if not allEqualTo(self.Format, (l.Format for l in lst)):
-		raise InconsistentFormats(self,
-			subtable="mark-to-base positioning lookup",
-			expected=self.Format,
-			got=[l.Format for l in lst]
-		)
+	assert allEqualTo(self.Format, (l.Format for l in lst))
 	if self.Format == 1:
 		_MarkBasePosFormat1_merge(self, lst, merger)
 	else:
-		raise UnsupportedFormat(self, subtable="mark-to-base positioning lookup")
+		assert False
 
 @AligningMerger.merger(ot.MarkMarkPos)
 def merge(merger, self, lst):
-	if not allEqualTo(self.Format, (l.Format for l in lst)):
-		raise InconsistentFormats(self,
-			subtable="mark-to-mark positioning lookup",
-			expected=self.Format,
-			got=[l.Format for l in lst]
-		)
+	assert allEqualTo(self.Format, (l.Format for l in lst))
 	if self.Format == 1:
 		_MarkBasePosFormat1_merge(self, lst, merger, 'Mark1', 'Mark2')
 	else:
-		raise UnsupportedFormat(self, subtable="mark-to-mark positioning lookup")
+		assert False
+
 
 def _PairSet_flatten(lst, font):
 	self = ot.PairSet()
 	self.Coverage = ot.Coverage()
+	self.Coverage.Format = 1
 
 	# Align them
 	glyphs, padded = _merge_GlyphOrders(font,
@@ -684,6 +666,7 @@
 	self = ot.PairPos()
 	self.Format = 1
 	self.Coverage = ot.Coverage()
+	self.Coverage.Format = 1
 	self.ValueFormat1 = reduce(int.__or__, [l.ValueFormat1 for l in lst], 0)
 	self.ValueFormat2 = reduce(int.__or__, [l.ValueFormat2 for l in lst], 0)
 
@@ -704,6 +687,7 @@
 	self = ot.PairPos()
 	self.Format = 2
 	self.Coverage = ot.Coverage()
+	self.Coverage.Format = 1
 	self.ValueFormat1 = reduce(int.__or__, [l.ValueFormat1 for l in lst], 0)
 	self.ValueFormat2 = reduce(int.__or__, [l.ValueFormat2 for l in lst], 0)
 
@@ -779,13 +763,8 @@
 		if not sts:
 			continue
 		if sts[0].__class__.__name__.startswith('Extension'):
-			if not allEqual([st.__class__ for st in sts]):
-				raise InconsistentExtensions(self,
-					expected="Extension",
-					got=[st.__class__.__name__ for st in sts]
-				)
-			if not allEqual([st.ExtensionLookupType for st in sts]):
-				raise InconsistentExtensions(self)
+			assert allEqual([st.__class__ for st in sts])
+			assert allEqual([st.ExtensionLookupType for st in sts])
 			l.LookupType = sts[0].ExtensionLookupType
 			new_sts = [st.ExtSubTable for st in sts]
 			del sts[:]
@@ -1013,8 +992,7 @@
 		masterModel = None
 		if None in lst:
 			if allNone(lst):
-				if out is not None:
-					raise FoundANone(self, got=lst)
+				assert out is None, (out, lst)
 				return
 			masterModel = self.model
 			model, lst = masterModel.getSubModel(lst)
@@ -1032,19 +1010,9 @@
 	base, varIdx = store_builder.storeMasters(master_values)
 	return base, builder.buildVarDevTable(varIdx)
 
-@VariationMerger.merger(ot.BaseCoord)
-def merge(merger, self, lst):
-	if self.Format != 1:
-		raise UnsupportedFormat(self, subtable="a baseline coordinate")
-	self.Coordinate, DeviceTable = buildVarDevTable(merger.store_builder, [a.Coordinate for a in lst])
-	if DeviceTable:
-		self.Format = 3
-		self.DeviceTable = DeviceTable
-
 @VariationMerger.merger(ot.CaretValue)
 def merge(merger, self, lst):
-	if self.Format != 1:
-		raise UnsupportedFormat(self, subtable="a caret")
+	assert self.Format == 1
 	self.Coordinate, DeviceTable = buildVarDevTable(merger.store_builder, [a.Coordinate for a in lst])
 	if DeviceTable:
 		self.Format = 3
@@ -1052,8 +1020,7 @@
 
 @VariationMerger.merger(ot.Anchor)
 def merge(merger, self, lst):
-	if self.Format != 1:
-		raise UnsupportedFormat(self, subtable="an anchor")
+	assert self.Format == 1
 	self.XCoordinate, XDeviceTable = buildVarDevTable(merger.store_builder, [a.XCoordinate for a in lst])
 	self.YCoordinate, YDeviceTable = buildVarDevTable(merger.store_builder, [a.YCoordinate for a in lst])
 	if XDeviceTable or YDeviceTable:
diff --git a/Lib/fontTools/varLib/models.py b/Lib/fontTools/varLib/models.py
index 9296ded..9d969d7 100644
--- a/Lib/fontTools/varLib/models.py
+++ b/Lib/fontTools/varLib/models.py
@@ -1,13 +1,12 @@
 """Variation fonts interpolation models."""
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 
 __all__ = ['nonNone', 'allNone', 'allEqual', 'allEqualTo', 'subList',
 	   'normalizeValue', 'normalizeLocation',
 	   'supportScalar',
 	   'VariationModel']
 
-from fontTools.misc.roundTools import noRound
-from .errors import VariationModelError
-
 
 def nonNone(lst):
 	return [l for l in lst if l is not None]
@@ -46,11 +45,7 @@
 	0.5
 	"""
 	lower, default, upper = triple
-	if not (lower <= default <= upper):
-		raise ValueError(
-			f"Invalid axis values, must be minimum, default, maximum: "
-			f"{lower:3.3f}, {default:3.3f}, {upper:3.3f}"
-		)
+	assert lower <= default <= upper, "invalid axis values: %3.3f, %3.3f %3.3f"%(lower, default, upper)
 	v = max(min(v, upper), lower)
 	if v == default:
 		v = 0.
@@ -144,7 +139,7 @@
 			continue
 		if v <= lower or upper <= v:
 			scalar = 0.
-			break
+			break;
 		if v < peak:
 			scalar *= (v - lower) / (peak - lower)
 		else: # v > peak
@@ -199,7 +194,7 @@
 
 	def __init__(self, locations, axisOrder=None):
 		if len(set(tuple(sorted(l.items())) for l in locations)) != len(locations):
-			raise VariationModelError("Locations must be unique.")
+			raise ValueError("locations must be unique")
 
 		self.origLocations = locations
 		self.axisOrder = axisOrder if axisOrder is not None else []
@@ -227,8 +222,7 @@
 
 	@staticmethod
 	def getMasterLocationsSortKeyFunc(locations, axisOrder=[]):
-		if {} not in locations:
-			raise VariationModelError("Base master not found.")
+		assert {} in locations, "Base master not found."
 		axisPoints = {}
 		for loc in locations:
 			if len(loc) != 1:
@@ -247,11 +241,7 @@
 				return -1 if v < 0 else +1 if v > 0 else 0
 			def key(loc):
 				rank = len(loc)
-				onPointAxes = [
-					axis for axis, value in loc.items()
-					if axis in axisPoints
-					and value in axisPoints[axis]
-				]
+				onPointAxes = [axis for axis,value in loc.items() if value in axisPoints[axis]]
 				orderedAxes = [axis for axis in axisOrder if axis in loc]
 				orderedAxes.extend([axis for axis in sorted(loc.keys()) if axis not in axisOrder])
 				return (
@@ -282,18 +272,34 @@
 
 	def _computeMasterSupports(self, axisPoints):
 		supports = []
-		regions = self._locationsToRegions()
-		for i,region in enumerate(regions):
-			locAxes = set(region.keys())
+		deltaWeights = []
+		locations = self.locations
+		# Compute min/max across each axis, use it as total range.
+		# TODO Take this as input from outside?
+		minV = {}
+		maxV = {}
+		for l in locations:
+			for k,v in l.items():
+				minV[k] = min(v, minV.get(k, v))
+				maxV[k] = max(v, maxV.get(k, v))
+		for i,loc in enumerate(locations):
+			box = {}
+			for axis,locV in loc.items():
+				if locV > 0:
+					box[axis] = (0, locV, maxV[axis])
+				else:
+					box[axis] = (minV[axis], locV, 0)
+
+			locAxes = set(loc.keys())
 			# Walk over previous masters now
-			for j,prev_region in enumerate(regions[:i]):
+			for j,m in enumerate(locations[:i]):
 				# Master with extra axes do not participte
-				if not set(prev_region.keys()).issubset(locAxes):
+				if not set(m.keys()).issubset(locAxes):
 					continue
 				# If it's NOT in the current box, it does not participate
 				relevant = True
-				for axis, (lower,peak,upper) in region.items():
-					if axis not in prev_region or not (prev_region[axis][1] == peak or lower < prev_region[axis][1] < upper):
+				for axis, (lower,peak,upper) in box.items():
+					if axis not in m or not (m[axis] == peak or lower < m[axis] < upper):
 						relevant = False
 						break
 				if not relevant:
@@ -308,10 +314,10 @@
 
 				bestAxes = {}
 				bestRatio = -1
-				for axis in prev_region.keys():
-					val = prev_region[axis][1]
-					assert axis in region
-					lower,locV,upper = region[axis]
+				for axis in m.keys():
+					val = m[axis]
+					assert axis in box
+					lower,locV,upper = box[axis]
 					newLower, newUpper = lower, upper
 					if val < locV:
 						newLower = val
@@ -329,46 +335,21 @@
 						bestAxes[axis] = (newLower, locV, newUpper)
 
 				for axis,triple in bestAxes.items ():
-					region[axis] = triple
-			supports.append(region)
-		self.supports = supports
-		self._computeDeltaWeights()
+					box[axis] = triple
+			supports.append(box)
 
-	def _locationsToRegions(self):
-		locations = self.locations
-		# Compute min/max across each axis, use it as total range.
-		# TODO Take this as input from outside?
-		minV = {}
-		maxV = {}
-		for l in locations:
-			for k,v in l.items():
-				minV[k] = min(v, minV.get(k, v))
-				maxV[k] = max(v, maxV.get(k, v))
-
-		regions = []
-		for i,loc in enumerate(locations):
-			region = {}
-			for axis,locV in loc.items():
-				if locV > 0:
-					region[axis] = (0, locV, maxV[axis])
-				else:
-					region[axis] = (minV[axis], locV, 0)
-			regions.append(region)
-		return regions
-
-	def _computeDeltaWeights(self):
-		deltaWeights = []
-		for i,loc in enumerate(self.locations):
 			deltaWeight = {}
 			# Walk over previous masters now, populate deltaWeight
-			for j,m in enumerate(self.locations[:i]):
-				scalar = supportScalar(loc, self.supports[j])
+			for j,m in enumerate(locations[:i]):
+				scalar = supportScalar(loc, supports[j])
 				if scalar:
 					deltaWeight[j] = scalar
 			deltaWeights.append(deltaWeight)
+
+		self.supports = supports
 		self.deltaWeights = deltaWeights
 
-	def getDeltas(self, masterValues, *, round=noRound):
+	def getDeltas(self, masterValues):
 		assert len(masterValues) == len(self.deltaWeights)
 		mapping = self.reverseMapping
 		out = []
@@ -376,12 +357,12 @@
 			delta = masterValues[mapping[i]]
 			for j,weight in weights.items():
 				delta -= out[j] * weight
-			out.append(round(delta))
+			out.append(delta)
 		return out
 
-	def getDeltasAndSupports(self, items, *, round=noRound):
+	def getDeltasAndSupports(self, items):
 		model, items = self.getSubModel(items)
-		return model.getDeltas(items, round=round), model.supports
+		return model.getDeltas(items), model.supports
 
 	def getScalars(self, loc):
 		return [supportScalar(loc, support) for support in self.supports]
@@ -390,7 +371,7 @@
 	def interpolateFromDeltasAndScalars(deltas, scalars):
 		v = None
 		assert len(deltas) == len(scalars)
-		for delta, scalar in zip(deltas, scalars):
+		for i,(delta,scalar) in enumerate(zip(deltas, scalars)):
 			if not scalar: continue
 			contribution = delta * scalar
 			if v is None:
@@ -403,12 +384,12 @@
 		scalars = self.getScalars(loc)
 		return self.interpolateFromDeltasAndScalars(deltas, scalars)
 
-	def interpolateFromMasters(self, loc, masterValues, *, round=noRound):
-		deltas = self.getDeltas(masterValues, round=round)
+	def interpolateFromMasters(self, loc, masterValues):
+		deltas = self.getDeltas(masterValues)
 		return self.interpolateFromDeltas(loc, deltas)
 
-	def interpolateFromMastersAndScalars(self, masterValues, scalars, *, round=noRound):
-		deltas = self.getDeltas(masterValues, round=round)
+	def interpolateFromMastersAndScalars(self, masterValues, scalars):
+		deltas = self.getDeltas(masterValues)
 		return self.interpolateFromDeltasAndScalars(deltas, scalars)
 
 
@@ -432,32 +413,26 @@
 	return va + (vb - va) * (v - a) / (b - a)
 
 
-def main(args=None):
-	"""Normalize locations on a given designspace"""
+def main(args):
 	from fontTools import configLogger
-	import argparse
 
-	parser = argparse.ArgumentParser(
-		"fonttools varLib.models",
-		description=main.__doc__,
-	)
-	parser.add_argument('--loglevel', metavar='LEVEL', default="INFO",
-		help="Logging level (defaults to INFO)")
+	args = args[1:]
 
-	group = parser.add_mutually_exclusive_group(required=True)
-	group.add_argument('-d', '--designspace',metavar="DESIGNSPACE",type=str)
-	group.add_argument('-l', '--locations', metavar='LOCATION', nargs='+',
-		help="Master locations as comma-separate coordinates. One must be all zeros.")
+	# TODO: allow user to configure logging via command-line options
+	configLogger(level="INFO")
 
-	args = parser.parse_args(args)
+	if len(args) < 1:
+		print("usage: fonttools varLib.models source.designspace", file=sys.stderr)
+		print("  or")
+		print("usage: fonttools varLib.models location1 location2 ...", file=sys.stderr)
+		sys.exit(1)
 
-	configLogger(level=args.loglevel)
 	from pprint import pprint
 
-	if args.designspace:
+	if len(args) == 1 and args[0].endswith('.designspace'):
 		from fontTools.designspaceLib import DesignSpaceDocument
 		doc = DesignSpaceDocument()
-		doc.read(args.designspace)
+		doc.read(args[0])
 		locs = [s.location for s in doc.sources]
 		print("Original locations:")
 		pprint(locs)
@@ -467,7 +442,7 @@
 		pprint(locs)
 	else:
 		axes = [chr(c) for c in range(ord('A'), ord('Z')+1)]
-		locs = [dict(zip(axes, (float(v) for v in s.split(',')))) for s in args.locations]
+		locs = [dict(zip(axes, (float(v) for v in s.split(',')))) for s in args]
 
 	model = VariationModel(locs)
 	print("Sorted locations:")
@@ -479,6 +454,6 @@
 	import doctest, sys
 
 	if len(sys.argv) > 1:
-		sys.exit(main())
+		sys.exit(main(sys.argv))
 
 	sys.exit(doctest.testmod().failed)
diff --git a/Lib/fontTools/varLib/mutator.py b/Lib/fontTools/varLib/mutator.py
index 02ce442..aba3271 100644
--- a/Lib/fontTools/varLib/mutator.py
+++ b/Lib/fontTools/varLib/mutator.py
@@ -3,8 +3,9 @@
 
 $ fonttools varLib.mutator ./NotoSansArabic-VF.ttf wght=140 wdth=85
 """
-from fontTools.misc.fixedTools import floatToFixedToFloat, floatToFixed
-from fontTools.misc.roundTools import otRound
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools.misc.fixedTools import floatToFixedToFloat, otRound, floatToFixed
 from fontTools.pens.boundsPen import BoundsPen
 from fontTools.ttLib import TTFont, newTable
 from fontTools.ttLib.tables import ttProgram
@@ -21,7 +22,6 @@
 import fontTools.subset.cff
 import os.path
 import logging
-from io import BytesIO
 
 
 log = logging.getLogger("fontTools.varlib.mutator")
@@ -139,7 +139,7 @@
 			lsb_delta = 0
 		else:
 			lsb = boundsPen.bounds[0]
-			lsb_delta = entry[1] - lsb
+		lsb_delta = entry[1] - lsb
 
 		if lsb_delta or width_delta:
 			if width_delta:
@@ -258,7 +258,7 @@
 		if not tableTag in varfont:
 			continue
 		table = varfont[tableTag].table
-		if not getattr(table, 'FeatureVariations', None):
+		if not hasattr(table, 'FeatureVariations'):
 			continue
 		variations = table.FeatureVariations
 		for record in variations.FeatureVariationRecord:
@@ -346,8 +346,14 @@
 		# Change maxp attributes as IDEF is added
 		if 'maxp' in varfont:
 			maxp = varfont['maxp']
-			setattr(maxp, "maxInstructionDefs", 1 + getattr(maxp, "maxInstructionDefs", 0))
-			setattr(maxp, "maxStackElements", max(len(loc), getattr(maxp, "maxStackElements", 0)))
+			if hasattr(maxp, "maxInstructionDefs"):
+				maxp.maxInstructionDefs += 1
+			else:
+				setattr(maxp, "maxInstructionDefs", 1)
+			if hasattr(maxp, "maxStackElements"):
+				maxp.maxStackElements = max(len(loc), maxp.maxStackElements)
+			else:
+				setattr(maxp, "maxInstructionDefs", len(loc))
 
 	if 'name' in varfont:
 		log.info("Pruning name table")
@@ -394,7 +400,6 @@
 
 
 def main(args=None):
-	"""Instantiate a variation font"""
 	from fontTools import configLogger
 	import argparse
 
diff --git a/Lib/fontTools/varLib/mvar.py b/Lib/fontTools/varLib/mvar.py
index 8b1355b..92083dd 100644
--- a/Lib/fontTools/varLib/mvar.py
+++ b/Lib/fontTools/varLib/mvar.py
@@ -1,3 +1,7 @@
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
+from fontTools.misc.py23 import *
+
 MVAR_ENTRIES = {
 	'hasc': ('OS/2', 'sTypoAscender'),		 # horizontal ascender
 	'hdsc': ('OS/2', 'sTypoDescender'),		 # horizontal descender
diff --git a/Lib/fontTools/varLib/plot.py b/Lib/fontTools/varLib/plot.py
index 811559f..6b13416 100644
--- a/Lib/fontTools/varLib/plot.py
+++ b/Lib/fontTools/varLib/plot.py
@@ -1,9 +1,11 @@
 """Visualize DesignSpaceDocument and resulting VariationModel."""
 
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.varLib.models import VariationModel, supportScalar
 from fontTools.designspaceLib import DesignSpaceDocument
-from matplotlib import pyplot
 from mpl_toolkits.mplot3d import axes3d
+from matplotlib import pyplot
 from itertools import cycle
 import math
 import logging
@@ -68,10 +70,10 @@
 
 
 def _plotLocations2D(model, axis, fig, cols, rows, names, **kwargs):
-	subplot = fig.add_subplot(111)
 	for i, (support, color, name) in enumerate(
 		zip(model.supports, cycle(pyplot.cm.Set1.colors), cycle(names))
 	):
+		subplot = fig.add_subplot(rows, cols, i + 1)
 		if name is not None:
 			subplot.set_title(name)
 		subplot.set_xlabel(axis)
@@ -91,10 +93,10 @@
 def _plotLocations3D(model, axes, fig, rows, cols, names, **kwargs):
 	ax1, ax2 = axes
 
-	axis3D = fig.add_subplot(111, projection='3d')
 	for i, (support, color, name) in enumerate(
 		zip(model.supports, cycle(pyplot.cm.Set1.colors), cycle(names))
 	):
+		axis3D = fig.add_subplot(rows, cols, i + 1, projection='3d')
 		if name is not None:
 			axis3D.set_title(name)
 		axis3D.set_xlabel(ax1)
diff --git a/Lib/fontTools/varLib/varStore.py b/Lib/fontTools/varLib/varStore.py
index 8a382df..d9d48a5 100644
--- a/Lib/fontTools/varLib/varStore.py
+++ b/Lib/fontTools/varLib/varStore.py
@@ -1,4 +1,6 @@
-from fontTools.misc.roundTools import noRound, otRound
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools.misc.fixedTools import otRound
 from fontTools.ttLib.tables import otTables as ot
 from fontTools.varLib.models import supportScalar
 from fontTools.varLib.builder import (buildVarRegionList, buildVarStore,
@@ -68,7 +70,7 @@
 			self._outer = varDataIdx
 			self._data = self._store.VarData[varDataIdx]
 			self._cache = self._varDataCaches[key]
-			if len(self._data.Item) == 0xFFFF:
+			if len(self._data.Item) == 0xFFF:
 				# This is full.  Need new one.
 				varDataIdx = None
 
@@ -83,12 +85,15 @@
 
 
 	def storeMasters(self, master_values):
-		deltas = self._model.getDeltas(master_values, round=round)
-		base = deltas.pop(0)
-		return base, self.storeDeltas(deltas, round=noRound)
+		deltas = self._model.getDeltas(master_values)
+		base = otRound(deltas.pop(0))
+		return base, self.storeDeltas(deltas)
 
-	def storeDeltas(self, deltas, *, round=round):
-		deltas = [round(d) for d in deltas]
+	def storeDeltas(self, deltas):
+		# Pity that this exists here, since VarData_addItem
+		# does the same.  But to look into our cache, it's
+		# good to adjust deltas here as well...
+		deltas = [otRound(d) for d in deltas]
 		if len(deltas) == len(self._supports) + 1:
 			deltas = tuple(deltas[1:])
 		else:
@@ -106,14 +111,14 @@
 			# Full array. Start new one.
 			self._add_VarData()
 			return self.storeDeltas(deltas)
-		self._data.addItem(deltas, round=noRound)
+		self._data.addItem(deltas)
 
 		varIdx = (self._outer << 16) + inner
 		self._cache[deltas] = varIdx
 		return varIdx
 
-def VarData_addItem(self, deltas, *, round=round):
-	deltas = [round(d) for d in deltas]
+def VarData_addItem(self, deltas):
+	deltas = [otRound(d) for d in deltas]
 
 	countUs = self.VarRegionCount
 	countThem = len(deltas)
@@ -542,13 +547,12 @@
 
 
 def main(args=None):
-	"""Optimize a font's GDEF variation store"""
 	from argparse import ArgumentParser
 	from fontTools import configLogger
 	from fontTools.ttLib import TTFont
 	from fontTools.ttLib.tables.otBase import OTTableWriter
 
-	parser = ArgumentParser(prog='varLib.varStore', description= main.__doc__)
+	parser = ArgumentParser(prog='varLib.varStore')
 	parser.add_argument('fontfile')
 	parser.add_argument('outfile', nargs='?')
 	options = parser.parse_args(args)
diff --git a/Lib/fontTools/voltLib/ast.py b/Lib/fontTools/voltLib/ast.py
index 3a1f4a0..1ce4781 100644
--- a/Lib/fontTools/voltLib/ast.py
+++ b/Lib/fontTools/voltLib/ast.py
@@ -1,58 +1,48 @@
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
 from fontTools.voltLib.error import VoltLibError
-from typing import NamedTuple
 
 
-class Pos(NamedTuple):
-    adv: int
-    dx: int
-    dy: int
-    adv_adjust_by: dict
-    dx_adjust_by: dict
-    dy_adjust_by: dict
-
-    def __str__(self):
-        res = ' POS'
-        for attr in ('adv', 'dx', 'dy'):
-            value = getattr(self, attr)
-            if value is not None:
-                res += f' {attr.upper()} {value}'
-                adjust_by = getattr(self, f'{attr}_adjust_by', {})
-                for size, adjustment in adjust_by.items():
-                    res += f' ADJUST_BY {adjustment} AT {size}'
-        res += ' END_POS'
-        return res
-
-
-class Element(object):
+class Statement(object):
     def __init__(self, location=None):
         self.location = location
 
     def build(self, builder):
         pass
 
-    def __str__(self):
-        raise NotImplementedError
+
+class Expression(object):
+    def __init__(self, location=None):
+        self.location = location
+
+    def build(self, builder):
+        pass
 
 
-class Statement(Element):
-    pass
-
-
-class Expression(Element):
-    pass
-
-
-class VoltFile(Statement):
-    def __init__(self):
-        Statement.__init__(self, location=None)
+class Block(Statement):
+    def __init__(self, location=None):
+        Statement.__init__(self, location)
         self.statements = []
 
     def build(self, builder):
         for s in self.statements:
             s.build(builder)
 
-    def __str__(self):
-        return '\n' + '\n'.join(str(s) for s in self.statements) + ' END\n'
+
+class VoltFile(Block):
+    def __init__(self):
+        Block.__init__(self, location=None)
+
+
+class LookupBlock(Block):
+    def __init__(self, name, location=None):
+        Block.__init__(self, location)
+        self.name = name
+
+    def build(self, builder):
+        builder.start_lookup_block(self.location, self.name)
+        Block.build(self, builder)
+        builder.end_lookup_block()
 
 
 class GlyphDefinition(Statement):
@@ -64,21 +54,6 @@
         self.type = gtype
         self.components = components
 
-    def __str__(self):
-        res = f'DEF_GLYPH "{self.name}" ID {self.id}'
-        if self.unicode is not None:
-            if len(self.unicode) > 1:
-                unicodes = ','.join(f'U+{u:04X}' for u in self.unicode)
-                res += f' UNICODEVALUES "{unicodes}"'
-            else:
-                res += f' UNICODE {self.unicode[0]}'
-        if self.type is not None:
-            res += f' TYPE {self.type}'
-        if self.components is not None:
-            res += f' COMPONENTS {self.components}'
-        res += ' END_GLYPH'
-        return res
-
 
 class GroupDefinition(Statement):
     def __init__(self, name, enum, location=None):
@@ -100,10 +75,6 @@
             self.glyphs_ = self.enum.glyphSet(groups)
         return self.glyphs_
 
-    def __str__(self):
-        enum = self.enum and str(self.enum) or ''
-        return f'DEF_GROUP "{self.name}"\n{enum}\nEND_GROUP'
-
 
 class GlyphName(Expression):
     """A single glyph name, such as cedilla."""
@@ -114,9 +85,6 @@
     def glyphSet(self):
         return (self.glyph,)
 
-    def __str__(self):
-        return f' GLYPH "{self.glyph}"'
-
 
 class Enum(Expression):
     """An enum"""
@@ -137,10 +105,6 @@
                 glyphs.extend(element.glyphSet())
         return tuple(glyphs)
 
-    def __str__(self):
-        enum = ''.join(str(e) for e in self.enum)
-        return f' ENUM{enum} END_ENUM'
-
 
 class GroupName(Expression):
     """A glyph group"""
@@ -159,9 +123,6 @@
                 'Group "%s" is used but undefined.' % (self.group),
                 self.location)
 
-    def __str__(self):
-        return f' GROUP "{self.group}"'
-
 
 class Range(Expression):
     """A glyph range"""
@@ -174,9 +135,6 @@
     def glyphSet(self):
         return tuple(self.parser.glyph_range(self.start, self.end))
 
-    def __str__(self):
-        return f' RANGE "{self.start}" TO "{self.end}"'
-
 
 class ScriptDefinition(Statement):
     def __init__(self, name, tag, langs, location=None):
@@ -185,16 +143,6 @@
         self.tag = tag
         self.langs = langs
 
-    def __str__(self):
-        res = 'DEF_SCRIPT'
-        if self.name is not None:
-            res += f' NAME "{self.name}"'
-        res += f' TAG "{self.tag}"\n\n'
-        for lang in self.langs:
-            res += f'{lang}'
-        res += 'END_SCRIPT'
-        return res
-
 
 class LangSysDefinition(Statement):
     def __init__(self, name, tag, features, location=None):
@@ -203,16 +151,6 @@
         self.tag = tag
         self.features = features
 
-    def __str__(self):
-        res = 'DEF_LANGSYS'
-        if self.name is not None:
-            res += f' NAME "{self.name}"'
-        res += f' TAG "{self.tag}"\n\n'
-        for feature in self.features:
-            res += f'{feature}'
-        res += 'END_LANGSYS\n'
-        return res
-
 
 class FeatureDefinition(Statement):
     def __init__(self, name, tag, lookups, location=None):
@@ -221,12 +159,6 @@
         self.tag = tag
         self.lookups = lookups
 
-    def __str__(self):
-        res = f'DEF_FEATURE NAME "{self.name}" TAG "{self.tag}"\n'
-        res += ' ' + ' '.join(f'LOOKUP "{l}"' for l in self.lookups) + '\n'
-        res += 'END_FEATURE\n'
-        return res
-
 
 class LookupDefinition(Statement):
     def __init__(self, name, process_base, process_marks, mark_glyph_set,
@@ -244,51 +176,12 @@
         self.sub = sub
         self.pos = pos
 
-    def __str__(self):
-        res = f'DEF_LOOKUP "{self.name}"'
-        res += f' {self.process_base and "PROCESS_BASE" or "SKIP_BASE"}'
-        if self.process_marks:
-            res += ' PROCESS_MARKS '
-            if self.mark_glyph_set:
-                res += f'MARK_GLYPH_SET "{self.mark_glyph_set}"'
-            elif isinstance(self.process_marks, str):
-                res += f'"{self.process_marks}"'
-            else:
-                res += 'ALL'
-        else:
-            res += ' SKIP_MARKS'
-        if self.direction is not None:
-            res += f' DIRECTION {self.direction}'
-        if self.reversal:
-            res += ' REVERSAL'
-        if self.comments is not None:
-            comments = self.comments.replace('\n', r'\n')
-            res += f'\nCOMMENTS "{comments}"'
-        if self.context:
-            res += '\n' + '\n'.join(str(c) for c in self.context)
-        else:
-            res += '\nIN_CONTEXT\nEND_CONTEXT'
-        if self.sub:
-            res += f'\n{self.sub}'
-        if self.pos:
-            res += f'\n{self.pos}'
-        return res
-
 
 class SubstitutionDefinition(Statement):
     def __init__(self, mapping, location=None):
         Statement.__init__(self, location)
         self.mapping = mapping
 
-    def __str__(self):
-        res = 'AS_SUBSTITUTION\n'
-        for src, dst in self.mapping.items():
-            src = ''.join(str(s) for s in src)
-            dst = ''.join(str(d) for d in dst)
-            res += f'SUB{src}\nWITH{dst}\nEND_SUB\n'
-        res += 'END_SUBSTITUTION'
-        return res
-
 
 class SubstitutionSingleDefinition(SubstitutionDefinition):
     pass
@@ -312,15 +205,6 @@
         self.coverage = coverage
         self.coverage_to = coverage_to
 
-    def __str__(self):
-        coverage = ''.join(str(c) for c in self.coverage)
-        res = f'AS_POSITION\nATTACH{coverage}\nTO'
-        for coverage, anchor in self.coverage_to:
-            coverage = ''.join(str(c) for c in coverage)
-            res += f'{coverage} AT ANCHOR "{anchor}"'
-        res += '\nEND_ATTACH\nEND_POSITION'
-        return res
-
 
 class PositionAttachCursiveDefinition(Statement):
     def __init__(self, coverages_exit, coverages_enter, location=None):
@@ -328,17 +212,6 @@
         self.coverages_exit = coverages_exit
         self.coverages_enter = coverages_enter
 
-    def __str__(self):
-        res = 'AS_POSITION\nATTACH_CURSIVE'
-        for coverage in self.coverages_exit:
-            coverage = ''.join(str(c) for c in coverage)
-            res += f'\nEXIT {coverage}'
-        for coverage in self.coverages_enter:
-            coverage = ''.join(str(c) for c in coverage)
-            res += f'\nENTER {coverage}'
-        res += '\nEND_ATTACH\nEND_POSITION'
-        return res
-
 
 class PositionAdjustPairDefinition(Statement):
     def __init__(self, coverages_1, coverages_2, adjust_pair, location=None):
@@ -347,36 +220,12 @@
         self.coverages_2 = coverages_2
         self.adjust_pair = adjust_pair
 
-    def __str__(self):
-        res = 'AS_POSITION\nADJUST_PAIR\n'
-        for coverage in self.coverages_1:
-            coverage = ' '.join(str(c) for c in coverage)
-            res += f' FIRST {coverage}'
-        res += '\n'
-        for coverage in self.coverages_2:
-            coverage = ' '.join(str(c) for c in coverage)
-            res += f' SECOND {coverage}'
-        res += '\n'
-        for (id_1, id_2), (pos_1, pos_2) in self.adjust_pair.items():
-            res += f' {id_1} {id_2} BY{pos_1}{pos_2}\n'
-        res += '\nEND_ADJUST\nEND_POSITION'
-        return res
-
 
 class PositionAdjustSingleDefinition(Statement):
     def __init__(self, adjust_single, location=None):
         Statement.__init__(self, location)
         self.adjust_single = adjust_single
 
-    def __str__(self):
-        res = 'AS_POSITION\nADJUST_SINGLE'
-        for coverage, pos in self.adjust_single:
-            coverage = ''.join(str(c) for c in coverage)
-            res += f'{coverage} BY{pos}'
-        res += '\nEND_ADJUST\nEND_POSITION'
-        return res
-
-
 
 class ContextDefinition(Statement):
     def __init__(self, ex_or_in, left=None, right=None, location=None):
@@ -385,17 +234,6 @@
         self.left = left if left is not None else []
         self.right = right if right is not None else []
 
-    def __str__(self):
-        res = self.ex_or_in + '\n'
-        for coverage in self.left:
-            coverage = ''.join(str(c) for c in coverage)
-            res += f' LEFT{coverage}\n'
-        for coverage in self.right:
-            coverage = ''.join(str(c) for c in coverage)
-            res += f' RIGHT{coverage}\n'
-        res += 'END_CONTEXT'
-        return res
-
 
 class AnchorDefinition(Statement):
     def __init__(self, name, gid, glyph_name, component, locked,
@@ -408,26 +246,9 @@
         self.locked = locked
         self.pos = pos
 
-    def __str__(self):
-        locked = self.locked and ' LOCKED' or ''
-        return (f'DEF_ANCHOR "{self.name}"'
-                f' ON {self.gid}'
-                f' GLYPH {self.glyph_name}'
-                f' COMPONENT {self.component}'
-                f'{locked}'
-                f' AT {self.pos} END_ANCHOR')
-
 
 class SettingDefinition(Statement):
     def __init__(self, name, value, location=None):
         Statement.__init__(self, location)
         self.name = name
         self.value = value
-
-    def __str__(self):
-        if self.value is True:
-            return f'{self.name}'
-        if isinstance(self.value, (tuple, list)):
-            value = " ".join(str(v) for v in self.value)
-            return f'{self.name} {value}'
-        return f'{self.name} {self.value}'
diff --git a/Lib/fontTools/voltLib/error.py b/Lib/fontTools/voltLib/error.py
index a905de1..f9900ad 100644
--- a/Lib/fontTools/voltLib/error.py
+++ b/Lib/fontTools/voltLib/error.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
 
 
 class VoltLibError(Exception):
diff --git a/Lib/fontTools/voltLib/lexer.py b/Lib/fontTools/voltLib/lexer.py
index bc982a7..53102b9 100644
--- a/Lib/fontTools/voltLib/lexer.py
+++ b/Lib/fontTools/voltLib/lexer.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
 from fontTools.voltLib.error import VoltLibError
 
 class Lexer(object):
diff --git a/Lib/fontTools/voltLib/parser.py b/Lib/fontTools/voltLib/parser.py
index 0e68d53..df035aa 100644
--- a/Lib/fontTools/voltLib/parser.py
+++ b/Lib/fontTools/voltLib/parser.py
@@ -1,3 +1,6 @@
+from __future__ import (
+    print_function, division, absolute_import, unicode_literals)
+from collections import OrderedDict
 import fontTools.voltLib.ast as ast
 from fontTools.voltLib.lexer import Lexer
 from fontTools.voltLib.error import VoltLibError
@@ -12,10 +15,9 @@
     "GRID_PPEM": "parse_ppem_",
     "PRESENTATION_PPEM": "parse_ppem_",
     "PPOSITIONING_PPEM": "parse_ppem_",
-    "COMPILER_USEEXTENSIONLOOKUPS": "parse_noarg_option_",
-    "COMPILER_USEPAIRPOSFORMAT2": "parse_noarg_option_",
+    "COMPILER_USEEXTENSIONLOOKUPS": "parse_compiler_flag_",
+    "COMPILER_USEPAIRPOSFORMAT2": "parse_compiler_flag_",
     "CMAP_FORMAT": "parse_cmap_format",
-    "DO_NOT_TOUCH_CMAP": "parse_noarg_option_",
 }
 
 
@@ -215,16 +217,13 @@
             if self.next_token_ == "MARK_GLYPH_SET":
                 self.advance_lexer_()
                 mark_glyph_set = self.expect_string_()
-            elif self.next_token_ == "ALL":
-                self.advance_lexer_()
-            elif self.next_token_ == "NONE":
-                self.advance_lexer_()
-                process_marks = False
             elif self.next_token_type_ == Lexer.STRING:
                 process_marks = self.expect_string_()
+            elif self.next_token_ == "ALL":
+                self.advance_lexer_()
             else:
                 raise VoltLibError(
-                    "Expected ALL, NONE, MARK_GLYPH_SET or an ID. "
+                    "Expected ALL, MARK_GLYPH_SET or an ID. "
                     "Got %s" % (self.next_token_type_),
                     location)
         elif self.next_token_ == "SKIP_MARKS":
@@ -242,7 +241,7 @@
         comments = None
         if self.next_token_ == "COMMENTS":
             self.expect_keyword_("COMMENTS")
-            comments = self.expect_string_().replace(r'\n', '\n')
+            comments = self.expect_string_()
         context = []
         while self.next_token_ in ("EXCEPT_CONTEXT", "IN_CONTEXT"):
             context = self.parse_context_()
@@ -312,7 +311,7 @@
             raise VoltLibError(
                 "Invalid substitution type",
                 location)
-        mapping = dict(zip(tuple(src), tuple(dest)))
+        mapping = OrderedDict(zip(tuple(src), tuple(dest)))
         if max_src == 1 and max_dest == 1:
             if reversal:
                 sub = ast.SubstitutionReverseChainingSingleDefinition(
@@ -494,7 +493,7 @@
                 adjustment, size = self.parse_adjust_by_()
                 dy_adjust_by[size] = adjustment
         self.expect_keyword_("END_POS")
-        return ast.Pos(adv, dx, dy, adv_adjust_by, dx_adjust_by, dy_adjust_by)
+        return (adv, dx, dy, adv_adjust_by, dx_adjust_by, dy_adjust_by)
 
     def parse_unicode_values_(self):
         location = self.cur_token_location_
@@ -550,11 +549,11 @@
         setting = ast.SettingDefinition(ppem_name, value, location=location)
         return setting
 
-    def parse_noarg_option_(self):
+    def parse_compiler_flag_(self):
         location = self.cur_token_location_
-        name = self.cur_token_
+        flag_name = self.cur_token_
         value = True
-        setting = ast.SettingDefinition(name, value, location=location)
+        setting = ast.SettingDefinition(flag_name, value, location=location)
         return setting
 
     def parse_cmap_format(self):
@@ -632,10 +631,10 @@
 
 class OrderedSymbolTable(SymbolTable):
     def __init__(self):
-        self.scopes_ = [{}]
+        self.scopes_ = [OrderedDict()]
 
     def enter_scope(self):
-        self.scopes_.append({})
+        self.scopes_.append(OrderedDict())
 
     def resolve(self, name, case_insensitive=False):
         SymbolTable.resolve(self, name, case_insensitive=case_insensitive)
diff --git a/Lib/fonttools.egg-info/PKG-INFO b/Lib/fonttools.egg-info/PKG-INFO
new file mode 100644
index 0000000..29e9467
--- /dev/null
+++ b/Lib/fonttools.egg-info/PKG-INFO
@@ -0,0 +1,1823 @@
+Metadata-Version: 2.1
+Name: fonttools
+Version: 3.44.0
+Summary: Tools to manipulate font files
+Home-page: http://github.com/fonttools/fonttools
+Author: Just van Rossum
+Author-email: just@letterror.com
+Maintainer: Behdad Esfahbod
+Maintainer-email: behdad@behdad.org
+License: MIT
+Description: |Travis Build Status| |Appveyor Build status| |Coverage Status| |PyPI| |Gitter Chat|
+        
+        What is this?
+        ~~~~~~~~~~~~~
+        
+        | fontTools is a library for manipulating fonts, written in Python. The
+          project includes the TTX tool, that can convert TrueType and OpenType
+          fonts to and from an XML text format, which is also called TTX. It
+          supports TrueType, OpenType, AFM and to an extent Type 1 and some
+          Mac-specific formats. The project has an `MIT open-source
+          licence <LICENSE>`__.
+        | Among other things this means you can use it free of charge.
+        
+        Installation
+        ~~~~~~~~~~~~
+        
+        FontTools requires `Python <http://www.python.org/download/>`__ 2.7, 3.4
+        or later.
+        
+        **NOTE** From August 2019, until no later than January 1 2020, the support
+        for *Python 2.7* will be limited to only critical bug fixes, and no new features
+        will be added to the ``py27`` branch. The upcoming FontTools 4.x series will require
+        *Python 3.6* or above. You can read more `here <https://python3statement.org>`__
+        and `here <https://github.com/fonttools/fonttools/issues/765>`__ for the
+        reasons behind this decision.
+        
+        The package is listed in the Python Package Index (PyPI), so you can
+        install it with `pip <https://pip.pypa.io>`__:
+        
+        .. code:: sh
+        
+            pip install fonttools
+        
+        If you would like to contribute to its development, you can clone the
+        repository from GitHub, install the package in 'editable' mode and
+        modify the source code in place. We recommend creating a virtual
+        environment, using `virtualenv <https://virtualenv.pypa.io>`__ or
+        Python 3 `venv <https://docs.python.org/3/library/venv.html>`__ module.
+        
+        .. code:: sh
+        
+            # download the source code to 'fonttools' folder
+            git clone https://github.com/fonttools/fonttools.git
+            cd fonttools
+        
+            # create new virtual environment called e.g. 'fonttools-venv', or anything you like
+            python -m virtualenv fonttools-venv
+        
+            # source the `activate` shell script to enter the environment (Un*x); to exit, just type `deactivate`
+            . fonttools-venv/bin/activate
+        
+            # to activate the virtual environment in Windows `cmd.exe`, do
+            fonttools-venv\Scripts\activate.bat
+        
+            # install in 'editable' mode
+            pip install -e .
+        
+        TTX – From OpenType and TrueType to XML and Back
+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+        
+        Once installed you can use the ``ttx`` command to convert binary font
+        files (``.otf``, ``.ttf``, etc) to the TTX XML format, edit them, and
+        convert them back to binary format. TTX files have a .ttx file
+        extension.
+        
+        .. code:: sh
+        
+            ttx /path/to/font.otf
+            ttx /path/to/font.ttx
+        
+        The TTX application can be used in two ways, depending on what
+        platform you run it on:
+        
+        -  As a command line tool (Windows/DOS, Unix, macOS)
+        -  By dropping files onto the application (Windows, macOS)
+        
+        TTX detects what kind of files it is fed: it will output a ``.ttx`` file
+        when it sees a ``.ttf`` or ``.otf``, and it will compile a ``.ttf`` or
+        ``.otf`` when the input file is a ``.ttx`` file. By default, the output
+        file is created in the same folder as the input file, and will have the
+        same name as the input file but with a different extension. TTX will
+        *never* overwrite existing files, but if necessary will append a unique
+        number to the output filename (before the extension) such as
+        ``Arial#1.ttf``
+        
+        When using TTX from the command line there are a bunch of extra options.
+        These are explained in the help text, as displayed when typing
+        ``ttx -h`` at the command prompt. These additional options include:
+        
+        -  specifying the folder where the output files are created
+        -  specifying which tables to dump or which tables to exclude
+        -  merging partial ``.ttx`` files with existing ``.ttf`` or ``.otf``
+           files
+        -  listing brief table info instead of dumping to ``.ttx``
+        -  splitting tables to separate ``.ttx`` files
+        -  disabling TrueType instruction disassembly
+        
+        The TTX file format
+        -------------------
+        
+        The following tables are currently supported:
+        
+        .. begin table list
+        .. code::
+        
+            BASE, CBDT, CBLC, CFF, CFF2, COLR, CPAL, DSIG, EBDT, EBLC, FFTM,
+            Feat, GDEF, GMAP, GPKG, GPOS, GSUB, Glat, Gloc, HVAR, JSTF, LTSH,
+            MATH, META, MVAR, OS/2, SING, STAT, SVG, Silf, Sill, TSI0, TSI1,
+            TSI2, TSI3, TSI5, TSIB, TSID, TSIJ, TSIP, TSIS, TSIV, TTFA, VDMX,
+            VORG, VVAR, ankr, avar, bsln, cidg, cmap, cvar, cvt, feat, fpgm,
+            fvar, gasp, gcid, glyf, gvar, hdmx, head, hhea, hmtx, kern, lcar,
+            loca, ltag, maxp, meta, mort, morx, name, opbd, post, prep, prop,
+            sbix, trak, vhea and vmtx
+        .. end table list
+        
+        Other tables are dumped as hexadecimal data.
+        
+        TrueType fonts use glyph indices (GlyphIDs) to refer to glyphs in most
+        places. While this is fine in binary form, it is really hard to work
+        with for humans. Therefore we use names instead.
+        
+        The glyph names are either extracted from the ``CFF`` table or the
+        ``post`` table, or are derived from a Unicode ``cmap`` table. In the
+        latter case the Adobe Glyph List is used to calculate names based on
+        Unicode values. If all of these methods fail, names are invented based
+        on GlyphID (eg ``glyph00142``)
+        
+        It is possible that different glyphs use the same name. If this happens,
+        we force the names to be unique by appending ``#n`` to the name (``n``
+        being an integer number.) The original names are being kept, so this has
+        no influence on a "round tripped" font.
+        
+        Because the order in which glyphs are stored inside the binary font is
+        important, we maintain an ordered list of glyph names in the font.
+        
+        Other Tools
+        ~~~~~~~~~~~
+        
+        Commands for merging and subsetting fonts are also available:
+        
+        .. code:: sh
+        
+            pyftmerge
+            pyftsubset
+        
+        fontTools Python Module
+        ~~~~~~~~~~~~~~~~~~~~~~~
+        
+        The fontTools Python module provides a convenient way to
+        programmatically edit font files.
+        
+        .. code:: py
+        
+            >>> from fontTools.ttLib import TTFont
+            >>> font = TTFont('/path/to/font.ttf')
+            >>> font
+            <fontTools.ttLib.TTFont object at 0x10c34ed50>
+            >>>
+        
+        A selection of sample Python programs is in the
+        `Snippets <https://github.com/fonttools/fonttools/blob/master/Snippets/>`__
+        directory.
+        
+        Optional Requirements
+        ---------------------
+        
+        The ``fontTools`` package currently has no (required) external dependencies
+        besides the modules included in the Python Standard Library.
+        However, a few extra dependencies are required by some of its modules, which
+        are needed to unlock optional features.
+        The ``fonttools`` PyPI distribution also supports so-called "extras", i.e. a
+        set of keywords that describe a group of additional dependencies, which can be
+        used when installing via pip, or when specifying a requirement.
+        For example:
+        
+        .. code:: sh
+        
+            pip install fonttools[ufo,lxml,woff,unicode]
+        
+        This command will install fonttools, as well as the optional dependencies that
+        are required to unlock the extra features named "ufo", etc.
+        
+        - ``Lib/fontTools/misc/etree.py``
+        
+          The module exports a ElementTree-like API for reading/writing XML files, and
+          allows to use as the backend either the built-in ``xml.etree`` module or
+          `lxml <https://http://lxml.de>`__. The latter is preferred whenever present,
+          as it is generally faster and more secure.
+        
+          *Extra:* ``lxml``
+        
+        - ``Lib/fontTools/ufoLib``
+        
+          Package for reading and writing UFO source files; it requires:
+        
+          * `fs <https://pypi.org/pypi/fs>`__: (aka ``pyfilesystem2``) filesystem
+            abstraction layer.
+        
+          * `enum34 <https://pypi.org/pypi/enum34>`__: backport for the built-in ``enum``
+            module (only required on Python < 3.4).
+        
+          *Extra:* ``ufo``
+        
+        - ``Lib/fontTools/ttLib/woff2.py``
+        
+          Module to compress/decompress WOFF 2.0 web fonts; it requires:
+        
+          * `brotli <https://pypi.python.org/pypi/Brotli>`__: Python bindings of
+            the Brotli compression library.
+        
+          *Extra:* ``woff``
+        
+        - ``Lib/fontTools/ttLib/sfnt.py``
+        
+          To better compress WOFF 1.0 web fonts, the following module can be used
+          instead of the built-in ``zlib`` library:
+        
+          * `zopfli <https://pypi.python.org/pypi/zopfli>`__: Python bindings of
+            the Zopfli compression library.
+        
+          *Extra:* ``woff``
+        
+        - ``Lib/fontTools/unicode.py``
+        
+          To display the Unicode character names when dumping the ``cmap`` table
+          with ``ttx`` we use the ``unicodedata`` module in the Standard Library.
+          The version included in there varies between different Python versions.
+          To use the latest available data, you can install:
+        
+          * `unicodedata2 <https://pypi.python.org/pypi/unicodedata2>`__:
+            ``unicodedata`` backport for Python 2.7 and 3.x updated to the latest
+            Unicode version 12.0. Note this is not necessary if you use Python 3.8
+            as the latter already comes with an up-to-date ``unicodedata``.
+        
+          *Extra:* ``unicode``
+        
+        - ``Lib/fontTools/varLib/interpolatable.py``
+        
+          Module for finding wrong contour/component order between different masters.
+          It requires one of the following packages in order to solve the so-called
+          "minimum weight perfect matching problem in bipartite graphs", or
+          the Assignment problem:
+        
+          * `scipy <https://pypi.python.org/pypi/scipy>`__: the Scientific Library
+            for Python, which internally uses `NumPy <https://pypi.python.org/pypi/numpy>`__
+            arrays and hence is very fast;
+          * `munkres <https://pypi.python.org/pypi/munkres>`__: a pure-Python
+            module that implements the Hungarian or Kuhn-Munkres algorithm.
+        
+          *Extra:* ``interpolatable``
+        
+        - ``Lib/fontTools/varLib/plot.py``
+        
+          Module for visualizing DesignSpaceDocument and resulting VariationModel.
+        
+          * `matplotlib <https://pypi.org/pypi/matplotlib>`__: 2D plotting library.
+        
+          *Extra:* ``plot``
+        
+        - ``Lib/fontTools/misc/symfont.py``
+        
+          Advanced module for symbolic font statistics analysis; it requires:
+        
+          * `sympy <https://pypi.python.org/pypi/sympy>`__: the Python library for
+            symbolic mathematics.
+        
+          *Extra:* ``symfont``
+        
+        - ``Lib/fontTools/t1Lib.py``
+        
+          To get the file creator and type of Macintosh PostScript Type 1 fonts
+          on Python 3 you need to install the following module, as the old ``MacOS``
+          module is no longer included in Mac Python:
+        
+          * `xattr <https://pypi.python.org/pypi/xattr>`__: Python wrapper for
+            extended filesystem attributes (macOS platform only).
+        
+          *Extra:* ``type1``
+        
+        - ``Lib/fontTools/pens/cocoaPen.py``
+        
+          Pen for drawing glyphs with Cocoa ``NSBezierPath``, requires:
+        
+          * `PyObjC <https://pypi.python.org/pypi/pyobjc>`__: the bridge between
+            Python and the Objective-C runtime (macOS platform only).
+        
+        - ``Lib/fontTools/pens/qtPen.py``
+        
+          Pen for drawing glyphs with Qt's ``QPainterPath``, requires:
+        
+          * `PyQt5 <https://pypi.python.org/pypi/PyQt5>`__: Python bindings for
+            the Qt cross platform UI and application toolkit.
+        
+        - ``Lib/fontTools/pens/reportLabPen.py``
+        
+          Pen to drawing glyphs as PNG images, requires:
+        
+          * `reportlab <https://pypi.python.org/pypi/reportlab>`__: Python toolkit
+            for generating PDFs and graphics.
+        
+        Testing
+        ~~~~~~~
+        
+        To run the test suite, you need to install `pytest <http://docs.pytest.org/en/latest/>`__.
+        When you run the ``pytest`` command, the tests will run against the
+        installed ``fontTools`` package, or the first one found in the
+        ``PYTHONPATH``.
+        
+        You can also use `tox <https://tox.readthedocs.io/en/latest/>`__ to
+        automatically run tests on different Python versions in isolated virtual
+        environments.
+        
+        .. code:: sh
+        
+            pip install tox
+            tox
+        
+        Note that when you run ``tox`` without arguments, the tests are executed
+        for all the environments listed in tox.ini's ``envlist``. In our case,
+        this includes Python 2.7 and 3.7, so for this to work the ``python2.7``
+        and ``python3.7`` executables must be available in your ``PATH``.
+        
+        You can specify an alternative environment list via the ``-e`` option,
+        or the ``TOXENV`` environment variable:
+        
+        .. code:: sh
+        
+            tox -e py27
+            TOXENV="py36-cov,htmlcov" tox
+        
+        Development Community
+        ~~~~~~~~~~~~~~~~~~~~~
+        
+        TTX/FontTools development is ongoing in an active community of
+        developers, that includes professional developers employed at major
+        software corporations and type foundries as well as hobbyists.
+        
+        Feature requests and bug reports are always welcome at
+        https://github.com/fonttools/fonttools/issues/
+        
+        The best place for discussions about TTX from an end-user perspective as
+        well as TTX/FontTools development is the
+        https://groups.google.com/d/forum/fonttools mailing list. There is also
+        a development https://groups.google.com/d/forum/fonttools-dev mailing
+        list for continuous integration notifications. You can also email Behdad
+        privately at behdad@behdad.org
+        
+        History
+        ~~~~~~~
+        
+        The fontTools project was started by Just van Rossum in 1999, and was
+        maintained as an open source project at
+        http://sourceforge.net/projects/fonttools/. In 2008, Paul Wise (pabs3)
+        began helping Just with stability maintenance. In 2013 Behdad Esfahbod
+        began a friendly fork, thoroughly reviewing the codebase and making
+        changes at https://github.com/behdad/fonttools to add new features and
+        support for new font formats.
+        
+        Acknowledgements
+        ~~~~~~~~~~~~~~~~
+        
+        In alphabetical order:
+        
+        Olivier Berten, Samyak Bhuta, Erik van Blokland, Petr van Blokland,
+        Jelle Bosma, Sascha Brawer, Tom Byrer, Frédéric Coiffier, Vincent
+        Connare, Dave Crossland, Simon Daniels, Peter Dekkers, Behdad Esfahbod,
+        Behnam Esfahbod, Hannes Famira, Sam Fishman, Matt Fontaine, Yannis
+        Haralambous, Greg Hitchcock, Jeremie Hornus, Khaled Hosny, John Hudson,
+        Denis Moyogo Jacquerye, Jack Jansen, Tom Kacvinsky, Jens Kutilek,
+        Antoine Leca, Werner Lemberg, Tal Leming, Peter Lofting, Cosimo Lupo,
+        Masaya Nakamura, Dave Opstad, Laurence Penney, Roozbeh Pournader, Garret
+        Rieger, Read Roberts, Guido van Rossum, Just van Rossum, Andreas Seidel,
+        Georg Seifert, Miguel Sousa, Adam Twardoch, Adrien Tétar, Vitaly Volkov,
+        Paul Wise.
+        
+        Copyrights
+        ~~~~~~~~~~
+        
+        | Copyright (c) 1999-2004 Just van Rossum, LettError
+          (just@letterror.com)
+        | See `LICENSE <LICENSE>`__ for the full license.
+        
+        Copyright (c) 2000 BeOpen.com. All Rights Reserved.
+        
+        Copyright (c) 1995-2001 Corporation for National Research Initiatives.
+        All Rights Reserved.
+        
+        Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. All
+        Rights Reserved.
+        
+        Have fun!
+        
+        .. |Travis Build Status| image:: https://travis-ci.org/fonttools/fonttools.svg
+           :target: https://travis-ci.org/fonttools/fonttools
+        .. |Appveyor Build status| image:: https://ci.appveyor.com/api/projects/status/0f7fmee9as744sl7/branch/master?svg=true
+           :target: https://ci.appveyor.com/project/fonttools/fonttools/branch/master
+        .. |Coverage Status| image:: https://codecov.io/gh/fonttools/fonttools/branch/master/graph/badge.svg
+           :target: https://codecov.io/gh/fonttools/fonttools
+        .. |PyPI| image:: https://img.shields.io/pypi/v/fonttools.svg
+           :target: https://pypi.org/project/FontTools
+        .. |Gitter Chat| image:: https://badges.gitter.im/fonttools-dev/Lobby.svg
+           :alt: Join the chat at https://gitter.im/fonttools-dev/Lobby
+           :target: https://gitter.im/fonttools-dev/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
+        
+        Changelog
+        ~~~~~~~~~
+        
+        3.44.0 (released 2019-08-02)
+        ----------------------------
+        
+        - NOTE: This is the last scheduled release to support Python 2.7. The upcoming fonttools
+          v4.x series is going to require Python 3.6 or greater.
+        - [varLib] Added new ``varLib.instancer`` module for partially instantiating variable
+          fonts. This extends (and will eventually replace) ``varLib.mutator`` module, as
+          it allows to create not just full static instances from a variable font, but also
+          "partial" or "less variable" fonts where some of the axes are dropped or
+          instantiated at a particular value.
+          Also available from the command-line as `fonttools varLib.instancer --help`
+          (#1537, #1628).
+        - [cffLib] Added support for ``FDSelect`` format 4 (#1677).
+        - [subset] Added support for subsetting ``sbix`` (Apple bitmap color font) table.
+        - [t1Lib] Fixed issue parsing ``eexec`` section in Type1 fonts when whitespace
+          characters are interspersed among the trailing zeros (#1676).
+        - [cffLib.specializer] Fixed bug in ``programToCommands`` with CFF2 charstrings (#1669).
+        
+        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)
+        ----------------------------
+        
+        - [subset] Fixed regression when passing ``--flavor=woff2`` option with an input font
+          that was already compressed as WOFF 1.0 (#1650).
+        
+        3.43.0 (released 2019-06-18)
+        ----------------------------
+        
+        - [woff2] Added support for compressing/decompressing WOFF2 fonts with non-transformed
+          ``glyf`` and ``loca`` tables, as well as with transformed ``hmtx`` table.
+          Removed ``Snippets/woff2_compress.py`` and ``Snippets/woff2_decompress.py`` scripts,
+          and replaced them with a new console entry point ``fonttools ttLib.woff2``
+          that provides two sub-commands ``compress`` and ``decompress``.
+        - [varLib.cff] Fixed bug when merging CFF2 ``PrivateDicts``. The ``PrivateDict``
+          data from the first region font was incorrecty used for all subsequent fonts.
+          The bug would only affect variable CFF2 fonts with hinting (#1643, #1644).
+          Also, fixed a merging bug when VF masters have no blends or marking glyphs (#1632,
+          #1642).
+        - [loggingTools] Removed unused backport of ``LastResortLogger`` class.
+        - [subset] Gracefully handle partial MATH table (#1635).
+        - [featureVars] Avoid duplicate references to ``rvrn`` feature record in
+          ``DefaultLangSys`` tables when calling ``addFeatureVariations`` on a font that
+          does not already have a ``GSUB`` table (aa8a5bc6).
+        - [varLib] Fixed merging of class-based kerning. Before, the process could introduce
+          rogue kerning values and variations for random classes against class zero (everything
+          not otherwise classed).
+        - [varLib] Fixed merging GPOS tables from master fonts with different number of
+          ``SinglePos`` subtables (#1621, #1641).
+        - [unicodedata] Updated Blocks, Scripts and ScriptExtensions to Unicode 12.1.
+        
+        3.42.0 (released 2019-05-28)
+        ----------------------------
+        
+        - [OS/2] Fixed sign of ``fsType``: it should be ``uint16``, not ``int16`` (#1619).
+        - [subset] Skip out-of-range class values in mark attachment (#1478).
+        - [fontBuilder] Add an empty ``DSIG`` table with ``setupDummyDSIG`` method (#1621).
+        - [varLib.merger] Fixed bug whereby ``GDEF.GlyphClassDef`` were being dropped
+          when generating instance via ``varLib.mutator`` (#1614).
+        - [varLib] Added command-line options ``-v`` and ``-q`` to configure logging (#1613).
+        - [subset] Update font extents in head table (#1612).
+        - [subset] Make --retain-gids truncate empty glyphs after the last non-empty glyph
+          (#1611).
+        - [requirements] Updated ``unicodedata2`` backport for Unicode 12.0.
+        
+        3.41.2 (released 2019-05-13)
+        ----------------------------
+        
+        - [cffLib] Fixed issue when importing a ``CFF2`` variable font from XML, whereby
+          the VarStore state was not propagated to PrivateDict (#1598).
+        - [varLib] Don't drop ``post`` glyph names when building CFF2 variable font (#1609).
+        
+        
+        3.41.1 (released 2019-05-13)
+        ----------------------------
+        
+        - [designspaceLib] Added ``loadSourceFonts`` method to load source fonts using
+          custom opener function (#1606).
+        - [head] Round font bounding box coordinates to integers to fix compile error
+          if CFF font has float coordinates (#1604, #1605).
+        - [feaLib] Don't write ``None`` in ``ast.ValueRecord.asFea()`` (#1599).
+        - [subset] Fixed issue ``AssertionError`` when using ``--desubroutinize`` option
+          (#1590, #1594).
+        - [graphite] Fixed bug in ``Silf`` table's ``decompile`` method unmasked by
+          previous typo fix (#1597). Decode languange code as UTF-8 in ``Sill`` table's
+          ``decompile`` method (#1600).
+        
+        3.41.0 (released 2019-04-29)
+        ----------------------------
+        
+        - [varLib/cffLib] Added support for building ``CFF2`` variable font from sparse
+          masters, or masters with more than one model (multiple ``VarStore.VarData``).
+          In ``cffLib.specializer``, added support for ``CFF2`` CharStrings with
+          ``blend`` operators (#1547, #1591).
+        - [subset] Fixed subsetting ``HVAR`` and ``VVAR`` with ``--retain-gids`` option,
+          and when advances mapping is null while sidebearings mappings are non-null
+          (#1587, #1588).
+        - Added ``otlLib.maxContextCalc`` module to compute ``OS/2.usMaxContext`` value.
+          Calculate it automatically when compiling features with feaLib. Added option
+          ``--recalc-max-context`` to ``subset`` module (#1582).
+        - [otBase/otTables] Fixed ``AttributeError`` on missing OT table fields after
+          importing font from TTX (#1584).
+        - [graphite] Fixed typo ``Silf`` table's ``decompile`` method (#1586).
+        - [otlLib] Better compress ``GPOS`` SinglePos (LookupType 1) subtables (#1539).
+        
+        3.40.0 (released 2019-04-08)
+        ----------------------------
+        
+        - [subset] Fixed error while subsetting ``VVAR`` with ``--retain-gids``
+          option (#1552).
+        - [designspaceLib] Use up-to-date default location in ``findDefault`` method
+          (#1554).
+        - [voltLib] Allow passing file-like object to Parser.
+        - [arrayTools/glyf] ``calcIntBounds`` (used to compute bounding boxes of glyf
+          table's glyphs) now uses ``otRound`` instead of ``round3`` (#1566).
+        - [svgLib] Added support for converting more SVG shapes to path ``d`` strings
+          (ellipse, line, polyline), as well as support for ``transform`` attributes.
+          Only ``matrix`` transformations are currently supported (#1564, #1564).
+        - [varLib] Added support for building ``VVAR`` table from ``vmtx`` and ``VORG``
+          tables (#1551).
+        - [fontBuilder] Enable making CFF2 fonts with ``post`` table format 2 (#1557).
+        - Fixed ``DeprecationWarning`` on invalid escape sequences (#1562).
+        
+        3.39.0 (released 2019-03-19)
+        ----------------------------
+        
+        - [ttLib/glyf] Raise more specific error when encountering recursive
+          component references (#1545, #1546).
+        - [Doc/designspaceLib] Defined new ``public.skipExportGlyphs`` lib key (#1534,
+          unified-font-object/ufo-spec#84).
+        - [varLib] Use ``vmtx`` to compute vertical phantom points; or ``hhea.ascent``
+          and ``head.unitsPerEM`` if ``vmtx`` is missing (#1528).
+        - [gvar/cvar] Sort XML element's min/value/max attributes in TupleVariation
+          toXML to improve readability of TTX dump (#1527).
+        - [varLib.plot] Added support for 2D plots with only 1 variation axis (#1522).
+        - [designspaceLib] Use axes maps when normalizing locations in
+          DesignSpaceDocument (#1226, #1521), and when finding default source (#1535).
+        - [mutator] Set ``OVERLAP_SIMPLE`` and ``OVERLAP_COMPOUND`` glyf flags by
+          default in ``instantiateVariableFont``. Added ``--no-overlap`` cli option
+          to disable this (#1518).
+        - [subset] Fixed subsetting ``VVAR`` table (#1516, #1517).  
+          Fixed subsetting an ``HVAR`` table that has an ``AdvanceWidthMap`` when the
+          option ``--retain-gids`` is used.
+        - [feaLib] Added ``forceChained`` in MultipleSubstStatement (#1511).  
+          Fixed double indentation of ``subtable`` statement (#1512).  
+          Added support for ``subtable`` statement in more places than just PairPos
+          lookups (#1520).  
+          Handle lookupflag 0 and lookupflag without a value (#1540).
+        - [varLib] In ``load_designspace``, provide a default English name for the
+          ``ital`` axis tag.
+        - Remove pyftinspect because it is unmaintained and bitrotted.
+        
+        3.38.0 (released 2019-02-18)
+        ----------------------------
+        
+        - [cffLib] Fixed RecursionError when unpickling or deepcopying TTFont with
+          CFF table (#1488, 649dc49).
+        - [subset] Fixed AttributeError when using --desubroutinize option (#1490).
+          Also, fixed desubroutinizing bug when subrs contain hints (#1499).
+        - [CPAL] Make Color a subclass of namedtuple (173a0f5).
+        - [feaLib] Allow hyphen in glyph class names.
+        - [feaLib] Added 'tables' option to __main__.py (#1497).
+        - [feaLib] Add support for special-case contextual positioning formatting
+          (#1501).
+        - [svgLib] Support converting SVG basic shapes (rect, circle, etc.) into
+          equivalent SVG paths (#1500, #1508).
+        - [Snippets] Added name-viewer.ipynb Jupyter notebook.
+        
+        
+        3.37.3 (released 2019-02-05)
+        ----------------------------
+        
+        - The previous release accidentally changed several files from Unix to DOS
+          line-endings. Fix that.
+        
+        3.37.2 (released 2019-02-05)
+        ----------------------------
+        
+        - [varLib] Temporarily revert the fix to ``load_masters()``, which caused a
+          crash in ``interpolate_layout()`` when ``deepcopy``-ing OTFs.
+        
+        3.37.1 (released 2019-02-05)
+        ----------------------------
+        
+        - [varLib] ``load_masters()`` now actually assigns the fonts it loads to the
+          source.font attributes.
+        - [varLib] Fixed an MVAR table generation crash when sparse masters were
+          involved.
+        - [voltLib] ``parse_coverage_()`` returns a tuple instead of an ast.Enum.
+        - [feaLib] A MarkClassDefinition inside a block is no longer doubly indented
+          compared to the rest of the block.
+        
+        3.37.0 (released 2019-01-28)
+        ----------------------------
+        
+        - [svgLib] Added support for converting elliptical arcs to cubic bezier curves
+          (#1464).
+        - [py23] Added backport for ``math.isfinite``.
+        - [varLib] Apply HIDDEN flag to fvar axis if designspace axis has attribute
+          ``hidden=1``.
+        - Fixed "DeprecationWarning: invalid escape sequence" in Python 3.7.
+        - [voltLib] Fixed parsing glyph groups. Distinguish different PROCESS_MARKS.
+          Accept COMPONENT glyph type.
+        - [feaLib] Distinguish missing value and explicit ``<NULL>`` for PairPos2
+          format A (#1459). Round-trip ``useExtension`` keyword. Implemented
+          ``ValueRecord.asFea`` method.
+        - [subset] Insert empty widths into hdmx when retaining gids (#1458).
+        
+        3.36.0 (released 2019-01-17)
+        ----------------------------
+        
+        - [ttx] Added ``--no-recalc-timestamp`` option to keep the original font's
+          ``head.modified`` timestamp (#1455, #46).
+        - [ttx/psCharStrings] Fixed issues while dumping and round-tripping CFF2 table
+          with ttx (#1451, #1452, #1456).
+        - [voltLib] Fixed check for duplicate anchors (#1450). Don't try to read past
+          the ``END`` operator in .vtp file (#1453).
+        - [varLib] Use sentinel value -0x8000 (-32768) to ignore post.underlineThickness
+          and post.underlinePosition when generating MVAR deltas (#1449,
+          googlei18n/ufo2ft#308).
+        - [subset] Added ``--retain-gids`` option to subset font without modifying the
+          current glyph indices (#1443, #1447).
+        - [ufoLib] Replace deprecated calls to ``getbytes`` and ``setbytes`` with new
+          equivalent ``readbytes`` and ``writebytes`` calls. ``fs`` >= 2.2 no required.
+        - [varLib] Allow loading masters from TTX files as well (#1441).
+        
+        3.35.2 (released 2019-01-14)
+        ----------------------------
+        
+        - [hmtx/vmtx]: Allow to compile/decompile ``hmtx`` and ``vmtx`` tables even
+          without the corresponding (required) metrics header tables, ``hhea`` and
+          ``vhea`` (#1439).
+        - [varLib] Added support for localized axes' ``labelname`` and named instances'
+          ``stylename`` (#1438).
+        
+        3.35.1 (released 2019-01-09)
+        ----------------------------
+        
+        - [_m_a_x_p] Include ``maxComponentElements`` in ``maxp`` table's recalculation.
+        
+        3.35.0 (released 2019-01-07)
+        ----------------------------
+        
+        - [psCharStrings] In ``encodeFloat`` function, use float's "general format" with
+          8 digits of precision (i.e. ``%8g``) instead of ``str()``. This works around
+          a macOS rendering issue when real numbers in CFF table are too long, and
+          also makes sure that floats are encoded with the same precision in python 2.7
+          and 3.x (#1430, googlei18n/ufo2ft#306).
+        - [_n_a_m_e/fontBuilder] Make ``_n_a_m_e_table.addMultilingualName`` also add
+          Macintosh (platformID=1) names by default. Added options to ``FontBuilder``
+          ``setupNameTable`` method to optionally disable Macintosh or Windows names.
+          (#1359, #1431).
+        - [varLib] Make ``build`` optionally accept a ``DesignSpaceDocument`` object,
+          instead of a designspace file path. The caller can now set the ``font``
+          attribute of designspace's sources to a TTFont object, thus allowing to
+          skip filenames manipulation altogether (#1416, #1425).
+        - [sfnt] Allow SFNTReader objects to be deep-copied.
+        - Require typing>=3.6.4 on py27 to fix issue with singledispatch (#1423).
+        - [designspaceLib/t1Lib/macRes] Fixed some cases where pathlib.Path objects were
+          not accepted (#1421).
+        - [varLib] Fixed merging of multiple PairPosFormat2 subtables (#1411).
+        - [varLib] The default STAT table version is now set to 1.1, to improve
+          compatibility with legacy applications (#1413).
+        
+        3.34.2 (released 2018-12-17)
+        ----------------------------
+        
+        - [merge] Fixed AssertionError when none of the script tables in GPOS/GSUB have
+          a DefaultLangSys record (#1408, 135a4a1).
+        
+        3.34.1 (released 2018-12-17)
+        ----------------------------
+        
+        - [varLib] Work around macOS rendering issue for composites without gvar entry (#1381).
+        
+        3.34.0 (released 2018-12-14)
+        ----------------------------
+        
+        - [varLib] Support generation of CFF2 variable fonts. ``model.reorderMasters()``
+          now supports arbitrary mapping. Fix handling of overlapping ranges for feature
+          variations (#1400).
+        - [cffLib, subset] Code clean-up and fixing related to CFF2 support.
+        - [ttLib.tables.ttProgram] Use raw strings for regex patterns (#1389).
+        - [fontbuilder] Initial support for building CFF2 fonts. Set CFF's
+          ``FontMatrix`` automatically from unitsPerEm.
+        - [plistLib] Accept the more general ``collections.Mapping`` instead of the
+          specific ``dict`` class to support custom data classes that should serialize
+          to dictionaries.
+        
+        3.33.0 (released 2018-11-30)
+        ----------------------------
+        - [subset] subsetter bug fix with variable fonts.
+        - [varLib.featureVar] Improve FeatureVariations generation with many rules.
+        - [varLib] Enable sparse masters when building variable fonts:
+          https://github.com/fonttools/fonttools/pull/1368#issuecomment-437257368
+        - [varLib.mutator] Add IDEF for GETVARIATION opcode, for handling hints in an
+          instance.
+        - [ttLib] Ignore the length of kern table subtable format 0
+        
+        3.32.0 (released 2018-11-01)
+        ----------------------------
+        
+        - [ufoLib] Make ``UFOWriter`` a subclass of ``UFOReader``, and use mixins
+          for shared methods (#1344).
+        - [featureVars] Fixed normalization error when a condition's minimum/maximum
+          attributes are missing in designspace ``<rule>`` (#1366).
+        - [setup.py] Added ``[plot]`` to extras, to optionally install ``matplotlib``,
+          needed to use the ``fonTools.varLib.plot`` module.
+        - [varLib] Take total bounding box into account when resolving model (7ee81c8).
+          If multiple axes have the same range ratio, cut across both (62003f4).
+        - [subset] Don't error if ``STAT`` has no ``AxisValue`` tables.
+        - [fontBuilder] Added a new submodule which contains a ``FontBuilder`` wrapper
+          class around ``TTFont`` that makes it easier to create a working TTF or OTF
+          font from scratch with code. NOTE: the API is still experimental and may
+          change in future versions.
+        
+        3.31.0 (released 2018-10-21)
+        ----------------------------
+        
+        - [ufoLib] Merged the `ufoLib <https://github.com/unified-font-objects/ufoLib>`__
+          master branch into a new ``fontTools.ufoLib`` package (#1335, #1095).
+          Moved ``ufoLib.pointPen`` module to ``fontTools.pens.pointPen``.
+          Moved ``ufoLib.etree`` module to ``fontTools.misc.etree``.
+          Moved ``ufoLib.plistlib`` module to ``fontTools.misc.plistlib``.
+          To use the new ``fontTools.ufoLib`` module you need to install fonttools
+          with the ``[ufo]`` extra, or you can manually install the required additional
+          dependencies (cf. README.rst).
+        - [morx] Support AAT action type to insert glyphs and clean up compilation
+          of AAT action tables (4a1871f, 2011ccf).
+        - [subset] The ``--no-hinting`` on a CFF font now also drops the optional
+          hinting keys in Private dict: ``ForceBold``, ``LanguageGroup``, and
+          ``ExpansionFactor`` (#1322).
+        - [subset] Include nameIDs referenced by STAT table (#1327).
+        - [loggingTools] Added ``msg=None`` argument to
+          ``CapturingLogHandler.assertRegex`` (0245f2c).
+        - [varLib.mutator] Implemented ``FeatureVariations`` instantiation (#1244).
+        - [g_l_y_f] Added PointPen support to ``_TTGlyph`` objects (#1334).
+        
+        3.30.0 (released 2018-09-18)
+        ----------------------------
+        
+        - [feaLib] Skip building noop class PairPos subtables when Coverage is NULL
+          (#1318).
+        - [ttx] Expose the previously reserved bit flag ``OVERLAP_SIMPLE`` of
+          glyf table's contour points in the TTX dump. This is used in some
+          implementations to specify a non-zero fill with overlapping contours (#1316).
+        - [ttLib] Added support for decompiling/compiling ``TS1C`` tables containing
+          VTT sources for ``cvar`` variation table (#1310).
+        - [varLib] Use ``fontTools.designspaceLib`` to read DesignSpaceDocument. The
+          ``fontTools.varLib.designspace`` module is now deprecated and will be removed
+          in future versions. The presence of an explicit ``axes`` element is now
+          required in order to build a variable font (#1224, #1313).
+        - [varLib] Implemented building GSUB FeatureVariations table from the ``rules``
+          element of DesignSpace document (#1240, #713, #1314).
+        - [subset] Added ``--no-layout-closure`` option to not expand the subset with
+          the glyphs produced by OpenType layout features. Instead, OpenType features
+          will be subset to only rules that are relevant to the otherwise-specified
+          glyph set (#43, #1121).
+        
+        3.29.1 (released 2018-09-10)
+        ----------------------------
+        
+        - [feaLib] Fixed issue whereby lookups from DFLT/dflt were not included in the
+          DFLT/non-dflt language systems (#1307).
+        - [graphite] Fixed issue on big-endian architectures (e.g. ppc64) (#1311).
+        - [subset] Added ``--layout-scripts`` option to add/exclude set of OpenType
+          layout scripts that will be preserved. By default all scripts are retained
+          (``'*'``) (#1303).
+        
+        3.29.0 (released 2018-07-26)
+        ----------------------------
+        
+        - [feaLib] In the OTL table builder, when the ``name`` table is excluded
+          from the list of tables to be build, skip compiling ``featureNames`` blocks,
+          as the records referenced in ``FeatureParams`` table don't exist (68951b7).
+        - [otBase] Try ``ExtensionLookup`` if other offset-overflow methods fail
+          (05f95f0).
+        - [feaLib] Added support for explicit ``subtable;`` break statements in
+          PairPos lookups; previously these were ignored (#1279, #1300, #1302).
+        - [cffLib.specializer] Make sure the stack depth does not exceed maxstack - 1,
+          so that a subroutinizer can insert subroutine calls (#1301,
+          https://github.com/googlei18n/ufo2ft/issues/266).
+        - [otTables] Added support for fixing offset overflow errors occurring inside
+          ``MarkBasePos`` subtables (#1297).
+        - [subset] Write the default output file extension based on ``--flavor`` option,
+          or the value of ``TTFont.sfntVersion`` (d7ac0ad).
+        - [unicodedata] Updated Blocks, Scripts and ScriptExtensions for Unicode 11
+          (452c85e).
+        - [xmlWriter] Added context manager to XMLWriter class to autoclose file
+          descriptor on exit (#1290).
+        - [psCharStrings] Optimize the charstring's bytecode by encoding as integers
+          all float values that have no decimal portion (8d7774a).
+        - [ttFont] Fixed missing import of ``TTLibError`` exception (#1285).
+        - [feaLib] Allow any languages other than ``dflt`` under ``DFLT`` script
+          (#1278, #1292).
+        
+        3.28.0 (released 2018-06-19)
+        ----------------------------
+        
+        - [featureVars] Added experimental module to build ``FeatureVariations``
+          tables. Still needs to be hooked up to ``varLib.build`` (#1240).
+        - [fixedTools] Added ``otRound`` to round floats to nearest integer towards
+          positive Infinity. This is now used where we deal with visual data like X/Y
+          coordinates, advance widths/heights, variation deltas, and similar (#1274,
+          #1248).
+        - [subset] Improved GSUB closure memoize algorithm.
+        - [varLib.models] Fixed regression in model resolution (180124, #1269).
+        - [feaLib.ast] Fixed error when converting ``SubtableStatement`` to string
+          (#1275).
+        - [varLib.mutator] Set ``OS/2.usWeightClass`` and ``usWidthClass``, and
+          ``post.italicAngle`` based on the 'wght', 'wdth' and 'slnt' axis values
+          (#1276, #1264).
+        - [py23/loggingTools] Don't automatically set ``logging.lastResort`` handler
+          on py27. Moved ``LastResortLogger`` to the ``loggingTools`` module (#1277).
+        
+        3.27.1 (released 2018-06-11)
+        ----------------------------
+        
+        - [ttGlyphPen] Issue a warning and skip building non-existing components
+          (https://github.com/googlei18n/fontmake/issues/411).
+        - [tests] Fixed issue running ttx_test.py from a tagged commit.
+        
+        3.27.0 (released 2018-06-11)
+        ----------------------------
+        
+        - [designspaceLib] Added new ``conditionSet`` element to ``rule`` element in
+          designspace document. Bumped ``format`` attribute to ``4.0`` (previously,
+          it was formatted as an integer). Removed ``checkDefault``, ``checkAxes``
+          methods, and any kind of guessing about the axes when the ``<axes>`` element
+          is missing. The default master is expected at the intersection of all default
+          values for each axis (#1254, #1255, #1267).
+        - [cffLib] Fixed issues when compiling CFF2 or converting from CFF when the
+          font has an FDArray (#1211, #1271).
+        - [varLib] Avoid attempting to build ``cvar`` table when ``glyf`` table is not
+          present, as is the case for CFF2 fonts.
+        - [subset] Handle None coverages in MarkGlyphSets; revert commit 02616ab that
+          sets empty Coverage tables in MarkGlyphSets to None, to make OTS happy.
+        - [ttFont] Allow to build glyph order from ``maxp.numGlyphs`` when ``post`` or
+          ``cmap`` are missing.
+        - [ttFont] Added ``__len__`` method to ``_TTGlyphSet``.
+        - [glyf] Ensure ``GlyphCoordinates`` never overflow signed shorts (#1230).
+        - [py23] Added alias for ``itertools.izip`` shadowing the built-in ``zip``.
+        - [loggingTools] Memoize ``log`` property of ``LogMixin`` class (fbab12).
+        - [ttx] Impoved test coverage (#1261).
+        - [Snippets] Addded script to append a suffix to all family names in a font.
+        - [varLib.plot] Make it work with matplotlib >= 2.1 (b38e2b).
+        
+        3.26.0 (released 2018-05-03)
+        ----------------------------
+        
+        - [designspace] Added a new optional ``layer`` attribute to the source element,
+          and a corresponding ``layerName`` attribute to the ``SourceDescriptor``
+          object (#1253).
+          Added ``conditionset`` element to the ``rule`` element to the spec, but not
+          implemented in designspace reader/writer yet (#1254).
+        - [varLib.models] Refine modeling one last time (0ecf5c5).
+        - [otBase] Fixed sharing of tables referred to by different offset sizes
+          (795f2f9).
+        - [subset] Don't drop a GDEF that only has VarStore (fc819d6). Set to None
+          empty Coverage tables in MarkGlyphSets (02616ab).
+        - [varLib]: Added ``--master-finder`` command-line option (#1249).
+        - [varLib.mutator] Prune fvar nameIDs from instance's name table (#1245).
+        - [otTables] Allow decompiling bad ClassDef tables with invalid format, with
+          warning (#1236).
+        - [varLib] Make STAT v1.2 and reuse nameIDs from fvar table (#1242).
+        - [varLib.plot] Show master locations. Set axis limits to -1, +1.
+        - [subset] Handle HVAR direct mapping. Passthrough 'cvar'.
+          Added ``--font-number`` command-line option for collections.
+        - [t1Lib] Allow a text encoding to be specified when parsing a Type 1 font
+          (#1234). Added ``kind`` argument to T1Font constructor (c5c161c).
+        - [ttLib] Added context manager API to ``TTFont`` class, so it can be used in
+          ``with`` statements to auto-close the file when exiting the context (#1232).
+        
+        3.25.0 (released 2018-04-03)
+        ----------------------------
+        
+        - [varLib] Improved support-resolution algorithm. Previously, the on-axis
+          masters would always cut the space. They don't anymore. That's more
+          consistent, and fixes the main issue Erik showed at TYPO Labs 2017.
+          Any varfont built that had an unusual master configuration will change
+          when rebuilt (42bef17, a523a697,
+          https://github.com/googlei18n/fontmake/issues/264).
+        - [varLib.models] Added a ``main()`` entry point, that takes positions and
+          prints model results.
+        - [varLib.plot] Added new module to plot a designspace's
+          VariationModel. Requires ``matplotlib``.
+        - [varLib.mutator] Added -o option to specify output file path (2ef60fa).
+        - [otTables] Fixed IndexError while pruning of HVAR pre-write (6b6c34a).
+        - [varLib.models] Convert delta array to floats if values overflows signed
+          short integer (0055f94).
+        
+        3.24.2 (released 2018-03-26)
+        ----------------------------
+        
+        - [otBase] Don't fail during ``ValueRecord`` copy if src has more items.
+          We drop hinting in the subsetter by simply changing ValueFormat, without
+          cleaning up the actual ValueRecords. This was causing assertion error if
+          a variable font was subsetted without hinting and then passed directly to
+          the mutator for instantiation without first it saving to disk.
+        
+        3.24.1 (released 2018-03-06)
+        ----------------------------
+        
+        - [varLib] Don't remap the same ``DeviceTable`` twice in VarStore optimizer
+          (#1206).
+        - [varLib] Add ``--disable-iup`` option to ``fonttools varLib`` script,
+          and a ``optimize=True`` keyword argument to ``varLib.build`` function,
+          to optionally disable IUP optimization while building varfonts.
+        - [ttCollection] Fixed issue while decompiling ttc with python3 (#1207).
+        
+        3.24.0 (released 2018-03-01)
+        ----------------------------
+        
+        - [ttGlyphPen] Decompose composite glyphs if any components' transform is too
+          large to fit a ``F2Dot14`` value, or clamp transform values that are
+          (almost) equal to +2.0 to make them fit and avoid decomposing (#1200,
+          #1204, #1205).
+        - [ttx] Added new ``-g`` option to dump glyphs from the ``glyf`` table
+          splitted as individual ttx files (#153, #1035, #1132, #1202).
+        - Copied ``ufoLib.filenames`` module to ``fontTools.misc.filenames``, used
+          for the ttx split-glyphs option (#1202).
+        - [feaLib] Added support for ``cvParameters`` blocks in Character Variant
+          feautures ``cv01-cv99`` (#860, #1169).
+        - [Snippets] Added ``checksum.py`` script to generate/check SHA1 hash of
+          ttx files (#1197).
+        - [varLib.mutator] Fixed issue while instantiating some variable fonts
+          whereby the horizontal advance width computed from ``gvar`` phantom points
+          could turn up to be negative (#1198).
+        - [varLib/subset] Fixed issue with subsetting GPOS variation data not
+          picking up ``ValueRecord`` ``Device`` objects (54fd71f).
+        - [feaLib/voltLib] In all AST elements, the ``location`` is no longer a
+          required positional argument, but an optional kewyord argument (defaults
+          to ``None``). This will make it easier to construct feature AST from
+          code (#1201).
+        
+        
+        3.23.0 (released 2018-02-26)
+        ----------------------------
+        
+        - [designspaceLib] Added an optional ``lib`` element to the designspace as a
+          whole, as well as to the instance elements, to store arbitrary data in a
+          property list dictionary, similar to the UFO's ``lib``. Added an optional
+          ``font`` attribute to the ``SourceDescriptor``, to allow operating on
+          in-memory font objects (#1175).
+        - [cffLib] Fixed issue with lazy-loading of attributes when attempting to
+          set the CFF TopDict.Encoding (#1177, #1187).
+        - [ttx] Fixed regression introduced in 3.22.0 that affected the split tables
+          ``-s`` option (#1188).
+        - [feaLib] Added ``IncludedFeaNotFound`` custom exception subclass, raised
+          when an included feature file cannot be found (#1186).
+        - [otTables] Changed ``VarIdxMap`` to use glyph names internally instead of
+          glyph indexes. The old ttx dumps of HVAR/VVAR tables that contain indexes
+          can still be imported (21cbab8, 38a0ffb).
+        - [varLib] Implemented VarStore optimizer (#1184).
+        - [subset] Implemented pruning of GDEF VarStore, HVAR and MVAR (#1179).
+        - [sfnt] Restore backward compatiblity with ``numFonts`` attribute of
+          ``SFNTReader`` object (#1181).
+        - [merge] Initial support for merging ``LangSysRecords`` (#1180).
+        - [ttCollection] don't seek(0) when writing to possibly unseekable strems.
+        - [subset] Keep all ``--name-IDs`` from 0 to 6 by default (#1170, #605, #114).
+        - [cffLib] Added ``width`` module to calculate optimal CFF default and
+          nominal glyph widths.
+        - [varLib] Don’t fail if STAT already in the master fonts (#1166).
+        
+        3.22.0 (released 2018-02-04)
+        ----------------------------
+        
+        - [subset] Support subsetting ``endchar`` acting as ``seac``-like components
+          in ``CFF`` (fixes #1162).
+        - [feaLib] Allow to build from pre-parsed ``ast.FeatureFile`` object.
+          Added ``tables`` argument to only build some tables instead of all (#1159,
+          #1163).
+        - [textTools] Replaced ``safeEval`` with ``ast.literal_eval`` (#1139).
+        - [feaLib] Added option to the parser to not resolve ``include`` statements
+          (#1154).
+        - [ttLib] Added new ``ttCollection`` module to read/write TrueType and
+          OpenType Collections. Exports a ``TTCollection`` class with a ``fonts``
+          attribute containing a list of ``TTFont`` instances, the methods ``save``
+          and ``saveXML``, plus some list-like methods. The ``importXML`` method is
+          not implemented yet (#17).
+        - [unicodeadata] Added ``ot_tag_to_script`` function that converts from
+          OpenType script tag to Unicode script code.
+        - Added new ``designspaceLib`` subpackage, originally from Erik Van Blokland's
+          ``designSpaceDocument``: https://github.com/LettError/designSpaceDocument
+          NOTE: this is not yet used internally by varLib, and the API may be subject
+          to changes (#911, #1110, LettError/designSpaceDocument#28).
+        - Added new FontTools icon images (8ee7c32).
+        - [unicodedata] Added ``script_horizontal_direction`` function that returns
+          either "LTR" or "RTL" given a unicode script code.
+        - [otConverters] Don't write descriptive name string as XML comment if the
+          NameID value is 0 (== NULL) (#1151, #1152).
+        - [unicodedata] Add ``ot_tags_from_script`` function to get the list of
+          OpenType script tags associated with unicode script code (#1150).
+        - [feaLib] Don't error when "enumerated" kern pairs conflict with preceding
+          single pairs; emit warning and chose the first value (#1147, #1148).
+        - [loggingTools] In ``CapturingLogHandler.assertRegex`` method, match the
+          fully formatted log message.
+        - [sbix] Fixed TypeError when concatenating str and bytes (#1154).
+        - [bezierTools] Implemented cusp support and removed ``approximate_fallback``
+          arg in ``calcQuadraticArcLength``. Added ``calcCubicArcLength`` (#1142).
+        
+        3.21.2 (released 2018-01-08)
+        ----------------------------
+        
+        - [varLib] Fixed merging PairPos Format1/2 with missing subtables (#1125).
+        
+        3.21.1 (released 2018-01-03)
+        ----------------------------
+        
+        - [feaLib] Allow mixed single/multiple substitutions (#612)
+        - Added missing ``*.afm`` test assets to MAINFEST.in (#1137).
+        - Fixed dumping ``SVG`` tables containing color palettes (#1124).
+        
+        3.21.0 (released 2017-12-18)
+        ----------------------------
+        
+        - [cmap] when compiling format6 subtable, don't assume gid0 is always called
+          '.notdef' (1e42224).
+        - [ot] Allow decompiling fonts with bad Coverage format number (1aafae8).
+        - Change FontTools licence to MIT (#1127).
+        - [post] Prune extra names already in standard Mac set (df1e8c7).
+        - [subset] Delete empty SubrsIndex after subsetting (#994, #1118).
+        - [varLib] Don't share points in cvar by default, as it currently fails on
+          some browsers (#1113).
+        - [afmLib] Make poor old afmLib work on python3.
+        
+        3.20.1 (released 2017-11-22)
+        ----------------------------
+        
+        - [unicodedata] Fixed issue with ``script`` and ``script_extension`` functions
+          returning inconsistent short vs long names. They both return the short four-
+          letter script codes now. Added ``script_name`` and ``script_code`` functions
+          to look up the long human-readable script name from the script code, and
+          viceversa (#1109, #1111).
+        
+        3.20.0 (released 2017-11-21)
+        ----------------------------
+        
+        - [unicodedata] Addded new module ``fontTools.unicodedata`` which exports the
+          same interface as the built-in ``unicodedata`` module, with the addition of
+          a few functions that are missing from the latter, such as ``script``,
+          ``script_extension`` and ``block``. Added a ``MetaTools/buildUCD.py`` script
+          to download and parse data files from the Unicode Character Database and
+          generate python modules containing lists of ranges and property values.
+        - [feaLib] Added ``__str__`` method to all ``ast`` elements (delegates to the
+          ``asFea`` method).
+        - [feaLib] ``Parser`` constructor now accepts a ``glyphNames`` iterable
+          instead of ``glyphMap`` dict. The latter still works but with a pending
+          deprecation warning (#1104).
+        - [bezierTools] Added arc length calculation functions originally from
+          ``pens.perimeterPen`` module (#1101).
+        - [varLib] Started generating STAT table (8af4309). Right now it just reflects
+          the axes, and even that with certain limitations:
+          * AxisOrdering is set to the order axes are defined,
+          * Name-table entries are not shared with fvar.
+        - [py23] Added backports for ``redirect_stdout`` and ``redirect_stderr``
+          context managers (#1097).
+        - [Graphite] Fixed some round-trip bugs (#1093).
+        
+        3.19.0 (released 2017-11-06)
+        ----------------------------
+        
+        - [varLib] Try set of used points instead of all points when testing whether to
+          share points between tuples (#1090).
+        - [CFF2] Fixed issue with reading/writing PrivateDict BlueValues to TTX file.
+          Read the commit message 8b02b5a and issue #1030 for more details.
+          NOTE: this change invalidates all the TTX files containing CFF2 tables
+          that where dumped with previous verisons of fonttools.
+          CFF2 Subr items can have values on the stack after the last operator, thus
+          a ``CFF2Subr`` class was added to accommodate this (#1091).
+        - [_k_e_r_n] Fixed compilation of AAT kern version=1.0 tables (#1089, #1094)
+        - [ttLib] Added getBestCmap() convenience method to TTFont class and cmap table
+          class that returns a preferred Unicode cmap subtable given a list of options
+          (#1092).
+        - [morx] Emit more meaningful subtable flags. Implement InsertionMorphAction
+        
+        3.18.0 (released 2017-10-30)
+        ----------------------------
+        
+        - [feaLib] Fixed writing back nested glyph classes (#1086).
+        - [TupleVariation] Reactivated shared points logic, bugfixes (#1009).
+        - [AAT] Implemented ``morx`` ligature subtables (#1082).
+        - [reverseContourPen] Keep duplicate lineTo following a moveTo (#1080,
+          https://github.com/googlei18n/cu2qu/issues/51).
+        - [varLib.mutator] Suport instantiation of GPOS, GDEF and MVAR (#1079).
+        - [sstruct] Fixed issue with ``unicode_literals`` and ``struct`` module in
+          old versions of python 2.7 (#993).
+        
+        3.17.0 (released 2017-10-16)
+        ----------------------------
+        
+        - [svgPathPen] Added an ``SVGPathPen`` that translates segment pen commands
+          into SVG path descriptions. Copied from Tal Leming's ``ufo2svg.svgPathPen``
+          https://github.com/typesupply/ufo2svg/blob/d69f992/Lib/ufo2svg/svgPathPen.py
+        - [reverseContourPen] Added ``ReverseContourPen``, a filter pen that draws
+          contours with the winding direction reversed, while keeping the starting
+          point (#1071).
+        - [filterPen] Added ``ContourFilterPen`` to manipulate contours as a whole
+          rather than segment by segment.
+        - [arrayTools] Added ``Vector`` class to apply math operations on an array
+          of numbers, and ``pairwise`` function to loop over pairs of items in an
+          iterable.
+        - [varLib] Added support for building and interpolation of ``cvar`` table
+          (f874cf6, a25a401).
+        
+        3.16.0 (released 2017-10-03)
+        ----------------------------
+        
+        - [head] Try using ``SOURCE_DATE_EPOCH`` environment variable when setting
+          the ``head`` modified timestamp to ensure reproducible builds (#1063).
+          See https://reproducible-builds.org/specs/source-date-epoch/
+        - [VTT] Decode VTT's ``TSI*`` tables text as UTF-8 (#1060).
+        - Added support for Graphite font tables: Feat, Glat, Gloc, Silf and Sill.
+          Thanks @mhosken! (#1054).
+        - [varLib] Default to using axis "name" attribute if "labelname" element
+          is missing (588f524).
+        - [merge] Added support for merging Script records. Remove unused features
+          and lookups after merge (d802580, 556508b).
+        - Added ``fontTools.svgLib`` package. Includes a parser for SVG Paths that
+          supports the Pen protocol (#1051). Also, added a snippet to convert SVG
+          outlines to UFO GLIF (#1053).
+        - [AAT] Added support for ``ankr``, ``bsln``, ``mort``, ``morx``, ``gcid``,
+          and ``cidg``.
+        - [subset] Implemented subsetting of ``prop``, ``opbd``, ``bsln``, ``lcar``.
+        
+        3.15.1 (released 2017-08-18)
+        ----------------------------
+        
+        - [otConverters] Implemented ``__add__`` and ``__radd__`` methods on
+          ``otConverters._LazyList`` that decompile a lazy list before adding
+          it to another list or ``_LazyList`` instance. Fixes an ``AttributeError``
+          in the ``subset`` module when attempting to sum ``_LazyList`` objects
+          (6ef48bd2, 1aef1683).
+        - [AAT] Support the `opbd` table with optical bounds (a47f6588).
+        - [AAT] Support `prop` table with glyph properties (d05617b4).
+        
+        
+        3.15.0 (released 2017-08-17)
+        ----------------------------
+        
+        - [AAT] Added support for AAT lookups. The ``lcar`` table can be decompiled
+          and recompiled; futher work needed to handle ``morx`` table (#1025).
+        - [subset] Keep (empty) DefaultLangSys for Script 'DFLT' (6eb807b5).
+        - [subset] Support GSUB/GPOS.FeatureVariations (fe01d87b).
+        - [varLib] In ``models.supportScalars``, ignore an axis when its peak value
+          is 0 (fixes #1020).
+        - [varLib] Add default mappings to all axes in avar to fix rendering issue
+          in some rasterizers (19c4b377, 04eacf13).
+        - [varLib] Flatten multiple tail PairPosFormat2 subtables before merging
+          (c55ef525).
+        - [ttLib] Added support for recalculating font bounding box in ``CFF`` and
+          ``head`` tables, and min/max values in ``hhea`` and ``vhea`` tables (#970).
+        
+        3.14.0 (released 2017-07-31)
+        ----------------------------
+        
+        - [varLib.merger] Remove Extensions subtables before merging (f7c20cf8).
+        - [varLib] Initialize the avar segment map with required default entries
+          (#1014).
+        - [varLib] Implemented optimal IUP optmiziation (#1019).
+        - [otData] Add ``AxisValueFormat4`` for STAT table v1.2 from OT v1.8.2
+          (#1015).
+        - [name] Fixed BCP46 language tag for Mac langID=9: 'si' -> 'sl'.
+        - [subset] Return value from ``_DehintingT2Decompiler.op_hintmask``
+          (c0d672ba).
+        - [cffLib] Allow to get TopDict by index as well as by name (dca96c9c).
+        - [cffLib] Removed global ``isCFF2`` state; use one set of classes for
+          both CFF and CFF2, maintaining backward compatibility existing code (#1007).
+        - [cffLib] Deprecated maxstack operator, per OpenType spec update 1.8.1.
+        - [cffLib] Added missing default (-100) for UnderlinePosition (#983).
+        - [feaLib] Enable setting nameIDs greater than 255 (#1003).
+        - [varLib] Recalculate ValueFormat when merging SinglePos (#996).
+        - [varLib] Do not emit MVAR if there are no entries in the variation store
+          (#987).
+        - [ttx] For ``-x`` option, pad with space if table tag length is < 4.
+        
+        3.13.1 (released 2017-05-30)
+        ----------------------------
+        
+        - [feaLib.builder] Removed duplicate lookups optimization. The original
+          lookup order and semantics of the feature file are preserved (#976).
+        
+        3.13.0 (released 2017-05-24)
+        ----------------------------
+        
+        - [varLib.mutator] Implement IUP optimization (#969).
+        - [_g_l_y_f.GlyphCoordinates] Changed ``__bool__()`` semantics to match those
+          of other iterables (e46f949). Removed ``__abs__()`` (3db5be2).
+        - [varLib.interpolate_layout] Added ``mapped`` keyword argument to
+          ``interpolate_layout`` to allow disabling avar mapping: if False (default),
+          the location is mapped using the map element of the axes in designspace file;
+          if True, it is assumed that location is in designspace's internal space and
+          no mapping is performed (#950, #975).
+        - [varLib.interpolate_layout] Import designspace-loading logic from varLib.
+        - [varLib] Fixed bug with recombining PairPosClass2 subtables (81498e5, #914).
+        - [cffLib.specializer] When copying iterables, cast to list (462b7f86).
+        
+        3.12.1 (released 2017-05-18)
+        ----------------------------
+        
+        - [pens.t2CharStringPen] Fixed AttributeError when calling addComponent in
+          T2CharStringPen (#965).
+        
+        3.12.0 (released 2017-05-17)
+        ----------------------------
+        
+        - [cffLib.specializer] Added new ``specializer`` module to optimize CFF
+          charstrings, used by the T2CharStringPen (#948).
+        - [varLib.mutator] Sort glyphs by component depth before calculating composite
+          glyphs' bounding boxes to ensure deltas are correctly caclulated (#945).
+        - [_g_l_y_f] Fixed loss of precision in GlyphCoordinates by using 'd' (double)
+          instead of 'f' (float) as ``array.array`` typecode (#963, #964).
+        
+        3.11.0 (released 2017-05-03)
+        ----------------------------
+        
+        - [t2CharStringPen] Initial support for specialized Type2 path operators:
+          vmoveto, hmoveto, vlineto, hlineto, vvcurveto, hhcurveto, vhcurveto and
+          hvcurveto. This should produce more compact charstrings (#940, #403).
+        - [Doc] Added Sphinx sources for the documentation. Thanks @gferreira (#935).
+        - [fvar] Expose flags in XML (#932)
+        - [name] Add helper function for building multi-lingual names (#921)
+        - [varLib] Fixed kern merging when a PairPosFormat2 has ClassDef1 with glyphs
+          that are NOT present in the Coverage (1b5e1c4, #939).
+        - [varLib] Fixed non-deterministic ClassDef order with PY3 (f056c12, #927).
+        - [feLib] Throw an error when the same glyph is defined in multiple mark
+          classes within the same lookup (3e3ff00, #453).
+        
+        3.10.0 (released 2017-04-14)
+        ----------------------------
+        
+        - [varLib] Added support for building ``avar`` table, using the designspace
+          ``<map>`` elements.
+        - [varLib] Removed unused ``build(..., axisMap)`` argument. Axis map should
+          be specified in designspace file now. We do not accept nonstandard axes
+          if ``<axes>`` element is not present.
+        - [varLib] Removed "custom" axis from the ``standard_axis_map``. This was
+          added before when glyphsLib was always exporting the (unused) custom axis.
+        - [varLib] Added partial support for building ``MVAR`` table; does not
+          implement ``gasp`` table variations yet.
+        - [pens] Added FilterPen base class, for pens that control another pen;
+          factored out ``addComponent`` method from BasePen into a separate abstract
+          DecomposingPen class; added DecomposingRecordingPen, which records
+          components decomposed as regular contours.
+        - [TSI1] Fixed computation of the textLength of VTT private tables (#913).
+        - [loggingTools] Added ``LogMixin`` class providing a ``log`` property to
+          subclasses, which returns a ``logging.Logger`` named after the latter.
+        - [loggingTools] Added ``assertRegex`` method to ``CapturingLogHandler``.
+        - [py23] Added backport for python 3's ``types.SimpleNamespace`` class.
+        - [EBLC] Fixed issue with python 3 ``zip`` iterator.
+        
+        3.9.2 (released 2017-04-08)
+        ---------------------------
+        
+        - [pens] Added pen to draw glyphs using WxPython ``GraphicsPath`` class:
+          https://wxpython.org/docs/api/wx.GraphicsPath-class.html
+        - [varLib.merger] Fixed issue with recombining multiple PairPosFormat2
+          subtables (#888)
+        - [varLib] Do not encode gvar deltas that are all zeroes, or if all values
+          are smaller than tolerance.
+        - [ttLib] _TTGlyphSet glyphs now also have ``height`` and ``tsb`` (top
+          side bearing) attributes from the ``vmtx`` table, if present.
+        - [glyf] In ``GlyphCoordintes`` class, added ``__bool__`` / ``__nonzero__``
+          methods, and ``array`` property to get raw array.
+        - [ttx] Support reading TTX files with BOM (#896)
+        - [CFF2] Fixed the reporting of the number of regions in the font.
+        
+        3.9.1 (released 2017-03-20)
+        ---------------------------
+        
+        - [varLib.merger] Fixed issue while recombining multiple PairPosFormat2
+          subtables if they were split because of offset overflows (9798c30).
+        - [varLib.merger] Only merge multiple PairPosFormat1 subtables if there is
+          at least one of the fonts with a non-empty Format1 subtable (0f5a46b).
+        - [varLib.merger] Fixed IndexError with empty ClassDef1 in PairPosFormat2
+          (aad0d46).
+        - [varLib.merger] Avoid reusing Class2Record (mutable) objects (e6125b3).
+        - [varLib.merger] Calculate ClassDef1 and ClassDef2's Format when merging
+          PairPosFormat2 (23511fd).
+        - [macUtils] Added missing ttLib import (b05f203).
+        
+        3.9.0 (released 2017-03-13)
+        ---------------------------
+        
+        - [feaLib] Added (partial) support for parsing feature file comments ``# ...``
+          appearing in between statements (#879).
+        - [feaLib] Cleaned up syntax tree for FeatureNames.
+        - [ttLib] Added support for reading/writing ``CFF2`` table (thanks to
+          @readroberts at Adobe), and ``TTFA`` (ttfautohint) table.
+        - [varLib] Fixed regression introduced with 3.8.0 in the calculation of
+          ``NumShorts``, i.e. the number of deltas in ItemVariationData's delta sets
+          that use a 16-bit representation (b2825ff).
+        
+        3.8.0 (released 2017-03-05)
+        ---------------------------
+        
+        - New pens: MomentsPen, StatisticsPen, RecordingPen, and TeePen.
+        - [misc] Added new ``fontTools.misc.symfont`` module, for symbolic font
+          statistical analysis; requires ``sympy`` (http://www.sympy.org/en/index.html)
+        - [varLib] Added experimental ``fontTools.varLib.interpolatable`` module for
+          finding wrong contour order between different masters
+        - [varLib] designspace.load() now returns a dictionary, instead of a tuple,
+          and supports <axes> element (#864); the 'masters' item was renamed 'sources',
+          like the <sources> element in the designspace document
+        - [ttLib] Fixed issue with recalculating ``head`` modified timestamp when
+          saving CFF fonts
+        - [ttLib] In TupleVariation, round deltas before compiling (#861, fixed #592)
+        - [feaLib] Ignore duplicate glyphs in classes used as MarkFilteringSet and
+          MarkAttachmentType (#863)
+        - [merge] Changed the ``gasp`` table merge logic so that only the one from
+          the first font is retained, similar to other hinting tables (#862)
+        - [Tests] Added tests for the ``varLib`` package, as well as test fonts
+          from the "Annotated OpenType Specification" (AOTS) to exercise ``ttLib``'s
+          table readers/writers (<https://github.com/adobe-type-tools/aots>)
+        
+        3.7.2 (released 2017-02-17)
+        ---------------------------
+        
+        - [subset] Keep advance widths when stripping ".notdef" glyph outline in
+          CID-keyed CFF fonts (#845)
+        - [feaLib] Zero values now produce the same results as makeotf (#633, #848)
+        - [feaLib] More compact encoding for “Contextual positioning with in-line
+          single positioning rules” (#514)
+        
+        3.7.1 (released 2017-02-15)
+        ---------------------------
+        
+        - [subset] Fixed issue with ``--no-hinting`` option whereby advance widths in
+          Type 2 charstrings were also being stripped (#709, #343)
+        - [feaLib] include statements now resolve relative paths like makeotf (#838)
+        - [feaLib] table ``name`` now handles Unicode codepoints beyond the Basic
+          Multilingual Plane, also supports old-style MacOS platform encodings (#842)
+        - [feaLib] correctly escape string literals when emitting feature syntax (#780)
+        
+        3.7.0 (released 2017-02-11)
+        ---------------------------
+        
+        - [ttx, mtiLib] Preserve ordering of glyph alternates in GSUB type 3 (#833).
+        - [feaLib] Glyph names can have dashes, as per new AFDKO syntax v1.20 (#559).
+        - [feaLib] feaLib.Parser now needs the font's glyph map for parsing.
+        - [varLib] Fix regression where GPOS values were stored as 0.
+        - [varLib] Allow merging of class-based kerning when ClassDefs are different
+        
+        3.6.3 (released 2017-02-06)
+        ---------------------------
+        
+        - [varLib] Fix building variation of PairPosFormat2 (b5c34ce).
+        - Populate defaults even for otTables that have postRead (e45297b).
+        - Fix compiling of MultipleSubstFormat1 with zero 'out' glyphs (b887860).
+        
+        3.6.2 (released 2017-01-30)
+        ---------------------------
+        
+        - [varLib.merger] Fixed "TypeError: reduce() of empty sequence with no
+          initial value" (3717dc6).
+        
+        3.6.1 (released 2017-01-28)
+        ---------------------------
+        
+        -  [py23] Fixed unhandled exception occurring at interpreter shutdown in
+           the "last resort" logging handler (972b3e6).
+        -  [agl] Ensure all glyph names are of native 'str' type; avoid mixing
+           'str' and 'unicode' in TTFont.glyphOrder (d8c4058).
+        -  Fixed inconsistent title levels in README.rst that caused PyPI to
+           incorrectly render the reStructuredText page.
+        
+        3.6.0 (released 2017-01-26)
+        ---------------------------
+        
+        -  [varLib] Refactored and improved the variation-font-building process.
+        -  Assembly code in the fpgm, prep, and glyf tables is now indented in
+           XML output for improved readability. The ``instruction`` element is
+           written as a simple tag if empty (#819).
+        -  [ttx] Fixed 'I/O operation on closed file' error when dumping
+           multiple TTXs to standard output with the '-o -' option.
+        -  The unit test modules (``*_test.py``) have been moved outside of the
+           fontTools package to the Tests folder, thus they are no longer
+           installed (#811).
+        
+        3.5.0 (released 2017-01-14)
+        ---------------------------
+        
+        -  Font tables read from XML can now be written back to XML with no
+           loss.
+        -  GSUB/GPOS LookupType is written out in XML as an element, not
+           comment. (#792)
+        -  When parsing cmap table, do not store items mapped to glyph id 0.
+           (#790)
+        -  [otlLib] Make ClassDef sorting deterministic. Fixes #766 (7d1ddb2)
+        -  [mtiLib] Added unit tests (#787)
+        -  [cvar] Implemented cvar table
+        -  [gvar] Renamed GlyphVariation to TupleVariation to match OpenType
+           terminology.
+        -  [otTables] Handle gracefully empty VarData.Item array when compiling
+           XML. (#797)
+        -  [varLib] Re-enabled generation of ``HVAR`` table for fonts with
+           TrueType outlines; removed ``--build-HVAR`` command-line option.
+        -  [feaLib] The parser can now be extended to support non-standard
+           statements in FEA code by using a customized Abstract Syntax Tree.
+           See, for example, ``feaLib.builder_test.test_extensions`` and
+           baseClass.feax (#794, fixes #773).
+        -  [feaLib] Added ``feaLib`` command to the 'fonttools' command-line
+           tool; applies a feature file to a font. ``fonttools feaLib -h`` for
+           help.
+        -  [pens] The ``T2CharStringPen`` now takes an optional
+           ``roundTolerance`` argument to control the rounding of coordinates
+           (#804, fixes #769).
+        -  [ci] Measure test coverage on all supported python versions and OSes,
+           combine coverage data and upload to
+           https://codecov.io/gh/fonttools/fonttools (#786)
+        -  [ci] Configured Travis and Appveyor for running tests on Python 3.6
+           (#785, 55c03bc)
+        -  The manual pages installation directory can be customized through
+           ``FONTTOOLS_MANPATH`` environment variable (#799, fixes #84).
+        -  [Snippets] Added otf2ttf.py, for converting fonts from CFF to
+           TrueType using the googlei18n/cu2qu module (#802)
+        
+        3.4.0 (released 2016-12-21)
+        ---------------------------
+        
+        -  [feaLib] Added support for generating FEA text from abstract syntax
+           tree (AST) objects (#776). Thanks @mhosken
+        -  Added ``agl.toUnicode`` function to convert AGL-compliant glyph names
+           to Unicode strings (#774)
+        -  Implemented MVAR table (b4d5381)
+        
+        3.3.1 (released 2016-12-15)
+        ---------------------------
+        
+        -  [setup] We no longer use versioneer.py to compute fonttools version
+           from git metadata, as this has caused issues for some users (#767).
+           Now we bump the version strings manually with a custom ``release``
+           command of setup.py script.
+        
+        3.3.0 (released 2016-12-06)
+        ---------------------------
+        
+        -  [ttLib] Implemented STAT table from OpenType 1.8 (#758)
+        -  [cffLib] Fixed decompilation of CFF fonts containing non-standard
+           key/value pairs in FontDict (issue #740; PR #744)
+        -  [py23] minor: in ``round3`` function, allow the second argument to be
+           ``None`` (#757)
+        -  The standalone ``sstruct`` and ``xmlWriter`` modules, deprecated
+           since vesion 3.2.0, have been removed. They can be imported from the
+           ``fontTools.misc`` package.
+        
+        3.2.3 (released 2016-12-02)
+        ---------------------------
+        
+        -  [py23] optimized performance of round3 function; added backport for
+           py35 math.isclose() (9d8dacb)
+        -  [subset] fixed issue with 'narrow' (UCS-2) Python 2 builds and
+           ``--text``/``--text-file`` options containing non-BMP chararcters
+           (16d0e5e)
+        -  [varLib] fixed issuewhen normalizing location values (8fa2ee1, #749)
+        -  [inspect] Made it compatible with both python2 and python3 (167ee60,
+           #748). Thanks @pnemade
+        
+        3.2.2 (released 2016-11-24)
+        ---------------------------
+        
+        -  [varLib] Do not emit null axes in fvar (1bebcec). Thanks @robmck-ms
+        -  [varLib] Handle fonts without GPOS (7915a45)
+        -  [merge] Ignore LangSys if None (a11bc56)
+        -  [subset] Fix subsetting MathVariants (78d3cbe)
+        -  [OS/2] Fix "Private Use (plane 15)" range (08a0d55). Thanks @mashabow
+        
+        3.2.1 (released 2016-11-03)
+        ---------------------------
+        
+        -  [OS/2] fix checking ``fsSelection`` bits matching ``head.macStyle``
+           bits
+        -  [varLib] added ``--build-HVAR`` option to generate ``HVAR`` table for
+           fonts with TrueType outlines. For ``CFF2``, it is enabled by default.
+        
+        3.2.0 (released 2016-11-02)
+        ---------------------------
+        
+        -  [varLib] Improve support for OpenType 1.8 Variable Fonts:
+        -  Implement GDEF's VariationStore
+        -  Implement HVAR/VVAR tables
+        -  Partial support for loading MutatorMath .designspace files with
+           varLib.designspace module
+        -  Add varLib.models with Variation fonts interpolation models
+        -  Implement GSUB/GPOS FeatureVariations
+        -  Initial support for interpolating and merging OpenType Layout tables
+           (see ``varLib.interpolate_layout`` and ``varLib.merger`` modules)
+        -  [API change] Change version to be an integer instead of a float in
+           XML output for GSUB, GPOS, GDEF, MATH, BASE, JSTF, HVAR, VVAR, feat,
+           hhea and vhea tables. Scripts that set the Version for those to 1.0
+           or other float values also need fixing. A warning is emitted when
+           code or XML needs fix.
+        -  several bug fixes to the cffLib module, contributed by Adobe's
+           @readroberts
+        -  The XML output for CFF table now has a 'major' and 'minor' elements
+           for specifying whether it's version 1.0 or 2.0 (support for CFF2 is
+           coming soon)
+        -  [setup.py] remove undocumented/deprecated ``extra_path`` Distutils
+           argument. This means that we no longer create a "FontTools" subfolder
+           in site-packages containing the actual fontTools package, as well as
+           the standalone xmlWriter and sstruct modules. The latter modules are
+           also deprecated, and scheduled for removal in upcoming releases.
+           Please change your import statements to point to from fontTools.misc
+           import xmlWriter and from fontTools.misc import sstruct.
+        -  [scripts] Add a 'fonttools' command-line tool that simply runs
+           ``fontTools.*`` sub-modules: e.g. ``fonttools ttx``,
+           ``fonttools subset``, etc.
+        -  [hmtx/vmts] Read advance width/heights as unsigned short (uint16);
+           automatically round float values to integers.
+        -  [ttLib/xmlWriter] add 'newlinestr=None' keyword argument to
+           ``TTFont.saveXML`` for overriding os-specific line endings (passed on
+           to ``XMLWriter`` instances).
+        -  [versioning] Use versioneer instead of ``setuptools_scm`` to
+           dynamically load version info from a git checkout at import time.
+        -  [feaLib] Support backslash-prefixed glyph names.
+        
+        3.1.2 (released 2016-09-27)
+        ---------------------------
+        
+        -  restore Makefile as an alternative way to build/check/install
+        -  README.md: update instructions for installing package from source,
+           and for running test suite
+        -  NEWS: Change log was out of sync with tagged release
+        
+        3.1.1 (released 2016-09-27)
+        ---------------------------
+        
+        -  Fix ``ttLibVersion`` attribute in TTX files still showing '3.0'
+           instead of '3.1'.
+        -  Use ``setuptools_scm`` to manage package versions.
+        
+        3.1.0 (released 2016-09-26)
+        ---------------------------
+        
+        -  [feaLib] New library to parse and compile Adobe FDK OpenType Feature
+           files.
+        -  [mtiLib] New library to parse and compile Monotype 'FontDame'
+           OpenType Layout Tables files.
+        -  [voltLib] New library to parse Microsoft VOLT project files.
+        -  [otlLib] New library to work with OpenType Layout tables.
+        -  [varLib] New library to work with OpenType Font Variations.
+        -  [pens] Add ttGlyphPen to draw to TrueType glyphs, and t2CharStringPen
+           to draw to Type 2 Charstrings (CFF); add areaPen and perimeterPen.
+        -  [ttLib.tables] Implement 'meta' and 'trak' tables.
+        -  [ttx] Add --flavor option for compiling to 'woff' or 'woff2'; add
+           ``--with-zopfli`` option to use Zopfli to compress WOFF 1.0 fonts.
+        -  [subset] Support subsetting 'COLR'/'CPAL' and 'CBDT'/'CBLC' color
+           fonts tables, and 'gvar' table for variation fonts.
+        -  [Snippets] Add ``symfont.py``, for symbolic font statistics analysis;
+           interpolatable.py, a preliminary script for detecting interpolation
+           errors; ``{merge,dump}_woff_metadata.py``.
+        -  [classifyTools] Helpers to classify things into classes.
+        -  [CI] Run tests on Windows, Linux and macOS using Appveyor and Travis
+           CI; check unit test coverage with Coverage.py/Coveralls; automatic
+           deployment to PyPI on tags.
+        -  [loggingTools] Use Python built-in logging module to print messages.
+        -  [py23] Make round() behave like Python 3 built-in round(); define
+           round2() and round3().
+        
+        3.0 (released 2015-09-01)
+        -------------------------
+        
+        -  Add Snippet scripts for cmap subtable format conversion, printing
+           GSUB/GPOS features, building a GX font from two masters
+        -  TTX WOFF2 support and a ``-f`` option to overwrite output file(s)
+        -  Support GX tables: ``avar``, ``gvar``, ``fvar``, ``meta``
+        -  Support ``feat`` and gzip-compressed SVG tables
+        -  Upgrade Mac East Asian encodings to native implementation if
+           available
+        -  Add Roman Croatian and Romanian encodings, codecs for mac-extended
+           East Asian encodings
+        -  Implement optimal GLYF glyph outline packing; disabled by default
+        
+        2.5 (released 2014-09-24)
+        -------------------------
+        
+        -  Add a Qt pen
+        -  Add VDMX table converter
+        -  Load all OpenType sub-structures lazily
+        -  Add support for cmap format 13.
+        -  Add pyftmerge tool
+        -  Update to Unicode 6.3.0d3
+        -  Add pyftinspect tool
+        -  Add support for Google CBLC/CBDT color bitmaps, standard EBLC/EBDT
+           embedded bitmaps, and ``SVG`` table (thanks to Read Roberts at Adobe)
+        -  Add support for loading, saving and ttx'ing WOFF file format
+        -  Add support for Microsoft COLR/CPAL layered color glyphs
+        -  Support PyPy
+        -  Support Jython, by replacing numpy with array/lists modules and
+           removed it, pure-Python StringIO, not cStringIO
+        -  Add pyftsubset and Subsetter object, supporting CFF and TTF
+        -  Add to ttx args for -q for quiet mode, -z to choose a bitmap dump
+           format
+        
+        2.4 (released 2013-06-22)
+        -------------------------
+        
+        -  Option to write to arbitrary files
+        -  Better dump format for DSIG
+        -  Better detection of OTF XML
+        -  Fix issue with Apple's kern table format
+        -  Fix mangling of TT glyph programs
+        -  Fix issues related to mona.ttf
+        -  Fix Windows Installer instructions
+        -  Fix some modern MacOS issues
+        -  Fix minor issues and typos
+        
+        2.3 (released 2009-11-08)
+        -------------------------
+        
+        -  TrueType Collection (TTC) support
+        -  Python 2.6 support
+        -  Update Unicode data to 5.2.0
+        -  Couple of bug fixes
+        
+        2.2 (released 2008-05-18)
+        -------------------------
+        
+        -  ClearType support
+        -  cmap format 1 support
+        -  PFA font support
+        -  Switched from Numeric to numpy
+        -  Update Unicode data to 5.1.0
+        -  Update AGLFN data to 1.6
+        -  Many bug fixes
+        
+        2.1 (released 2008-01-28)
+        -------------------------
+        
+        -  Many years worth of fixes and features
+        
+        2.0b2 (released 2002-??-??)
+        ---------------------------
+        
+        -  Be "forgiving" when interpreting the maxp table version field:
+           interpret any value as 1.0 if it's not 0.5. Fixes dumping of these
+           GPL fonts: http://www.freebsd.org/cgi/pds.cgi?ports/chinese/wangttf
+        -  Fixed ttx -l: it turned out this part of the code didn't work with
+           Python 2.2.1 and earlier. My bad to do most of my testing with a
+           different version than I shipped TTX with :-(
+        -  Fixed bug in ClassDef format 1 subtable (Andreas Seidel bumped into
+           this one).
+        
+        2.0b1 (released 2002-09-10)
+        ---------------------------
+        
+        -  Fixed embarrassing bug: the master checksum in the head table is now
+           calculated correctly even on little-endian platforms (such as Intel).
+        -  Made the cmap format 4 compiler smarter: the binary data it creates
+           is now more or less as compact as possible. TTX now makes more
+           compact data than in any shipping font I've tested it with.
+        -  Dump glyph names as a separate "GlyphOrder" pseudo table as opposed
+           to as part of the glyf table (obviously needed for CFF-OTF's).
+        -  Added proper support for the CFF table.
+        -  Don't barf on empty tables (questionable, but "there are font out
+           there...")
+        -  When writing TT glyf data, align glyphs on 4-byte boundaries. This
+           seems to be the current recommendation by MS. Also: don't barf on
+           fonts which are already 4-byte aligned.
+        -  Windows installer contributed bu Adam Twardoch! Yay!
+        -  Changed the command line interface again, now by creating one new
+           tool replacing the old ones: ttx It dumps and compiles, depending on
+           input file types. The options have changed somewhat.
+        -  The -d option is back (output dir)
+        -  ttcompile's -i options is now called -m (as in "merge"), to avoid
+           clash with dump's -i.
+        -  The -s option ("split tables") no longer creates a directory, but
+           instead outputs a small .ttx file containing references to the
+           individual table files. This is not a true link, it's a simple file
+           name, and the referenced file should be in the same directory so
+           ttcompile can find them.
+        -  compile no longer accepts a directory as input argument. Instead it
+           can parse the new "mini-ttx" format as output by "ttx -s".
+        -  all arguments are input files
+        -  Renamed the command line programs and moved them to the Tools
+           subdirectory. They are now installed by the setup.py install script.
+        -  Added OpenType support. BASE, GDEF, GPOS, GSUB and JSTF are (almost)
+           fully supported. The XML output is not yet final, as I'm still
+           considering to output certain subtables in a more human-friendly
+           manner.
+        -  Fixed 'kern' table to correctly accept subtables it doesn't know
+           about, as well as interpreting Apple's definition of the 'kern' table
+           headers correctly.
+        -  Fixed bug where glyphnames were not calculated from 'cmap' if it was
+           (one of the) first tables to be decompiled. More specifically: it
+           cmap was the first to ask for a glyphID -> glyphName mapping.
+        -  Switched XML parsers: use expat instead of xmlproc. Should be faster.
+        -  Removed my UnicodeString object: I now require Python 2.0 or up,
+           which has unicode support built in.
+        -  Removed assert in glyf table: redundant data at the end of the table
+           is now ignored instead of raising an error. Should become a warning.
+        -  Fixed bug in hmtx/vmtx code that only occured if all advances were
+           equal.
+        -  Fixed subtle bug in TT instruction disassembler.
+        -  Couple of fixes to the 'post' table.
+        -  Updated OS/2 table to latest spec.
+        
+        1.0b1 (released 2001-08-10)
+        ---------------------------
+        
+        -  Reorganized the command line interface for ttDump.py and
+           ttCompile.py, they now behave more like "normal" command line tool,
+           in that they accept multiple input files for batch processing.
+        -  ttDump.py and ttCompile.py don't silently override files anymore, but
+           ask before doing so. Can be overridden by -f.
+        -  Added -d option to both ttDump.py and ttCompile.py.
+        -  Installation is now done with distutils. (Needs work for environments
+           without compilers.)
+        -  Updated installation instructions.
+        -  Added some workarounds so as to handle certain buggy fonts more
+           gracefully.
+        -  Updated Unicode table to Unicode 3.0 (Thanks Antoine!)
+        -  Included a Python script by Adam Twardoch that adds some useful stuff
+           to the Windows registry.
+        -  Moved the project to SourceForge.
+        
+        1.0a6 (released 2000-03-15)
+        ---------------------------
+        
+        -  Big reorganization: made ttLib a subpackage of the new fontTools
+           package, changed several module names. Called the entire suite
+           "FontTools"
+        -  Added several submodules to fontTools, some new, some older.
+        -  Added experimental CFF/GPOS/GSUB support to ttLib, read-only (but XML
+           dumping of GPOS/GSUB is for now disabled)
+        -  Fixed hdmx endian bug
+        -  Added -b option to ttCompile.py, it disables recalculation of
+           bounding boxes, as requested by Werner Lemberg.
+        -  Renamed tt2xml.pt to ttDump.py and xml2tt.py to ttCompile.py
+        -  Use ".ttx" as file extension instead of ".xml".
+        -  TTX is now the name of the XML-based *format* for TT fonts, and not
+           just an application.
+        
+        1.0a5
+        -----
+        
+        Never released
+        
+        -  More tables supported: hdmx, vhea, vmtx
+        
+        1.0a3 & 1.0a4
+        -------------
+        
+        Never released
+        
+        -  fixed most portability issues
+        -  retracted the "Euro_or_currency" change from 1.0a2: it was
+           nonsense!
+        
+        1.0a2 (released 1999-05-02)
+        ---------------------------
+        
+        -  binary release for MacOS
+        -  genenates full FOND resources: including width table, PS font name
+           info and kern table if applicable.
+        -  added cmap format 4 support. Extra: dumps Unicode char names as XML
+           comments!
+        -  added cmap format 6 support
+        -  now accepts true type files starting with "true" (instead of just
+           0x00010000 and "OTTO")
+        -  'glyf' table support is now complete: I added support for composite
+           scale, xy-scale and two-by-two for the 'glyf' table. For now,
+           component offset scale behaviour defaults to Apple-style. This only
+           affects the (re)calculation of the glyph bounding box.
+        -  changed "Euro" to "Euro_or_currency" in the Standard Apple Glyph
+           order list, since we cannot tell from the 'post' table which is
+           meant. I should probably doublecheck with a Unicode encoding if
+           available. (This does not affect the output!)
+        
+        Fixed bugs: - 'hhea' table is now recalculated correctly - fixed wrong
+        assumption about sfnt resource names
+        
+        1.0a1 (released 1999-04-27)
+        ---------------------------
+        
+        -  initial binary release for MacOS
+        
+Platform: Any
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Console
+Classifier: Environment :: Other Environment
+Classifier: Intended Audience :: Developers
+Classifier: Intended Audience :: End Users/Desktop
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Natural Language :: English
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
+Classifier: Topic :: Text Processing :: Fonts
+Classifier: Topic :: Multimedia :: Graphics
+Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
+Provides-Extra: woff
+Provides-Extra: all
+Provides-Extra: symfont
+Provides-Extra: interpolatable
+Provides-Extra: unicode
+Provides-Extra: type1
+Provides-Extra: lxml
+Provides-Extra: ufo
+Provides-Extra: plot
+Provides-Extra: graphite
diff --git a/Lib/fonttools.egg-info/SOURCES.txt b/Lib/fonttools.egg-info/SOURCES.txt
new file mode 100644
index 0000000..29f3b12
--- /dev/null
+++ b/Lib/fonttools.egg-info/SOURCES.txt
@@ -0,0 +1,1820 @@
+.appveyor.yml
+.codecov.yml
+.coveragerc
+.travis.yml
+LICENSE
+LICENSE.external
+MANIFEST.in
+Makefile
+NEWS.rst
+README.rst
+dev-requirements.txt
+fonttools
+requirements.txt
+run-tests.sh
+setup.cfg
+setup.py
+tox.ini
+.travis/after_success.sh
+.travis/before_install.sh
+.travis/install.sh
+.travis/run.sh
+Doc/Makefile
+Doc/make.bat
+Doc/man/man1/ttx.1
+Doc/source/afmLib.rst
+Doc/source/agl.rst
+Doc/source/cffLib.rst
+Doc/source/conf.py
+Doc/source/encodings.rst
+Doc/source/feaLib.rst
+Doc/source/index.rst
+Doc/source/merge.rst
+Doc/source/subset.rst
+Doc/source/t1Lib.rst
+Doc/source/ttx.rst
+Doc/source/voltLib.rst
+Doc/source/designspaceLib/index.rst
+Doc/source/designspaceLib/readme.rst
+Doc/source/designspaceLib/scripting.rst
+Doc/source/misc/arrayTools.rst
+Doc/source/misc/bezierTools.rst
+Doc/source/misc/classifyTools.rst
+Doc/source/misc/eexec.rst
+Doc/source/misc/encodingTools.rst
+Doc/source/misc/fixedTools.rst
+Doc/source/misc/index.rst
+Doc/source/misc/loggingTools.rst
+Doc/source/misc/psCharStrings.rst
+Doc/source/misc/sstruct.rst
+Doc/source/misc/testTools.rst
+Doc/source/misc/textTools.rst
+Doc/source/misc/timeTools.rst
+Doc/source/misc/transform.rst
+Doc/source/misc/xmlReader.rst
+Doc/source/misc/xmlWriter.rst
+Doc/source/pens/areaPen.rst
+Doc/source/pens/basePen.rst
+Doc/source/pens/boundsPen.rst
+Doc/source/pens/filterPen.rst
+Doc/source/pens/index.rst
+Doc/source/pens/perimeterPen.rst
+Doc/source/pens/pointInsidePen.rst
+Doc/source/pens/recordingPen.rst
+Doc/source/pens/statisticsPen.rst
+Doc/source/pens/t2CharStringPen.rst
+Doc/source/pens/teePen.rst
+Doc/source/pens/transformPen.rst
+Doc/source/ttLib/index.rst
+Doc/source/ttLib/macUtils.rst
+Doc/source/ttLib/sfnt.rst
+Doc/source/ttLib/tables.rst
+Doc/source/ttLib/woff2.rst
+Doc/source/ufoLib/converters.rst
+Doc/source/ufoLib/filenames.rst
+Doc/source/ufoLib/glifLib.rst
+Doc/source/ufoLib/pointPen.rst
+Doc/source/ufoLib/ufoLib.rst
+Doc/source/varLib/designspace.rst
+Doc/source/varLib/index.rst
+Doc/source/varLib/interpolatable.rst
+Doc/source/varLib/interpolate_layout.rst
+Doc/source/varLib/merger.rst
+Doc/source/varLib/models.rst
+Doc/source/varLib/mutator.rst
+Lib/fontTools/__init__.py
+Lib/fontTools/__main__.py
+Lib/fontTools/afmLib.py
+Lib/fontTools/agl.py
+Lib/fontTools/fontBuilder.py
+Lib/fontTools/merge.py
+Lib/fontTools/ttx.py
+Lib/fontTools/unicode.py
+Lib/fontTools/cffLib/__init__.py
+Lib/fontTools/cffLib/specializer.py
+Lib/fontTools/cffLib/width.py
+Lib/fontTools/designspaceLib/__init__.py
+Lib/fontTools/encodings/MacRoman.py
+Lib/fontTools/encodings/StandardEncoding.py
+Lib/fontTools/encodings/__init__.py
+Lib/fontTools/encodings/codecs.py
+Lib/fontTools/feaLib/__init__.py
+Lib/fontTools/feaLib/__main__.py
+Lib/fontTools/feaLib/ast.py
+Lib/fontTools/feaLib/builder.py
+Lib/fontTools/feaLib/error.py
+Lib/fontTools/feaLib/lexer.py
+Lib/fontTools/feaLib/parser.py
+Lib/fontTools/misc/__init__.py
+Lib/fontTools/misc/arrayTools.py
+Lib/fontTools/misc/bezierTools.py
+Lib/fontTools/misc/classifyTools.py
+Lib/fontTools/misc/cliTools.py
+Lib/fontTools/misc/dictTools.py
+Lib/fontTools/misc/eexec.py
+Lib/fontTools/misc/encodingTools.py
+Lib/fontTools/misc/etree.py
+Lib/fontTools/misc/filenames.py
+Lib/fontTools/misc/fixedTools.py
+Lib/fontTools/misc/intTools.py
+Lib/fontTools/misc/loggingTools.py
+Lib/fontTools/misc/macCreatorType.py
+Lib/fontTools/misc/macRes.py
+Lib/fontTools/misc/plistlib.py
+Lib/fontTools/misc/psCharStrings.py
+Lib/fontTools/misc/psLib.py
+Lib/fontTools/misc/psOperators.py
+Lib/fontTools/misc/py23.py
+Lib/fontTools/misc/sstruct.py
+Lib/fontTools/misc/symfont.py
+Lib/fontTools/misc/testTools.py
+Lib/fontTools/misc/textTools.py
+Lib/fontTools/misc/timeTools.py
+Lib/fontTools/misc/transform.py
+Lib/fontTools/misc/xmlReader.py
+Lib/fontTools/misc/xmlWriter.py
+Lib/fontTools/mtiLib/__init__.py
+Lib/fontTools/mtiLib/__main__.py
+Lib/fontTools/otlLib/__init__.py
+Lib/fontTools/otlLib/builder.py
+Lib/fontTools/otlLib/maxContextCalc.py
+Lib/fontTools/pens/__init__.py
+Lib/fontTools/pens/areaPen.py
+Lib/fontTools/pens/basePen.py
+Lib/fontTools/pens/boundsPen.py
+Lib/fontTools/pens/cocoaPen.py
+Lib/fontTools/pens/filterPen.py
+Lib/fontTools/pens/momentsPen.py
+Lib/fontTools/pens/perimeterPen.py
+Lib/fontTools/pens/pointInsidePen.py
+Lib/fontTools/pens/pointPen.py
+Lib/fontTools/pens/qtPen.py
+Lib/fontTools/pens/recordingPen.py
+Lib/fontTools/pens/reportLabPen.py
+Lib/fontTools/pens/reverseContourPen.py
+Lib/fontTools/pens/statisticsPen.py
+Lib/fontTools/pens/svgPathPen.py
+Lib/fontTools/pens/t2CharStringPen.py
+Lib/fontTools/pens/teePen.py
+Lib/fontTools/pens/transformPen.py
+Lib/fontTools/pens/ttGlyphPen.py
+Lib/fontTools/pens/wxPen.py
+Lib/fontTools/subset/__init__.py
+Lib/fontTools/subset/__main__.py
+Lib/fontTools/subset/cff.py
+Lib/fontTools/svgLib/__init__.py
+Lib/fontTools/svgLib/path/__init__.py
+Lib/fontTools/svgLib/path/arc.py
+Lib/fontTools/svgLib/path/parser.py
+Lib/fontTools/svgLib/path/shapes.py
+Lib/fontTools/t1Lib/__init__.py
+Lib/fontTools/ttLib/__init__.py
+Lib/fontTools/ttLib/macUtils.py
+Lib/fontTools/ttLib/sfnt.py
+Lib/fontTools/ttLib/standardGlyphOrder.py
+Lib/fontTools/ttLib/ttCollection.py
+Lib/fontTools/ttLib/ttFont.py
+Lib/fontTools/ttLib/woff2.py
+Lib/fontTools/ttLib/tables/B_A_S_E_.py
+Lib/fontTools/ttLib/tables/BitmapGlyphMetrics.py
+Lib/fontTools/ttLib/tables/C_B_D_T_.py
+Lib/fontTools/ttLib/tables/C_B_L_C_.py
+Lib/fontTools/ttLib/tables/C_F_F_.py
+Lib/fontTools/ttLib/tables/C_F_F__2.py
+Lib/fontTools/ttLib/tables/C_O_L_R_.py
+Lib/fontTools/ttLib/tables/C_P_A_L_.py
+Lib/fontTools/ttLib/tables/D_S_I_G_.py
+Lib/fontTools/ttLib/tables/DefaultTable.py
+Lib/fontTools/ttLib/tables/E_B_D_T_.py
+Lib/fontTools/ttLib/tables/E_B_L_C_.py
+Lib/fontTools/ttLib/tables/F_F_T_M_.py
+Lib/fontTools/ttLib/tables/F__e_a_t.py
+Lib/fontTools/ttLib/tables/G_D_E_F_.py
+Lib/fontTools/ttLib/tables/G_M_A_P_.py
+Lib/fontTools/ttLib/tables/G_P_K_G_.py
+Lib/fontTools/ttLib/tables/G_P_O_S_.py
+Lib/fontTools/ttLib/tables/G_S_U_B_.py
+Lib/fontTools/ttLib/tables/G__l_a_t.py
+Lib/fontTools/ttLib/tables/G__l_o_c.py
+Lib/fontTools/ttLib/tables/H_V_A_R_.py
+Lib/fontTools/ttLib/tables/J_S_T_F_.py
+Lib/fontTools/ttLib/tables/L_T_S_H_.py
+Lib/fontTools/ttLib/tables/M_A_T_H_.py
+Lib/fontTools/ttLib/tables/M_E_T_A_.py
+Lib/fontTools/ttLib/tables/M_V_A_R_.py
+Lib/fontTools/ttLib/tables/O_S_2f_2.py
+Lib/fontTools/ttLib/tables/S_I_N_G_.py
+Lib/fontTools/ttLib/tables/S_T_A_T_.py
+Lib/fontTools/ttLib/tables/S_V_G_.py
+Lib/fontTools/ttLib/tables/S__i_l_f.py
+Lib/fontTools/ttLib/tables/S__i_l_l.py
+Lib/fontTools/ttLib/tables/T_S_I_B_.py
+Lib/fontTools/ttLib/tables/T_S_I_C_.py
+Lib/fontTools/ttLib/tables/T_S_I_D_.py
+Lib/fontTools/ttLib/tables/T_S_I_J_.py
+Lib/fontTools/ttLib/tables/T_S_I_P_.py
+Lib/fontTools/ttLib/tables/T_S_I_S_.py
+Lib/fontTools/ttLib/tables/T_S_I_V_.py
+Lib/fontTools/ttLib/tables/T_S_I__0.py
+Lib/fontTools/ttLib/tables/T_S_I__1.py
+Lib/fontTools/ttLib/tables/T_S_I__2.py
+Lib/fontTools/ttLib/tables/T_S_I__3.py
+Lib/fontTools/ttLib/tables/T_S_I__5.py
+Lib/fontTools/ttLib/tables/T_T_F_A_.py
+Lib/fontTools/ttLib/tables/TupleVariation.py
+Lib/fontTools/ttLib/tables/V_D_M_X_.py
+Lib/fontTools/ttLib/tables/V_O_R_G_.py
+Lib/fontTools/ttLib/tables/V_V_A_R_.py
+Lib/fontTools/ttLib/tables/__init__.py
+Lib/fontTools/ttLib/tables/_a_n_k_r.py
+Lib/fontTools/ttLib/tables/_a_v_a_r.py
+Lib/fontTools/ttLib/tables/_b_s_l_n.py
+Lib/fontTools/ttLib/tables/_c_i_d_g.py
+Lib/fontTools/ttLib/tables/_c_m_a_p.py
+Lib/fontTools/ttLib/tables/_c_v_a_r.py
+Lib/fontTools/ttLib/tables/_c_v_t.py
+Lib/fontTools/ttLib/tables/_f_e_a_t.py
+Lib/fontTools/ttLib/tables/_f_p_g_m.py
+Lib/fontTools/ttLib/tables/_f_v_a_r.py
+Lib/fontTools/ttLib/tables/_g_a_s_p.py
+Lib/fontTools/ttLib/tables/_g_c_i_d.py
+Lib/fontTools/ttLib/tables/_g_l_y_f.py
+Lib/fontTools/ttLib/tables/_g_v_a_r.py
+Lib/fontTools/ttLib/tables/_h_d_m_x.py
+Lib/fontTools/ttLib/tables/_h_e_a_d.py
+Lib/fontTools/ttLib/tables/_h_h_e_a.py
+Lib/fontTools/ttLib/tables/_h_m_t_x.py
+Lib/fontTools/ttLib/tables/_k_e_r_n.py
+Lib/fontTools/ttLib/tables/_l_c_a_r.py
+Lib/fontTools/ttLib/tables/_l_o_c_a.py
+Lib/fontTools/ttLib/tables/_l_t_a_g.py
+Lib/fontTools/ttLib/tables/_m_a_x_p.py
+Lib/fontTools/ttLib/tables/_m_e_t_a.py
+Lib/fontTools/ttLib/tables/_m_o_r_t.py
+Lib/fontTools/ttLib/tables/_m_o_r_x.py
+Lib/fontTools/ttLib/tables/_n_a_m_e.py
+Lib/fontTools/ttLib/tables/_o_p_b_d.py
+Lib/fontTools/ttLib/tables/_p_o_s_t.py
+Lib/fontTools/ttLib/tables/_p_r_e_p.py
+Lib/fontTools/ttLib/tables/_p_r_o_p.py
+Lib/fontTools/ttLib/tables/_s_b_i_x.py
+Lib/fontTools/ttLib/tables/_t_r_a_k.py
+Lib/fontTools/ttLib/tables/_v_h_e_a.py
+Lib/fontTools/ttLib/tables/_v_m_t_x.py
+Lib/fontTools/ttLib/tables/asciiTable.py
+Lib/fontTools/ttLib/tables/grUtils.py
+Lib/fontTools/ttLib/tables/otBase.py
+Lib/fontTools/ttLib/tables/otConverters.py
+Lib/fontTools/ttLib/tables/otData.py
+Lib/fontTools/ttLib/tables/otTables.py
+Lib/fontTools/ttLib/tables/sbixGlyph.py
+Lib/fontTools/ttLib/tables/sbixStrike.py
+Lib/fontTools/ttLib/tables/table_API_readme.txt
+Lib/fontTools/ttLib/tables/ttProgram.py
+Lib/fontTools/ufoLib/__init__.py
+Lib/fontTools/ufoLib/converters.py
+Lib/fontTools/ufoLib/errors.py
+Lib/fontTools/ufoLib/etree.py
+Lib/fontTools/ufoLib/filenames.py
+Lib/fontTools/ufoLib/glifLib.py
+Lib/fontTools/ufoLib/kerning.py
+Lib/fontTools/ufoLib/plistlib.py
+Lib/fontTools/ufoLib/pointPen.py
+Lib/fontTools/ufoLib/utils.py
+Lib/fontTools/ufoLib/validators.py
+Lib/fontTools/unicodedata/Blocks.py
+Lib/fontTools/unicodedata/OTTags.py
+Lib/fontTools/unicodedata/ScriptExtensions.py
+Lib/fontTools/unicodedata/Scripts.py
+Lib/fontTools/unicodedata/__init__.py
+Lib/fontTools/varLib/__init__.py
+Lib/fontTools/varLib/__main__.py
+Lib/fontTools/varLib/builder.py
+Lib/fontTools/varLib/cff.py
+Lib/fontTools/varLib/featureVars.py
+Lib/fontTools/varLib/instancer.py
+Lib/fontTools/varLib/interpolatable.py
+Lib/fontTools/varLib/interpolate_layout.py
+Lib/fontTools/varLib/iup.py
+Lib/fontTools/varLib/merger.py
+Lib/fontTools/varLib/models.py
+Lib/fontTools/varLib/mutator.py
+Lib/fontTools/varLib/mvar.py
+Lib/fontTools/varLib/plot.py
+Lib/fontTools/varLib/varStore.py
+Lib/fontTools/voltLib/__init__.py
+Lib/fontTools/voltLib/ast.py
+Lib/fontTools/voltLib/error.py
+Lib/fontTools/voltLib/lexer.py
+Lib/fontTools/voltLib/parser.py
+Lib/fonttools.egg-info/PKG-INFO
+Lib/fonttools.egg-info/SOURCES.txt
+Lib/fonttools.egg-info/dependency_links.txt
+Lib/fonttools.egg-info/entry_points.txt
+Lib/fonttools.egg-info/requires.txt
+Lib/fonttools.egg-info/top_level.txt
+MetaTools/buildTableList.py
+MetaTools/buildUCD.py
+MetaTools/roundTrip.py
+Snippets/README.md
+Snippets/checksum.py
+Snippets/cmap-format.py
+Snippets/dump_woff_metadata.py
+Snippets/edit_raw_table_data.py
+Snippets/fix-dflt-langsys.py
+Snippets/interpolate.py
+Snippets/layout-features.py
+Snippets/merge_woff_metadata.py
+Snippets/otf2ttf.py
+Snippets/rename-fonts.py
+Snippets/subset-fpgm.py
+Snippets/svg2glif.py
+Tests/agl_test.py
+Tests/conftest.py
+Tests/merge_test.py
+Tests/unicodedata_test.py
+Tests/afmLib/afmLib_test.py
+Tests/afmLib/data/TestAFM.afm
+Tests/cffLib/cffLib_test.py
+Tests/cffLib/specializer_test.py
+Tests/cffLib/data/TestCFF2Widths.ttx
+Tests/cffLib/data/TestFDSelect4.ttx
+Tests/cffLib/data/TestOTF.ttx
+Tests/cffLib/data/TestSparseCFF2VF.ttx
+Tests/designspaceLib/designspace_test.py
+Tests/designspaceLib/data/test.designspace
+Tests/encodings/codecs_test.py
+Tests/feaLib/__init__.py
+Tests/feaLib/ast_test.py
+Tests/feaLib/builder_test.py
+Tests/feaLib/error_test.py
+Tests/feaLib/lexer_test.py
+Tests/feaLib/parser_test.py
+Tests/feaLib/data/AlternateSubtable.fea
+Tests/feaLib/data/AlternateSubtable.ttx
+Tests/feaLib/data/Attach.fea
+Tests/feaLib/data/Attach.ttx
+Tests/feaLib/data/ChainPosSubtable.fea
+Tests/feaLib/data/ChainPosSubtable.ttx
+Tests/feaLib/data/ChainSubstSubtable.fea
+Tests/feaLib/data/ChainSubstSubtable.ttx
+Tests/feaLib/data/GPOS_1.fea
+Tests/feaLib/data/GPOS_1.ttx
+Tests/feaLib/data/GPOS_1_zero.fea
+Tests/feaLib/data/GPOS_1_zero.ttx
+Tests/feaLib/data/GPOS_2.fea
+Tests/feaLib/data/GPOS_2.ttx
+Tests/feaLib/data/GPOS_2b.fea
+Tests/feaLib/data/GPOS_2b.ttx
+Tests/feaLib/data/GPOS_3.fea
+Tests/feaLib/data/GPOS_3.ttx
+Tests/feaLib/data/GPOS_4.fea
+Tests/feaLib/data/GPOS_4.ttx
+Tests/feaLib/data/GPOS_5.fea
+Tests/feaLib/data/GPOS_5.ttx
+Tests/feaLib/data/GPOS_6.fea
+Tests/feaLib/data/GPOS_6.ttx
+Tests/feaLib/data/GPOS_8.fea
+Tests/feaLib/data/GPOS_8.ttx
+Tests/feaLib/data/GSUB_2.fea
+Tests/feaLib/data/GSUB_2.ttx
+Tests/feaLib/data/GSUB_3.fea
+Tests/feaLib/data/GSUB_3.ttx
+Tests/feaLib/data/GSUB_6.fea
+Tests/feaLib/data/GSUB_6.ttx
+Tests/feaLib/data/GSUB_8.fea
+Tests/feaLib/data/GSUB_8.ttx
+Tests/feaLib/data/GlyphClassDef.fea
+Tests/feaLib/data/GlyphClassDef.ttx
+Tests/feaLib/data/LigatureCaretByIndex.fea
+Tests/feaLib/data/LigatureCaretByIndex.ttx
+Tests/feaLib/data/LigatureCaretByPos.fea
+Tests/feaLib/data/LigatureCaretByPos.ttx
+Tests/feaLib/data/LigatureSubtable.fea
+Tests/feaLib/data/LigatureSubtable.ttx
+Tests/feaLib/data/MultipleSubstSubtable.fea
+Tests/feaLib/data/MultipleSubstSubtable.ttx
+Tests/feaLib/data/PairPosSubtable.fea
+Tests/feaLib/data/PairPosSubtable.ttx
+Tests/feaLib/data/SingleSubstSubtable.fea
+Tests/feaLib/data/SingleSubstSubtable.ttx
+Tests/feaLib/data/ZeroValue_ChainSinglePos_horizontal.fea
+Tests/feaLib/data/ZeroValue_ChainSinglePos_horizontal.ttx
+Tests/feaLib/data/ZeroValue_ChainSinglePos_vertical.fea
+Tests/feaLib/data/ZeroValue_ChainSinglePos_vertical.ttx
+Tests/feaLib/data/ZeroValue_PairPos_horizontal.fea
+Tests/feaLib/data/ZeroValue_PairPos_horizontal.ttx
+Tests/feaLib/data/ZeroValue_PairPos_vertical.fea
+Tests/feaLib/data/ZeroValue_PairPos_vertical.ttx
+Tests/feaLib/data/ZeroValue_SinglePos_horizontal.fea
+Tests/feaLib/data/ZeroValue_SinglePos_horizontal.ttx
+Tests/feaLib/data/ZeroValue_SinglePos_vertical.fea
+Tests/feaLib/data/ZeroValue_SinglePos_vertical.ttx
+Tests/feaLib/data/baseClass.fea
+Tests/feaLib/data/baseClass.feax
+Tests/feaLib/data/bug1307.fea
+Tests/feaLib/data/bug1307.ttx
+Tests/feaLib/data/bug1459.fea
+Tests/feaLib/data/bug1459.ttx
+Tests/feaLib/data/bug453.fea
+Tests/feaLib/data/bug453.ttx
+Tests/feaLib/data/bug457.fea
+Tests/feaLib/data/bug457.ttx
+Tests/feaLib/data/bug463.fea
+Tests/feaLib/data/bug463.ttx
+Tests/feaLib/data/bug501.fea
+Tests/feaLib/data/bug501.ttx
+Tests/feaLib/data/bug502.fea
+Tests/feaLib/data/bug502.ttx
+Tests/feaLib/data/bug504.fea
+Tests/feaLib/data/bug504.ttx
+Tests/feaLib/data/bug505.fea
+Tests/feaLib/data/bug505.ttx
+Tests/feaLib/data/bug506.fea
+Tests/feaLib/data/bug506.ttx
+Tests/feaLib/data/bug509.fea
+Tests/feaLib/data/bug509.ttx
+Tests/feaLib/data/bug512.fea
+Tests/feaLib/data/bug512.ttx
+Tests/feaLib/data/bug514.fea
+Tests/feaLib/data/bug514.ttx
+Tests/feaLib/data/bug568.fea
+Tests/feaLib/data/bug568.ttx
+Tests/feaLib/data/bug633.fea
+Tests/feaLib/data/bug633.ttx
+Tests/feaLib/data/enum.fea
+Tests/feaLib/data/enum.ttx
+Tests/feaLib/data/feature_aalt.fea
+Tests/feaLib/data/feature_aalt.ttx
+Tests/feaLib/data/ignore_pos.fea
+Tests/feaLib/data/ignore_pos.ttx
+Tests/feaLib/data/include0.fea
+Tests/feaLib/data/language_required.fea
+Tests/feaLib/data/language_required.ttx
+Tests/feaLib/data/lookup.fea
+Tests/feaLib/data/lookup.ttx
+Tests/feaLib/data/lookupflag.fea
+Tests/feaLib/data/lookupflag.ttx
+Tests/feaLib/data/markClass.fea
+Tests/feaLib/data/markClass.ttx
+Tests/feaLib/data/mini.fea
+Tests/feaLib/data/multiple_feature_blocks.fea
+Tests/feaLib/data/multiple_feature_blocks.ttx
+Tests/feaLib/data/name.fea
+Tests/feaLib/data/name.ttx
+Tests/feaLib/data/omitted_GlyphClassDef.fea
+Tests/feaLib/data/omitted_GlyphClassDef.ttx
+Tests/feaLib/data/size.fea
+Tests/feaLib/data/size.ttx
+Tests/feaLib/data/size2.fea
+Tests/feaLib/data/size2.ttx
+Tests/feaLib/data/spec10.fea
+Tests/feaLib/data/spec10.ttx
+Tests/feaLib/data/spec4h1.fea
+Tests/feaLib/data/spec4h1.ttx
+Tests/feaLib/data/spec4h2.fea
+Tests/feaLib/data/spec4h2.ttx
+Tests/feaLib/data/spec5d1.fea
+Tests/feaLib/data/spec5d1.ttx
+Tests/feaLib/data/spec5d2.fea
+Tests/feaLib/data/spec5d2.ttx
+Tests/feaLib/data/spec5f_ii_1.fea
+Tests/feaLib/data/spec5f_ii_1.ttx
+Tests/feaLib/data/spec5f_ii_2.fea
+Tests/feaLib/data/spec5f_ii_2.ttx
+Tests/feaLib/data/spec5f_ii_3.fea
+Tests/feaLib/data/spec5f_ii_3.ttx
+Tests/feaLib/data/spec5f_ii_4.fea
+Tests/feaLib/data/spec5f_ii_4.ttx
+Tests/feaLib/data/spec5fi1.fea
+Tests/feaLib/data/spec5fi1.ttx
+Tests/feaLib/data/spec5fi2.fea
+Tests/feaLib/data/spec5fi2.ttx
+Tests/feaLib/data/spec5fi3.fea
+Tests/feaLib/data/spec5fi3.ttx
+Tests/feaLib/data/spec5fi4.fea
+Tests/feaLib/data/spec5fi4.ttx
+Tests/feaLib/data/spec5h1.fea
+Tests/feaLib/data/spec5h1.ttx
+Tests/feaLib/data/spec6b_ii.fea
+Tests/feaLib/data/spec6b_ii.ttx
+Tests/feaLib/data/spec6d2.fea
+Tests/feaLib/data/spec6d2.ttx
+Tests/feaLib/data/spec6e.fea
+Tests/feaLib/data/spec6e.ttx
+Tests/feaLib/data/spec6f.fea
+Tests/feaLib/data/spec6f.ttx
+Tests/feaLib/data/spec6h_ii.fea
+Tests/feaLib/data/spec6h_ii.ttx
+Tests/feaLib/data/spec6h_iii_1.fea
+Tests/feaLib/data/spec6h_iii_1.ttx
+Tests/feaLib/data/spec6h_iii_3d.fea
+Tests/feaLib/data/spec6h_iii_3d.ttx
+Tests/feaLib/data/spec8a.fea
+Tests/feaLib/data/spec8a.ttx
+Tests/feaLib/data/spec8b.fea
+Tests/feaLib/data/spec8b.ttx
+Tests/feaLib/data/spec8c.fea
+Tests/feaLib/data/spec8c.ttx
+Tests/feaLib/data/spec8d.fea
+Tests/feaLib/data/spec8d.ttx
+Tests/feaLib/data/spec9a.fea
+Tests/feaLib/data/spec9a.ttx
+Tests/feaLib/data/spec9b.fea
+Tests/feaLib/data/spec9b.ttx
+Tests/feaLib/data/spec9c1.fea
+Tests/feaLib/data/spec9c1.ttx
+Tests/feaLib/data/spec9c2.fea
+Tests/feaLib/data/spec9c2.ttx
+Tests/feaLib/data/spec9c3.fea
+Tests/feaLib/data/spec9c3.ttx
+Tests/feaLib/data/spec9d.fea
+Tests/feaLib/data/spec9d.ttx
+Tests/feaLib/data/spec9e.fea
+Tests/feaLib/data/spec9e.ttx
+Tests/feaLib/data/spec9f.fea
+Tests/feaLib/data/spec9f.ttx
+Tests/feaLib/data/spec9g.fea
+Tests/feaLib/data/spec9g.ttx
+Tests/feaLib/data/include/include1.fea
+Tests/feaLib/data/include/include3.fea
+Tests/feaLib/data/include/include4.fea
+Tests/feaLib/data/include/include5.fea
+Tests/feaLib/data/include/include6.fea
+Tests/feaLib/data/include/includemissingfile.fea
+Tests/feaLib/data/include/includeself.fea
+Tests/feaLib/data/include/subdir/include2.fea
+Tests/fontBuilder/fontBuilder_test.py
+Tests/fontBuilder/data/test.otf.ttx
+Tests/fontBuilder/data/test.ttf.ttx
+Tests/fontBuilder/data/test_uvs.ttf.ttx
+Tests/fontBuilder/data/test_var.otf.ttx
+Tests/fontBuilder/data/test_var.ttf.ttx
+Tests/misc/arrayTools_test.py
+Tests/misc/bezierTools_test.py
+Tests/misc/classifyTools_test.py
+Tests/misc/eexec_test.py
+Tests/misc/encodingTools_test.py
+Tests/misc/etree_test.py
+Tests/misc/filenames_test.py
+Tests/misc/fixedTools_test.py
+Tests/misc/loggingTools_test.py
+Tests/misc/macRes_test.py
+Tests/misc/plistlib_test.py
+Tests/misc/psCharStrings_test.py
+Tests/misc/py23_test.py
+Tests/misc/testTools_test.py
+Tests/misc/textTools_test.py
+Tests/misc/timeTools_test.py
+Tests/misc/transform_test.py
+Tests/misc/xmlReader_test.py
+Tests/misc/xmlWriter_test.py
+Tests/misc/testdata/test.plist
+Tests/mtiLib/mti_test.py
+Tests/mtiLib/data/featurename-backward.ttx.GSUB
+Tests/mtiLib/data/featurename-backward.txt
+Tests/mtiLib/data/featurename-forward.ttx.GSUB
+Tests/mtiLib/data/featurename-forward.txt
+Tests/mtiLib/data/lookupnames-backward.ttx.GSUB
+Tests/mtiLib/data/lookupnames-backward.txt
+Tests/mtiLib/data/lookupnames-forward.ttx.GSUB
+Tests/mtiLib/data/lookupnames-forward.txt
+Tests/mtiLib/data/mixed-toplevels.ttx.GSUB
+Tests/mtiLib/data/mixed-toplevels.txt
+Tests/mtiLib/data/mti/README
+Tests/mtiLib/data/mti/chained-glyph.ttx.GPOS
+Tests/mtiLib/data/mti/chained-glyph.ttx.GSUB
+Tests/mtiLib/data/mti/chained-glyph.txt
+Tests/mtiLib/data/mti/chainedclass.ttx.GSUB
+Tests/mtiLib/data/mti/chainedclass.txt
+Tests/mtiLib/data/mti/chainedcoverage.ttx.GSUB
+Tests/mtiLib/data/mti/chainedcoverage.txt
+Tests/mtiLib/data/mti/cmap.ttx
+Tests/mtiLib/data/mti/cmap.ttx.cmap
+Tests/mtiLib/data/mti/cmap.txt
+Tests/mtiLib/data/mti/context-glyph.txt
+Tests/mtiLib/data/mti/contextclass.txt
+Tests/mtiLib/data/mti/contextcoverage.txt
+Tests/mtiLib/data/mti/featuretable.txt
+Tests/mtiLib/data/mti/gdefattach.ttx.GDEF
+Tests/mtiLib/data/mti/gdefattach.txt
+Tests/mtiLib/data/mti/gdefclasses.ttx.GDEF
+Tests/mtiLib/data/mti/gdefclasses.txt
+Tests/mtiLib/data/mti/gdefligcaret.ttx.GDEF
+Tests/mtiLib/data/mti/gdefligcaret.txt
+Tests/mtiLib/data/mti/gdefmarkattach.ttx.GDEF
+Tests/mtiLib/data/mti/gdefmarkattach.txt
+Tests/mtiLib/data/mti/gdefmarkfilter.ttx.GDEF
+Tests/mtiLib/data/mti/gdefmarkfilter.txt
+Tests/mtiLib/data/mti/gposcursive.ttx.GPOS
+Tests/mtiLib/data/mti/gposcursive.txt
+Tests/mtiLib/data/mti/gposkernset.ttx.GPOS
+Tests/mtiLib/data/mti/gposkernset.txt
+Tests/mtiLib/data/mti/gposmarktobase.ttx.GPOS
+Tests/mtiLib/data/mti/gposmarktobase.txt
+Tests/mtiLib/data/mti/gpospairclass.ttx.GPOS
+Tests/mtiLib/data/mti/gpospairclass.txt
+Tests/mtiLib/data/mti/gpospairglyph.ttx.GPOS
+Tests/mtiLib/data/mti/gpospairglyph.txt
+Tests/mtiLib/data/mti/gpossingle.ttx.GPOS
+Tests/mtiLib/data/mti/gpossingle.txt
+Tests/mtiLib/data/mti/gsubalternate.ttx.GSUB
+Tests/mtiLib/data/mti/gsubalternate.txt
+Tests/mtiLib/data/mti/gsubligature.ttx.GSUB
+Tests/mtiLib/data/mti/gsubligature.txt
+Tests/mtiLib/data/mti/gsubmultiple.ttx.GSUB
+Tests/mtiLib/data/mti/gsubmultiple.txt
+Tests/mtiLib/data/mti/gsubreversechanined.ttx.GSUB
+Tests/mtiLib/data/mti/gsubreversechanined.txt
+Tests/mtiLib/data/mti/gsubsingle.ttx.GSUB
+Tests/mtiLib/data/mti/gsubsingle.txt
+Tests/mtiLib/data/mti/mark-to-ligature.ttx.GPOS
+Tests/mtiLib/data/mti/mark-to-ligature.txt
+Tests/mtiLib/data/mti/scripttable.ttx.GPOS
+Tests/mtiLib/data/mti/scripttable.ttx.GSUB
+Tests/mtiLib/data/mti/scripttable.txt
+Tests/otlLib/builder_test.py
+Tests/otlLib/maxContextCalc_test.py
+Tests/otlLib/data/gpos_91.ttx
+Tests/otlLib/data/gsub_51.ttx
+Tests/otlLib/data/gsub_52.ttx
+Tests/otlLib/data/gsub_71.ttx
+Tests/pens/areaPen_test.py
+Tests/pens/basePen_test.py
+Tests/pens/boundsPen_test.py
+Tests/pens/perimeterPen_test.py
+Tests/pens/pointInsidePen_test.py
+Tests/pens/pointPen_test.py
+Tests/pens/recordingPen_test.py
+Tests/pens/reverseContourPen_test.py
+Tests/pens/t2CharStringPen_test.py
+Tests/pens/ttGlyphPen_test.py
+Tests/subset/subset_test.py
+Tests/subset/data/Lobster.subset.otf
+Tests/subset/data/Lobster.subset.ttx
+Tests/subset/data/NotdefWidthCID-Regular.ttx
+Tests/subset/data/TestANKR.ttx
+Tests/subset/data/TestBSLN-0.ttx
+Tests/subset/data/TestBSLN-1.ttx
+Tests/subset/data/TestBSLN-2.ttx
+Tests/subset/data/TestBSLN-3.ttx
+Tests/subset/data/TestCID-Regular.ttx
+Tests/subset/data/TestCLR-Regular.ttx
+Tests/subset/data/TestGVAR.ttx
+Tests/subset/data/TestHVVAR.ttx
+Tests/subset/data/TestLCAR-0.ttx
+Tests/subset/data/TestLCAR-1.ttx
+Tests/subset/data/TestMATH-Regular.ttx
+Tests/subset/data/TestOPBD-0.ttx
+Tests/subset/data/TestOPBD-1.ttx
+Tests/subset/data/TestOTF-Regular.ttx
+Tests/subset/data/TestPROP.ttx
+Tests/subset/data/TestTTF-Regular.ttx
+Tests/subset/data/TestTTF-Regular_non_BMP_char.ttx
+Tests/subset/data/expect_HVVAR.ttx
+Tests/subset/data/expect_HVVAR_retain_gids.ttx
+Tests/subset/data/expect_ankr.ttx
+Tests/subset/data/expect_bsln_0.ttx
+Tests/subset/data/expect_bsln_1.ttx
+Tests/subset/data/expect_bsln_2.ttx
+Tests/subset/data/expect_bsln_3.ttx
+Tests/subset/data/expect_desubroutinize_CFF.ttx
+Tests/subset/data/expect_keep_colr.ttx
+Tests/subset/data/expect_keep_gvar.ttx
+Tests/subset/data/expect_keep_gvar_notdef_outline.ttx
+Tests/subset/data/expect_keep_math.ttx
+Tests/subset/data/expect_lcar_0.ttx
+Tests/subset/data/expect_lcar_1.ttx
+Tests/subset/data/expect_math_partial.ttx
+Tests/subset/data/expect_no_hinting_CFF.ttx
+Tests/subset/data/expect_no_hinting_TTF.ttx
+Tests/subset/data/expect_no_hinting_desubroutinize_CFF.ttx
+Tests/subset/data/expect_no_notdef_outline_cid.ttx
+Tests/subset/data/expect_no_notdef_outline_otf.ttx
+Tests/subset/data/expect_no_notdef_outline_ttf.ttx
+Tests/subset/data/expect_notdef_width_cid.ttx
+Tests/subset/data/expect_opbd_0.ttx
+Tests/subset/data/expect_opbd_1.ttx
+Tests/subset/data/expect_prop_0.ttx
+Tests/subset/data/expect_prop_1.ttx
+Tests/subset/data/expect_sbix.ttx
+Tests/subset/data/google_color.ttx
+Tests/subset/data/sbix.ttx
+Tests/subset/data/test_cntrmask_CFF.desub.ttx
+Tests/subset/data/test_cntrmask_CFF.ttx
+Tests/subset/data/test_hinted_subrs_CFF.desub.ttx
+Tests/subset/data/test_hinted_subrs_CFF.ttx
+Tests/subset/data/test_math_partial.ttx
+Tests/svgLib/path/__init__.py
+Tests/svgLib/path/parser_test.py
+Tests/svgLib/path/path_test.py
+Tests/svgLib/path/shapes_test.py
+Tests/t1Lib/t1Lib_test.py
+Tests/t1Lib/data/TestT1-Regular.lwfn
+Tests/t1Lib/data/TestT1-Regular.pfa
+Tests/t1Lib/data/TestT1-Regular.pfb
+Tests/t1Lib/data/TestT1-weird-zeros.pfa
+Tests/ttLib/sfnt_test.py
+Tests/ttLib/woff2_test.py
+Tests/ttLib/data/TestOTF-Regular.otx
+Tests/ttLib/data/TestTTF-Regular.ttx
+Tests/ttLib/data/TestTTFComplex-Regular.ttx
+Tests/ttLib/data/test_woff2_metadata.xml
+Tests/ttLib/tables/C_F_F__2_test.py
+Tests/ttLib/tables/C_F_F_test.py
+Tests/ttLib/tables/C_P_A_L_test.py
+Tests/ttLib/tables/M_V_A_R_test.py
+Tests/ttLib/tables/O_S_2f_2_test.py
+Tests/ttLib/tables/S_T_A_T_test.py
+Tests/ttLib/tables/T_S_I__0_test.py
+Tests/ttLib/tables/T_S_I__1_test.py
+Tests/ttLib/tables/TupleVariation_test.py
+Tests/ttLib/tables/_a_n_k_r_test.py
+Tests/ttLib/tables/_a_v_a_r_test.py
+Tests/ttLib/tables/_b_s_l_n_test.py
+Tests/ttLib/tables/_c_i_d_g_test.py
+Tests/ttLib/tables/_c_m_a_p_test.py
+Tests/ttLib/tables/_c_v_a_r_test.py
+Tests/ttLib/tables/_f_p_g_m_test.py
+Tests/ttLib/tables/_f_v_a_r_test.py
+Tests/ttLib/tables/_g_c_i_d_test.py
+Tests/ttLib/tables/_g_l_y_f_test.py
+Tests/ttLib/tables/_g_v_a_r_test.py
+Tests/ttLib/tables/_h_h_e_a_test.py
+Tests/ttLib/tables/_h_m_t_x_test.py
+Tests/ttLib/tables/_k_e_r_n_test.py
+Tests/ttLib/tables/_l_c_a_r_test.py
+Tests/ttLib/tables/_l_t_a_g_test.py
+Tests/ttLib/tables/_m_e_t_a_test.py
+Tests/ttLib/tables/_m_o_r_t_test.py
+Tests/ttLib/tables/_m_o_r_x_test.py
+Tests/ttLib/tables/_n_a_m_e_test.py
+Tests/ttLib/tables/_o_p_b_d_test.py
+Tests/ttLib/tables/_p_r_o_p_test.py
+Tests/ttLib/tables/_t_r_a_k_test.py
+Tests/ttLib/tables/_v_h_e_a_test.py
+Tests/ttLib/tables/_v_m_t_x_test.py
+Tests/ttLib/tables/otBase_test.py
+Tests/ttLib/tables/otConverters_test.py
+Tests/ttLib/tables/otTables_test.py
+Tests/ttLib/tables/tables_test.py
+Tests/ttLib/tables/ttProgram_test.py
+Tests/ttLib/tables/data/C_F_F_.bin
+Tests/ttLib/tables/data/C_F_F_.ttx
+Tests/ttLib/tables/data/C_F_F__2.bin
+Tests/ttLib/tables/data/C_F_F__2.ttx
+Tests/ttLib/tables/data/_c_m_a_p_format_14.ttx
+Tests/ttLib/tables/data/_c_m_a_p_format_14_bw_compat.ttx
+Tests/ttLib/tables/data/_g_l_y_f_outline_flag_bit6.glyf.bin
+Tests/ttLib/tables/data/_g_l_y_f_outline_flag_bit6.head.bin
+Tests/ttLib/tables/data/_g_l_y_f_outline_flag_bit6.loca.bin
+Tests/ttLib/tables/data/_g_l_y_f_outline_flag_bit6.maxp.bin
+Tests/ttLib/tables/data/_g_l_y_f_outline_flag_bit6.ttx
+Tests/ttLib/tables/data/_h_h_e_a_recalc_OTF.ttx
+Tests/ttLib/tables/data/_h_h_e_a_recalc_TTF.ttx
+Tests/ttLib/tables/data/_h_h_e_a_recalc_empty.ttx
+Tests/ttLib/tables/data/_v_h_e_a_recalc_OTF.ttx
+Tests/ttLib/tables/data/_v_h_e_a_recalc_TTF.ttx
+Tests/ttLib/tables/data/_v_h_e_a_recalc_empty.ttx
+Tests/ttLib/tables/data/ttProgram.ttx
+Tests/ttLib/tables/data/aots/README
+Tests/ttLib/tables/data/aots/base.otf
+Tests/ttLib/tables/data/aots/base.ttx.CFF
+Tests/ttLib/tables/data/aots/base.ttx.OS_2
+Tests/ttLib/tables/data/aots/base.ttx.cmap
+Tests/ttLib/tables/data/aots/base.ttx.head
+Tests/ttLib/tables/data/aots/base.ttx.hhea
+Tests/ttLib/tables/data/aots/base.ttx.hmtx
+Tests/ttLib/tables/data/aots/base.ttx.maxp
+Tests/ttLib/tables/data/aots/base.ttx.name
+Tests/ttLib/tables/data/aots/base.ttx.post
+Tests/ttLib/tables/data/aots/classdef1_font1.otf
+Tests/ttLib/tables/data/aots/classdef1_font1.ttx.GSUB
+Tests/ttLib/tables/data/aots/classdef1_font2.otf
+Tests/ttLib/tables/data/aots/classdef1_font2.ttx.GSUB
+Tests/ttLib/tables/data/aots/classdef1_font3.otf
+Tests/ttLib/tables/data/aots/classdef1_font3.ttx.GSUB
+Tests/ttLib/tables/data/aots/classdef1_font4.otf
+Tests/ttLib/tables/data/aots/classdef1_font4.ttx.GSUB
+Tests/ttLib/tables/data/aots/classdef2_font1.otf
+Tests/ttLib/tables/data/aots/classdef2_font1.ttx.GSUB
+Tests/ttLib/tables/data/aots/classdef2_font2.otf
+Tests/ttLib/tables/data/aots/classdef2_font2.ttx.GSUB
+Tests/ttLib/tables/data/aots/classdef2_font3.otf
+Tests/ttLib/tables/data/aots/classdef2_font3.ttx.GSUB
+Tests/ttLib/tables/data/aots/classdef2_font4.otf
+Tests/ttLib/tables/data/aots/classdef2_font4.ttx.GSUB
+Tests/ttLib/tables/data/aots/cmap0_font1.otf
+Tests/ttLib/tables/data/aots/cmap0_font1.ttx.cmap
+Tests/ttLib/tables/data/aots/cmap10_font1.otf
+Tests/ttLib/tables/data/aots/cmap10_font1.ttx.cmap
+Tests/ttLib/tables/data/aots/cmap10_font2.otf
+Tests/ttLib/tables/data/aots/cmap10_font2.ttx.cmap
+Tests/ttLib/tables/data/aots/cmap12_font1.otf
+Tests/ttLib/tables/data/aots/cmap12_font1.ttx.cmap
+Tests/ttLib/tables/data/aots/cmap14_font1.otf
+Tests/ttLib/tables/data/aots/cmap14_font1.ttx.cmap
+Tests/ttLib/tables/data/aots/cmap2_font1.otf
+Tests/ttLib/tables/data/aots/cmap2_font1.ttx.cmap
+Tests/ttLib/tables/data/aots/cmap4_font1.otf
+Tests/ttLib/tables/data/aots/cmap4_font1.ttx.cmap
+Tests/ttLib/tables/data/aots/cmap4_font2.otf
+Tests/ttLib/tables/data/aots/cmap4_font2.ttx.cmap
+Tests/ttLib/tables/data/aots/cmap4_font3.otf
+Tests/ttLib/tables/data/aots/cmap4_font3.ttx.cmap
+Tests/ttLib/tables/data/aots/cmap4_font4.otf
+Tests/ttLib/tables/data/aots/cmap4_font4.ttx.cmap
+Tests/ttLib/tables/data/aots/cmap6_font1.otf
+Tests/ttLib/tables/data/aots/cmap6_font1.ttx.cmap
+Tests/ttLib/tables/data/aots/cmap6_font2.otf
+Tests/ttLib/tables/data/aots/cmap6_font2.ttx.cmap
+Tests/ttLib/tables/data/aots/cmap8_font1.otf
+Tests/ttLib/tables/data/aots/cmap8_font1.ttx.cmap
+Tests/ttLib/tables/data/aots/cmap_composition_font1.otf
+Tests/ttLib/tables/data/aots/cmap_composition_font1.ttx.cmap
+Tests/ttLib/tables/data/aots/cmap_subtableselection_font1.otf
+Tests/ttLib/tables/data/aots/cmap_subtableselection_font1.ttx.cmap
+Tests/ttLib/tables/data/aots/cmap_subtableselection_font2.otf
+Tests/ttLib/tables/data/aots/cmap_subtableselection_font2.ttx.cmap
+Tests/ttLib/tables/data/aots/cmap_subtableselection_font3.otf
+Tests/ttLib/tables/data/aots/cmap_subtableselection_font3.ttx.cmap
+Tests/ttLib/tables/data/aots/cmap_subtableselection_font4.otf
+Tests/ttLib/tables/data/aots/cmap_subtableselection_font4.ttx.cmap
+Tests/ttLib/tables/data/aots/cmap_subtableselection_font5.otf
+Tests/ttLib/tables/data/aots/cmap_subtableselection_font5.ttx.cmap
+Tests/ttLib/tables/data/aots/gpos1_1_lookupflag_f1.otf
+Tests/ttLib/tables/data/aots/gpos1_1_lookupflag_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos1_1_lookupflag_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos1_1_simple_f1.otf
+Tests/ttLib/tables/data/aots/gpos1_1_simple_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos1_1_simple_f2.otf
+Tests/ttLib/tables/data/aots/gpos1_1_simple_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos1_1_simple_f3.otf
+Tests/ttLib/tables/data/aots/gpos1_1_simple_f3.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos1_1_simple_f4.otf
+Tests/ttLib/tables/data/aots/gpos1_1_simple_f4.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos1_2_font1.otf
+Tests/ttLib/tables/data/aots/gpos1_2_font1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos1_2_font2.otf
+Tests/ttLib/tables/data/aots/gpos1_2_font2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos1_2_font2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos2_1_font6.otf
+Tests/ttLib/tables/data/aots/gpos2_1_font6.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos2_1_font7.otf
+Tests/ttLib/tables/data/aots/gpos2_1_font7.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f1.otf
+Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f2.otf
+Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos2_1_next_glyph_f1.otf
+Tests/ttLib/tables/data/aots/gpos2_1_next_glyph_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos2_1_next_glyph_f2.otf
+Tests/ttLib/tables/data/aots/gpos2_1_next_glyph_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos2_1_simple_f1.otf
+Tests/ttLib/tables/data/aots/gpos2_1_simple_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos2_2_font1.otf
+Tests/ttLib/tables/data/aots/gpos2_2_font1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos2_2_font2.otf
+Tests/ttLib/tables/data/aots/gpos2_2_font2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos2_2_font2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos2_2_font3.otf
+Tests/ttLib/tables/data/aots/gpos2_2_font3.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos2_2_font3.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos2_2_font4.otf
+Tests/ttLib/tables/data/aots/gpos2_2_font4.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos2_2_font5.otf
+Tests/ttLib/tables/data/aots/gpos2_2_font5.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos3_font1.otf
+Tests/ttLib/tables/data/aots/gpos3_font1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos3_font2.otf
+Tests/ttLib/tables/data/aots/gpos3_font2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos3_font2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos3_font3.otf
+Tests/ttLib/tables/data/aots/gpos3_font3.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos3_font3.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos4_lookupflag_f1.otf
+Tests/ttLib/tables/data/aots/gpos4_lookupflag_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos4_lookupflag_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos4_lookupflag_f2.otf
+Tests/ttLib/tables/data/aots/gpos4_lookupflag_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos4_lookupflag_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos4_multiple_anchors_1.otf
+Tests/ttLib/tables/data/aots/gpos4_multiple_anchors_1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos4_multiple_anchors_1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos4_simple_1.otf
+Tests/ttLib/tables/data/aots/gpos4_simple_1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos4_simple_1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos5_font1.otf
+Tests/ttLib/tables/data/aots/gpos5_font1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos5_font1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos5_font1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gpos6_font1.otf
+Tests/ttLib/tables/data/aots/gpos6_font1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos6_font1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos7_1_font1.otf
+Tests/ttLib/tables/data/aots/gpos7_1_font1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos9_font1.otf
+Tests/ttLib/tables/data/aots/gpos9_font1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos9_font2.otf
+Tests/ttLib/tables/data/aots/gpos9_font2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f1.otf
+Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f2.otf
+Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f3.otf
+Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f3.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f3.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f4.otf
+Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f4.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f4.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining1_lookupflag_f1.otf
+Tests/ttLib/tables/data/aots/gpos_chaining1_lookupflag_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining1_lookupflag_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f1.otf
+Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f2.otf
+Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining1_next_glyph_f1.otf
+Tests/ttLib/tables/data/aots/gpos_chaining1_next_glyph_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining1_next_glyph_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f1.otf
+Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f2.otf
+Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining1_successive_f1.otf
+Tests/ttLib/tables/data/aots/gpos_chaining1_successive_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining1_successive_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f1.otf
+Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f2.otf
+Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f3.otf
+Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f3.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f3.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f4.otf
+Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f4.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f4.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining2_lookupflag_f1.otf
+Tests/ttLib/tables/data/aots/gpos_chaining2_lookupflag_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining2_lookupflag_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f1.otf
+Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f2.otf
+Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining2_next_glyph_f1.otf
+Tests/ttLib/tables/data/aots/gpos_chaining2_next_glyph_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining2_next_glyph_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f1.otf
+Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f2.otf
+Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining2_successive_f1.otf
+Tests/ttLib/tables/data/aots/gpos_chaining2_successive_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining2_successive_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f1.otf
+Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f2.otf
+Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f3.otf
+Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f3.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f3.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f4.otf
+Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f4.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f4.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining3_lookupflag_f1.otf
+Tests/ttLib/tables/data/aots/gpos_chaining3_lookupflag_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining3_lookupflag_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining3_next_glyph_f1.otf
+Tests/ttLib/tables/data/aots/gpos_chaining3_next_glyph_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining3_next_glyph_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f1.otf
+Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f2.otf
+Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_chaining3_successive_f1.otf
+Tests/ttLib/tables/data/aots/gpos_chaining3_successive_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_chaining3_successive_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context1_boundary_f1.otf
+Tests/ttLib/tables/data/aots/gpos_context1_boundary_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context1_boundary_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context1_boundary_f2.otf
+Tests/ttLib/tables/data/aots/gpos_context1_boundary_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context1_boundary_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context1_expansion_f1.otf
+Tests/ttLib/tables/data/aots/gpos_context1_expansion_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context1_expansion_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f1.otf
+Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f2.otf
+Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f1.otf
+Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f2.otf
+Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context1_next_glyph_f1.otf
+Tests/ttLib/tables/data/aots/gpos_context1_next_glyph_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context1_next_glyph_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context1_simple_f1.otf
+Tests/ttLib/tables/data/aots/gpos_context1_simple_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context1_simple_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context1_simple_f2.otf
+Tests/ttLib/tables/data/aots/gpos_context1_simple_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context1_simple_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context1_successive_f1.otf
+Tests/ttLib/tables/data/aots/gpos_context1_successive_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context1_successive_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context2_boundary_f1.otf
+Tests/ttLib/tables/data/aots/gpos_context2_boundary_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context2_boundary_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context2_boundary_f2.otf
+Tests/ttLib/tables/data/aots/gpos_context2_boundary_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context2_boundary_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context2_classes_f1.otf
+Tests/ttLib/tables/data/aots/gpos_context2_classes_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context2_classes_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context2_classes_f2.otf
+Tests/ttLib/tables/data/aots/gpos_context2_classes_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context2_classes_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context2_expansion_f1.otf
+Tests/ttLib/tables/data/aots/gpos_context2_expansion_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context2_expansion_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f1.otf
+Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f2.otf
+Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f1.otf
+Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f2.otf
+Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context2_next_glyph_f1.otf
+Tests/ttLib/tables/data/aots/gpos_context2_next_glyph_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context2_next_glyph_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context2_simple_f1.otf
+Tests/ttLib/tables/data/aots/gpos_context2_simple_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context2_simple_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context2_simple_f2.otf
+Tests/ttLib/tables/data/aots/gpos_context2_simple_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context2_simple_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context2_successive_f1.otf
+Tests/ttLib/tables/data/aots/gpos_context2_successive_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context2_successive_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context3_boundary_f1.otf
+Tests/ttLib/tables/data/aots/gpos_context3_boundary_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context3_boundary_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context3_boundary_f2.otf
+Tests/ttLib/tables/data/aots/gpos_context3_boundary_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context3_boundary_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f1.otf
+Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f2.otf
+Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f2.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context3_next_glyph_f1.otf
+Tests/ttLib/tables/data/aots/gpos_context3_next_glyph_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context3_next_glyph_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context3_simple_f1.otf
+Tests/ttLib/tables/data/aots/gpos_context3_simple_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context3_simple_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gpos_context3_successive_f1.otf
+Tests/ttLib/tables/data/aots/gpos_context3_successive_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gpos_context3_successive_f1.ttx.GPOS
+Tests/ttLib/tables/data/aots/gsub1_1_lookupflag_f1.otf
+Tests/ttLib/tables/data/aots/gsub1_1_lookupflag_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub1_1_lookupflag_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub1_1_modulo_f1.otf
+Tests/ttLib/tables/data/aots/gsub1_1_modulo_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub1_1_simple_f1.otf
+Tests/ttLib/tables/data/aots/gsub1_1_simple_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub1_2_lookupflag_f1.otf
+Tests/ttLib/tables/data/aots/gsub1_2_lookupflag_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub1_2_lookupflag_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub1_2_simple_f1.otf
+Tests/ttLib/tables/data/aots/gsub1_2_simple_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub2_1_lookupflag_f1.otf
+Tests/ttLib/tables/data/aots/gsub2_1_lookupflag_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub2_1_lookupflag_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub2_1_multiple_sequences_f1.otf
+Tests/ttLib/tables/data/aots/gsub2_1_multiple_sequences_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub2_1_simple_f1.otf
+Tests/ttLib/tables/data/aots/gsub2_1_simple_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub3_1_lookupflag_f1.otf
+Tests/ttLib/tables/data/aots/gsub3_1_lookupflag_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub3_1_lookupflag_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub3_1_multiple_f1.otf
+Tests/ttLib/tables/data/aots/gsub3_1_multiple_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub3_1_simple_f1.otf
+Tests/ttLib/tables/data/aots/gsub3_1_simple_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub4_1_lookupflag_f1.otf
+Tests/ttLib/tables/data/aots/gsub4_1_lookupflag_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub4_1_lookupflag_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub4_1_multiple_ligatures_f1.otf
+Tests/ttLib/tables/data/aots/gsub4_1_multiple_ligatures_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub4_1_multiple_ligatures_f2.otf
+Tests/ttLib/tables/data/aots/gsub4_1_multiple_ligatures_f2.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub4_1_multiple_ligsets_f1.otf
+Tests/ttLib/tables/data/aots/gsub4_1_multiple_ligsets_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub4_1_simple_f1.otf
+Tests/ttLib/tables/data/aots/gsub4_1_simple_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub7_font1.otf
+Tests/ttLib/tables/data/aots/gsub7_font1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub7_font2.otf
+Tests/ttLib/tables/data/aots/gsub7_font2.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f1.otf
+Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f2.otf
+Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f2.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f3.otf
+Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f3.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f3.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f4.otf
+Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f4.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f4.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining1_lookupflag_f1.otf
+Tests/ttLib/tables/data/aots/gsub_chaining1_lookupflag_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining1_lookupflag_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f1.otf
+Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f2.otf
+Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f2.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining1_next_glyph_f1.otf
+Tests/ttLib/tables/data/aots/gsub_chaining1_next_glyph_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining1_next_glyph_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f1.otf
+Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f2.otf
+Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f2.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining1_successive_f1.otf
+Tests/ttLib/tables/data/aots/gsub_chaining1_successive_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining1_successive_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f1.otf
+Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f2.otf
+Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f2.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f3.otf
+Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f3.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f3.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f4.otf
+Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f4.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f4.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining2_lookupflag_f1.otf
+Tests/ttLib/tables/data/aots/gsub_chaining2_lookupflag_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining2_lookupflag_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f1.otf
+Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f2.otf
+Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f2.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining2_next_glyph_f1.otf
+Tests/ttLib/tables/data/aots/gsub_chaining2_next_glyph_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining2_next_glyph_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f1.otf
+Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f2.otf
+Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f2.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining2_successive_f1.otf
+Tests/ttLib/tables/data/aots/gsub_chaining2_successive_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining2_successive_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f1.otf
+Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f2.otf
+Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f2.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f3.otf
+Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f3.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f3.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f4.otf
+Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f4.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f4.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining3_lookupflag_f1.otf
+Tests/ttLib/tables/data/aots/gsub_chaining3_lookupflag_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining3_lookupflag_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining3_next_glyph_f1.otf
+Tests/ttLib/tables/data/aots/gsub_chaining3_next_glyph_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining3_next_glyph_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f1.otf
+Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f2.otf
+Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f2.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_chaining3_successive_f1.otf
+Tests/ttLib/tables/data/aots/gsub_chaining3_successive_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_chaining3_successive_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context1_boundary_f1.otf
+Tests/ttLib/tables/data/aots/gsub_context1_boundary_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context1_boundary_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context1_boundary_f2.otf
+Tests/ttLib/tables/data/aots/gsub_context1_boundary_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context1_boundary_f2.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context1_expansion_f1.otf
+Tests/ttLib/tables/data/aots/gsub_context1_expansion_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context1_expansion_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f1.otf
+Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f2.otf
+Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f2.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f1.otf
+Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f2.otf
+Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f2.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context1_next_glyph_f1.otf
+Tests/ttLib/tables/data/aots/gsub_context1_next_glyph_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context1_next_glyph_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context1_simple_f1.otf
+Tests/ttLib/tables/data/aots/gsub_context1_simple_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context1_simple_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context1_simple_f2.otf
+Tests/ttLib/tables/data/aots/gsub_context1_simple_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context1_simple_f2.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context1_successive_f1.otf
+Tests/ttLib/tables/data/aots/gsub_context1_successive_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context1_successive_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context2_boundary_f1.otf
+Tests/ttLib/tables/data/aots/gsub_context2_boundary_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context2_boundary_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context2_boundary_f2.otf
+Tests/ttLib/tables/data/aots/gsub_context2_boundary_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context2_boundary_f2.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context2_classes_f1.otf
+Tests/ttLib/tables/data/aots/gsub_context2_classes_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context2_classes_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context2_classes_f2.otf
+Tests/ttLib/tables/data/aots/gsub_context2_classes_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context2_classes_f2.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context2_expansion_f1.otf
+Tests/ttLib/tables/data/aots/gsub_context2_expansion_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context2_expansion_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f1.otf
+Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f2.otf
+Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f2.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f1.otf
+Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f2.otf
+Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f2.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context2_next_glyph_f1.otf
+Tests/ttLib/tables/data/aots/gsub_context2_next_glyph_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context2_next_glyph_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context2_simple_f1.otf
+Tests/ttLib/tables/data/aots/gsub_context2_simple_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context2_simple_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context2_simple_f2.otf
+Tests/ttLib/tables/data/aots/gsub_context2_simple_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context2_simple_f2.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context2_successive_f1.otf
+Tests/ttLib/tables/data/aots/gsub_context2_successive_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context2_successive_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context3_boundary_f1.otf
+Tests/ttLib/tables/data/aots/gsub_context3_boundary_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context3_boundary_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context3_boundary_f2.otf
+Tests/ttLib/tables/data/aots/gsub_context3_boundary_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context3_boundary_f2.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f1.otf
+Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f2.otf
+Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f2.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f2.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context3_next_glyph_f1.otf
+Tests/ttLib/tables/data/aots/gsub_context3_next_glyph_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context3_next_glyph_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context3_simple_f1.otf
+Tests/ttLib/tables/data/aots/gsub_context3_simple_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context3_simple_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/gsub_context3_successive_f1.otf
+Tests/ttLib/tables/data/aots/gsub_context3_successive_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/gsub_context3_successive_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/lookupflag_ignore_attach_f1.otf
+Tests/ttLib/tables/data/aots/lookupflag_ignore_attach_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/lookupflag_ignore_attach_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/lookupflag_ignore_base_f1.otf
+Tests/ttLib/tables/data/aots/lookupflag_ignore_base_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/lookupflag_ignore_base_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/lookupflag_ignore_combination_f1.otf
+Tests/ttLib/tables/data/aots/lookupflag_ignore_combination_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/lookupflag_ignore_combination_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/lookupflag_ignore_ligatures_f1.otf
+Tests/ttLib/tables/data/aots/lookupflag_ignore_ligatures_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/lookupflag_ignore_ligatures_f1.ttx.GSUB
+Tests/ttLib/tables/data/aots/lookupflag_ignore_marks_f1.otf
+Tests/ttLib/tables/data/aots/lookupflag_ignore_marks_f1.ttx.GDEF
+Tests/ttLib/tables/data/aots/lookupflag_ignore_marks_f1.ttx.GSUB
+Tests/ttLib/tables/data/graphite/graphite_tests.ttf
+Tests/ttLib/tables/data/graphite/graphite_tests.ttx.Feat
+Tests/ttLib/tables/data/graphite/graphite_tests.ttx.Glat
+Tests/ttLib/tables/data/graphite/graphite_tests.ttx.Glat.setup
+Tests/ttLib/tables/data/graphite/graphite_tests.ttx.Silf
+Tests/ttLib/tables/data/graphite/graphite_tests.ttx.Silf.setup
+Tests/ttLib/tables/data/graphite/graphite_tests.ttx.Sill
+Tests/ttx/ttx_test.py
+Tests/ttx/data/TestBOM.ttx
+Tests/ttx/data/TestDFONT.dfont
+Tests/ttx/data/TestNoSFNT.ttx
+Tests/ttx/data/TestNoXML.ttx
+Tests/ttx/data/TestOTF.otf
+Tests/ttx/data/TestOTF.ttx
+Tests/ttx/data/TestTTC.ttc
+Tests/ttx/data/TestTTF.ttf
+Tests/ttx/data/TestTTF.ttx
+Tests/ttx/data/TestWOFF.woff
+Tests/ttx/data/TestWOFF2.woff2
+Tests/ufoLib/GLIF1_test.py
+Tests/ufoLib/GLIF2_test.py
+Tests/ufoLib/UFO1_test.py
+Tests/ufoLib/UFO2_test.py
+Tests/ufoLib/UFO3_test.py
+Tests/ufoLib/UFOConversion_test.py
+Tests/ufoLib/UFOZ_test.py
+Tests/ufoLib/__init__.py
+Tests/ufoLib/filenames_test.py
+Tests/ufoLib/glifLib_test.py
+Tests/ufoLib/testSupport.py
+Tests/ufoLib/testdata/DemoFont.ufo/fontinfo.plist
+Tests/ufoLib/testdata/DemoFont.ufo/lib.plist
+Tests/ufoLib/testdata/DemoFont.ufo/metainfo.plist
+Tests/ufoLib/testdata/DemoFont.ufo/glyphs/A_.glif
+Tests/ufoLib/testdata/DemoFont.ufo/glyphs/B_.glif
+Tests/ufoLib/testdata/DemoFont.ufo/glyphs/F_.glif
+Tests/ufoLib/testdata/DemoFont.ufo/glyphs/F__A__B_.glif
+Tests/ufoLib/testdata/DemoFont.ufo/glyphs/G_.glif
+Tests/ufoLib/testdata/DemoFont.ufo/glyphs/O_.glif
+Tests/ufoLib/testdata/DemoFont.ufo/glyphs/R_.glif
+Tests/ufoLib/testdata/DemoFont.ufo/glyphs/a.glif
+Tests/ufoLib/testdata/DemoFont.ufo/glyphs/contents.plist
+Tests/ufoLib/testdata/DemoFont.ufo/glyphs/testglyph1.glif
+Tests/ufoLib/testdata/DemoFont.ufo/glyphs/testglyph1.reversed.glif
+Tests/ufoLib/testdata/TestFont1 (UFO1).ufo/fontinfo.plist
+Tests/ufoLib/testdata/TestFont1 (UFO1).ufo/groups.plist
+Tests/ufoLib/testdata/TestFont1 (UFO1).ufo/kerning.plist
+Tests/ufoLib/testdata/TestFont1 (UFO1).ufo/lib.plist
+Tests/ufoLib/testdata/TestFont1 (UFO1).ufo/metainfo.plist
+Tests/ufoLib/testdata/TestFont1 (UFO1).ufo/glyphs/A_.glif
+Tests/ufoLib/testdata/TestFont1 (UFO1).ufo/glyphs/B_.glif
+Tests/ufoLib/testdata/TestFont1 (UFO1).ufo/glyphs/contents.plist
+Tests/ufoLib/testdata/TestFont1 (UFO2).ufo/features.fea
+Tests/ufoLib/testdata/TestFont1 (UFO2).ufo/fontinfo.plist
+Tests/ufoLib/testdata/TestFont1 (UFO2).ufo/groups.plist
+Tests/ufoLib/testdata/TestFont1 (UFO2).ufo/kerning.plist
+Tests/ufoLib/testdata/TestFont1 (UFO2).ufo/lib.plist
+Tests/ufoLib/testdata/TestFont1 (UFO2).ufo/metainfo.plist
+Tests/ufoLib/testdata/TestFont1 (UFO2).ufo/glyphs/A_.glif
+Tests/ufoLib/testdata/TestFont1 (UFO2).ufo/glyphs/B_.glif
+Tests/ufoLib/testdata/TestFont1 (UFO2).ufo/glyphs/contents.plist
+Tests/ufoLib/testdata/TestFont1 (UFO3).ufo/fontinfo.plist
+Tests/ufoLib/testdata/TestFont1 (UFO3).ufo/kerning.plist
+Tests/ufoLib/testdata/TestFont1 (UFO3).ufo/layercontents.plist
+Tests/ufoLib/testdata/TestFont1 (UFO3).ufo/lib.plist
+Tests/ufoLib/testdata/TestFont1 (UFO3).ufo/metainfo.plist
+Tests/ufoLib/testdata/TestFont1 (UFO3).ufo/data/com.github.fonttools.ttx/CUST.ttx
+Tests/ufoLib/testdata/TestFont1 (UFO3).ufo/glyphs/_notdef.glif
+Tests/ufoLib/testdata/TestFont1 (UFO3).ufo/glyphs/a.glif
+Tests/ufoLib/testdata/TestFont1 (UFO3).ufo/glyphs/b.glif
+Tests/ufoLib/testdata/TestFont1 (UFO3).ufo/glyphs/c.glif
+Tests/ufoLib/testdata/TestFont1 (UFO3).ufo/glyphs/contents.plist
+Tests/ufoLib/testdata/TestFont1 (UFO3).ufo/glyphs/d.glif
+Tests/ufoLib/testdata/TestFont1 (UFO3).ufo/glyphs/e.glif
+Tests/ufoLib/testdata/TestFont1 (UFO3).ufo/glyphs/f.glif
+Tests/ufoLib/testdata/TestFont1 (UFO3).ufo/glyphs/g.glif
+Tests/ufoLib/testdata/TestFont1 (UFO3).ufo/glyphs/h.glif
+Tests/ufoLib/testdata/TestFont1 (UFO3).ufo/glyphs/i.glif
+Tests/ufoLib/testdata/TestFont1 (UFO3).ufo/glyphs/j.glif
+Tests/ufoLib/testdata/TestFont1 (UFO3).ufo/glyphs/k.glif
+Tests/ufoLib/testdata/TestFont1 (UFO3).ufo/glyphs/l.glif
+Tests/ufoLib/testdata/TestFont1 (UFO3).ufo/glyphs/space.glif
+Tests/ufoLib/testdata/UFO3-Read Data.ufo/metainfo.plist
+Tests/ufoLib/testdata/UFO3-Read Data.ufo/data/org.unifiedfontobject.file.txt
+Tests/ufoLib/testdata/UFO3-Read Data.ufo/data/org.unifiedfontobject.directory/foo.txt
+Tests/ufoLib/testdata/UFO3-Read Data.ufo/data/org.unifiedfontobject.directory/bar/lol.txt
+Tests/varLib/__init__.py
+Tests/varLib/builder_test.py
+Tests/varLib/featureVars_test.py
+Tests/varLib/instancer_test.py
+Tests/varLib/interpolatable_test.py
+Tests/varLib/interpolate_layout_test.py
+Tests/varLib/models_test.py
+Tests/varLib/mutator_test.py
+Tests/varLib/varLib_test.py
+Tests/varLib/data/Build.designspace
+Tests/varLib/data/BuildAvarEmptyAxis.designspace
+Tests/varLib/data/BuildAvarIdentityMaps.designspace
+Tests/varLib/data/BuildAvarSingleAxis.designspace
+Tests/varLib/data/BuildGvarCompositeExplicitDelta.designspace
+Tests/varLib/data/FeatureVars.designspace
+Tests/varLib/data/InterpolateLayout.designspace
+Tests/varLib/data/InterpolateLayout2.designspace
+Tests/varLib/data/InterpolateLayout3.designspace
+Tests/varLib/data/KerningMerging.designspace
+Tests/varLib/data/PartialInstancerTest-VF.ttx
+Tests/varLib/data/PartialInstancerTest2-VF.ttx
+Tests/varLib/data/SparseMasters.designspace
+Tests/varLib/data/TestCFF2.designspace
+Tests/varLib/data/TestNonMarkingCFF2.designspace
+Tests/varLib/data/TestSparseCFF2VF.designspace
+Tests/varLib/data/TestVVAR.designspace
+Tests/varLib/data/test_vpal.designspace
+Tests/varLib/data/master_cff2/TestCFF2_Black.ttx
+Tests/varLib/data/master_cff2/TestCFF2_ExtraLight.ttx
+Tests/varLib/data/master_cff2/TestCFF2_Regular.ttx
+Tests/varLib/data/master_kerning_merging/0.ttx
+Tests/varLib/data/master_kerning_merging/1.ttx
+Tests/varLib/data/master_kerning_merging/2.ttx
+Tests/varLib/data/master_non_marking_cff2/TestNonMarkingCFF2_ExtraLight.ttx
+Tests/varLib/data/master_non_marking_cff2/TestNonMarkingCFF2_Regular.ttx
+Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w0.00.ttx
+Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w1000.00.ttx
+Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w439.00.ttx
+Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w440.00.ttx
+Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w599.00.ttx
+Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w600.00.ttx
+Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w669.00.ttx
+Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w670.00.ttx
+Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w799.00.ttx
+Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w800.00.ttx
+Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w889.00.ttx
+Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w890.00.ttx
+Tests/varLib/data/master_ttx_getvar_ttf/Mutator_Getvar.ttx
+Tests/varLib/data/master_ttx_interpolatable_otf/TestFamily2-Master0.ttx
+Tests/varLib/data/master_ttx_interpolatable_otf/TestFamily2-Master1.ttx
+Tests/varLib/data/master_ttx_interpolatable_ttf/SparseMasters-Bold.ttx
+Tests/varLib/data/master_ttx_interpolatable_ttf/SparseMasters-Medium.ttx
+Tests/varLib/data/master_ttx_interpolatable_ttf/SparseMasters-Regular.ttx
+Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master0.ttx
+Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master1.ttx
+Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master2.ttx
+Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master3.ttx
+Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master4.ttx
+Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily2-Master0.ttx
+Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily2-Master1.ttx
+Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-Bold.ttx
+Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-Condensed.ttx
+Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-CondensedBold.ttx
+Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-CondensedLight.ttx
+Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-CondensedSemiBold.ttx
+Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-Light.ttx
+Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-Regular.ttx
+Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-SemiBold.ttx
+Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily4-Italic15.ttx
+Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily4-Regular.ttx
+Tests/varLib/data/master_ttx_varfont_otf/TestCFF2VF.ttx
+Tests/varLib/data/master_ttx_varfont_ttf/Mutator_IUP.ttx
+Tests/varLib/data/master_ufo/TestFamily-Master0.ufo/features.fea
+Tests/varLib/data/master_ufo/TestFamily-Master0.ufo/fontinfo.plist
+Tests/varLib/data/master_ufo/TestFamily-Master0.ufo/lib.plist
+Tests/varLib/data/master_ufo/TestFamily-Master0.ufo/metainfo.plist
+Tests/varLib/data/master_ufo/TestFamily-Master0.ufo/glyphs/A_.glif
+Tests/varLib/data/master_ufo/TestFamily-Master0.ufo/glyphs/_notdef.glif
+Tests/varLib/data/master_ufo/TestFamily-Master0.ufo/glyphs/a.glif
+Tests/varLib/data/master_ufo/TestFamily-Master0.ufo/glyphs/contents.plist
+Tests/varLib/data/master_ufo/TestFamily-Master0.ufo/glyphs/dollar.glif
+Tests/varLib/data/master_ufo/TestFamily-Master0.ufo/glyphs/dollar.nostroke.glif
+Tests/varLib/data/master_ufo/TestFamily-Master0.ufo/glyphs/space.glif
+Tests/varLib/data/master_ufo/TestFamily-Master1.ufo/features.fea
+Tests/varLib/data/master_ufo/TestFamily-Master1.ufo/fontinfo.plist
+Tests/varLib/data/master_ufo/TestFamily-Master1.ufo/lib.plist
+Tests/varLib/data/master_ufo/TestFamily-Master1.ufo/metainfo.plist
+Tests/varLib/data/master_ufo/TestFamily-Master1.ufo/glyphs/A_.glif
+Tests/varLib/data/master_ufo/TestFamily-Master1.ufo/glyphs/_notdef.glif
+Tests/varLib/data/master_ufo/TestFamily-Master1.ufo/glyphs/a.glif
+Tests/varLib/data/master_ufo/TestFamily-Master1.ufo/glyphs/contents.plist
+Tests/varLib/data/master_ufo/TestFamily-Master1.ufo/glyphs/dollar.glif
+Tests/varLib/data/master_ufo/TestFamily-Master1.ufo/glyphs/dollar.nostroke.glif
+Tests/varLib/data/master_ufo/TestFamily-Master1.ufo/glyphs/space.glif
+Tests/varLib/data/master_ufo/TestFamily-Master2.ufo/features.fea
+Tests/varLib/data/master_ufo/TestFamily-Master2.ufo/fontinfo.plist
+Tests/varLib/data/master_ufo/TestFamily-Master2.ufo/lib.plist
+Tests/varLib/data/master_ufo/TestFamily-Master2.ufo/metainfo.plist
+Tests/varLib/data/master_ufo/TestFamily-Master2.ufo/glyphs/A_.glif
+Tests/varLib/data/master_ufo/TestFamily-Master2.ufo/glyphs/_notdef.glif
+Tests/varLib/data/master_ufo/TestFamily-Master2.ufo/glyphs/a.glif
+Tests/varLib/data/master_ufo/TestFamily-Master2.ufo/glyphs/contents.plist
+Tests/varLib/data/master_ufo/TestFamily-Master2.ufo/glyphs/dollar.glif
+Tests/varLib/data/master_ufo/TestFamily-Master2.ufo/glyphs/dollar.nostroke.glif
+Tests/varLib/data/master_ufo/TestFamily-Master2.ufo/glyphs/space.glif
+Tests/varLib/data/master_ufo/TestFamily-Master3.ufo/features.fea
+Tests/varLib/data/master_ufo/TestFamily-Master3.ufo/fontinfo.plist
+Tests/varLib/data/master_ufo/TestFamily-Master3.ufo/lib.plist
+Tests/varLib/data/master_ufo/TestFamily-Master3.ufo/metainfo.plist
+Tests/varLib/data/master_ufo/TestFamily-Master3.ufo/glyphs/A_.glif
+Tests/varLib/data/master_ufo/TestFamily-Master3.ufo/glyphs/_notdef.glif
+Tests/varLib/data/master_ufo/TestFamily-Master3.ufo/glyphs/a.glif
+Tests/varLib/data/master_ufo/TestFamily-Master3.ufo/glyphs/contents.plist
+Tests/varLib/data/master_ufo/TestFamily-Master3.ufo/glyphs/dollar.glif
+Tests/varLib/data/master_ufo/TestFamily-Master3.ufo/glyphs/dollar.nostroke.glif
+Tests/varLib/data/master_ufo/TestFamily-Master3.ufo/glyphs/space.glif
+Tests/varLib/data/master_ufo/TestFamily-Master4.ufo/features.fea
+Tests/varLib/data/master_ufo/TestFamily-Master4.ufo/fontinfo.plist
+Tests/varLib/data/master_ufo/TestFamily-Master4.ufo/lib.plist
+Tests/varLib/data/master_ufo/TestFamily-Master4.ufo/metainfo.plist
+Tests/varLib/data/master_ufo/TestFamily-Master4.ufo/glyphs/A_.glif
+Tests/varLib/data/master_ufo/TestFamily-Master4.ufo/glyphs/_notdef.glif
+Tests/varLib/data/master_ufo/TestFamily-Master4.ufo/glyphs/a.glif
+Tests/varLib/data/master_ufo/TestFamily-Master4.ufo/glyphs/contents.plist
+Tests/varLib/data/master_ufo/TestFamily-Master4.ufo/glyphs/dollar.glif
+Tests/varLib/data/master_ufo/TestFamily-Master4.ufo/glyphs/dollar.nostroke.glif
+Tests/varLib/data/master_ufo/TestFamily-Master4.ufo/glyphs/space.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/features.fea
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/fontinfo.plist
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/lib.plist
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/metainfo.plist
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/glyphs/A_.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/glyphs/A_.sc.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/glyphs/_notdef.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/glyphs/a.alt.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/glyphs/a.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/glyphs/ampersand.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/glyphs/atilde.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/glyphs/circledotted.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/glyphs/contents.plist
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/glyphs/d.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/glyphs/dieresisbelowcmb.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/glyphs/dieresiscmb.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/glyphs/f.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/glyphs/f_t.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/glyphs/n.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/glyphs/space.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/glyphs/t.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/glyphs/tildebelowcmb.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master0.ufo/glyphs/tildecmb.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/features.fea
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/fontinfo.plist
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/lib.plist
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/metainfo.plist
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/glyphs/A_.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/glyphs/A_.sc.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/glyphs/_notdef.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/glyphs/a.alt.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/glyphs/a.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/glyphs/ampersand.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/glyphs/atilde.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/glyphs/circledotted.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/glyphs/contents.plist
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/glyphs/d.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/glyphs/dieresisbelowcmb.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/glyphs/dieresiscmb.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/glyphs/f.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/glyphs/f_t.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/glyphs/n.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/glyphs/space.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/glyphs/t.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/glyphs/tildebelowcmb.glif
+Tests/varLib/data/master_ufo/TestFamily2-Master1.ufo/glyphs/tildecmb.glif
+Tests/varLib/data/master_ufo/TestFamily3-Bold.ufo/fontinfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-Bold.ufo/groups.plist
+Tests/varLib/data/master_ufo/TestFamily3-Bold.ufo/kerning.plist
+Tests/varLib/data/master_ufo/TestFamily3-Bold.ufo/layercontents.plist
+Tests/varLib/data/master_ufo/TestFamily3-Bold.ufo/lib.plist
+Tests/varLib/data/master_ufo/TestFamily3-Bold.ufo/metainfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-Bold.ufo/glyphs/F_.glif
+Tests/varLib/data/master_ufo/TestFamily3-Bold.ufo/glyphs/T_.glif
+Tests/varLib/data/master_ufo/TestFamily3-Bold.ufo/glyphs/contents.plist
+Tests/varLib/data/master_ufo/TestFamily3-Bold.ufo/glyphs/l.glif
+Tests/varLib/data/master_ufo/TestFamily3-Bold.ufo/glyphs/layerinfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-Bold.ufo/glyphs/n.glif
+Tests/varLib/data/master_ufo/TestFamily3-Bold.ufo/glyphs/o.glif
+Tests/varLib/data/master_ufo/TestFamily3-Bold.ufo/glyphs/s.glif
+Tests/varLib/data/master_ufo/TestFamily3-Bold.ufo/glyphs/t.glif
+Tests/varLib/data/master_ufo/TestFamily3-Condensed.ufo/fontinfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-Condensed.ufo/groups.plist
+Tests/varLib/data/master_ufo/TestFamily3-Condensed.ufo/kerning.plist
+Tests/varLib/data/master_ufo/TestFamily3-Condensed.ufo/layercontents.plist
+Tests/varLib/data/master_ufo/TestFamily3-Condensed.ufo/lib.plist
+Tests/varLib/data/master_ufo/TestFamily3-Condensed.ufo/metainfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-Condensed.ufo/glyphs/F_.glif
+Tests/varLib/data/master_ufo/TestFamily3-Condensed.ufo/glyphs/T_.glif
+Tests/varLib/data/master_ufo/TestFamily3-Condensed.ufo/glyphs/contents.plist
+Tests/varLib/data/master_ufo/TestFamily3-Condensed.ufo/glyphs/l.glif
+Tests/varLib/data/master_ufo/TestFamily3-Condensed.ufo/glyphs/layerinfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-Condensed.ufo/glyphs/n.glif
+Tests/varLib/data/master_ufo/TestFamily3-Condensed.ufo/glyphs/o.glif
+Tests/varLib/data/master_ufo/TestFamily3-Condensed.ufo/glyphs/s.glif
+Tests/varLib/data/master_ufo/TestFamily3-Condensed.ufo/glyphs/t.glif
+Tests/varLib/data/master_ufo/TestFamily3-CondensedBold.ufo/fontinfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedBold.ufo/groups.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedBold.ufo/kerning.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedBold.ufo/layercontents.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedBold.ufo/lib.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedBold.ufo/metainfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedBold.ufo/glyphs/F_.glif
+Tests/varLib/data/master_ufo/TestFamily3-CondensedBold.ufo/glyphs/T_.glif
+Tests/varLib/data/master_ufo/TestFamily3-CondensedBold.ufo/glyphs/contents.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedBold.ufo/glyphs/l.glif
+Tests/varLib/data/master_ufo/TestFamily3-CondensedBold.ufo/glyphs/layerinfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedBold.ufo/glyphs/n.glif
+Tests/varLib/data/master_ufo/TestFamily3-CondensedBold.ufo/glyphs/o.glif
+Tests/varLib/data/master_ufo/TestFamily3-CondensedBold.ufo/glyphs/s.glif
+Tests/varLib/data/master_ufo/TestFamily3-CondensedBold.ufo/glyphs/t.glif
+Tests/varLib/data/master_ufo/TestFamily3-CondensedLight.ufo/fontinfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedLight.ufo/groups.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedLight.ufo/kerning.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedLight.ufo/layercontents.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedLight.ufo/lib.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedLight.ufo/metainfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedLight.ufo/glyphs/F_.glif
+Tests/varLib/data/master_ufo/TestFamily3-CondensedLight.ufo/glyphs/T_.glif
+Tests/varLib/data/master_ufo/TestFamily3-CondensedLight.ufo/glyphs/contents.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedLight.ufo/glyphs/l.glif
+Tests/varLib/data/master_ufo/TestFamily3-CondensedLight.ufo/glyphs/layerinfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedLight.ufo/glyphs/n.glif
+Tests/varLib/data/master_ufo/TestFamily3-CondensedLight.ufo/glyphs/o.glif
+Tests/varLib/data/master_ufo/TestFamily3-CondensedLight.ufo/glyphs/s.glif
+Tests/varLib/data/master_ufo/TestFamily3-CondensedLight.ufo/glyphs/t.glif
+Tests/varLib/data/master_ufo/TestFamily3-CondensedSemiBold.ufo/fontinfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedSemiBold.ufo/groups.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedSemiBold.ufo/kerning.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedSemiBold.ufo/layercontents.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedSemiBold.ufo/lib.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedSemiBold.ufo/metainfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedSemiBold.ufo/glyphs/F_.glif
+Tests/varLib/data/master_ufo/TestFamily3-CondensedSemiBold.ufo/glyphs/T_.glif
+Tests/varLib/data/master_ufo/TestFamily3-CondensedSemiBold.ufo/glyphs/contents.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedSemiBold.ufo/glyphs/l.glif
+Tests/varLib/data/master_ufo/TestFamily3-CondensedSemiBold.ufo/glyphs/layerinfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-CondensedSemiBold.ufo/glyphs/n.glif
+Tests/varLib/data/master_ufo/TestFamily3-CondensedSemiBold.ufo/glyphs/o.glif
+Tests/varLib/data/master_ufo/TestFamily3-CondensedSemiBold.ufo/glyphs/s.glif
+Tests/varLib/data/master_ufo/TestFamily3-CondensedSemiBold.ufo/glyphs/t.glif
+Tests/varLib/data/master_ufo/TestFamily3-Light.ufo/fontinfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-Light.ufo/groups.plist
+Tests/varLib/data/master_ufo/TestFamily3-Light.ufo/kerning.plist
+Tests/varLib/data/master_ufo/TestFamily3-Light.ufo/layercontents.plist
+Tests/varLib/data/master_ufo/TestFamily3-Light.ufo/lib.plist
+Tests/varLib/data/master_ufo/TestFamily3-Light.ufo/metainfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-Light.ufo/glyphs/F_.glif
+Tests/varLib/data/master_ufo/TestFamily3-Light.ufo/glyphs/T_.glif
+Tests/varLib/data/master_ufo/TestFamily3-Light.ufo/glyphs/contents.plist
+Tests/varLib/data/master_ufo/TestFamily3-Light.ufo/glyphs/l.glif
+Tests/varLib/data/master_ufo/TestFamily3-Light.ufo/glyphs/layerinfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-Light.ufo/glyphs/n.glif
+Tests/varLib/data/master_ufo/TestFamily3-Light.ufo/glyphs/o.glif
+Tests/varLib/data/master_ufo/TestFamily3-Light.ufo/glyphs/s.glif
+Tests/varLib/data/master_ufo/TestFamily3-Light.ufo/glyphs/t.glif
+Tests/varLib/data/master_ufo/TestFamily3-Regular.ufo/fontinfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-Regular.ufo/groups.plist
+Tests/varLib/data/master_ufo/TestFamily3-Regular.ufo/kerning.plist
+Tests/varLib/data/master_ufo/TestFamily3-Regular.ufo/layercontents.plist
+Tests/varLib/data/master_ufo/TestFamily3-Regular.ufo/lib.plist
+Tests/varLib/data/master_ufo/TestFamily3-Regular.ufo/metainfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-Regular.ufo/glyphs/F_.glif
+Tests/varLib/data/master_ufo/TestFamily3-Regular.ufo/glyphs/T_.glif
+Tests/varLib/data/master_ufo/TestFamily3-Regular.ufo/glyphs/contents.plist
+Tests/varLib/data/master_ufo/TestFamily3-Regular.ufo/glyphs/l.glif
+Tests/varLib/data/master_ufo/TestFamily3-Regular.ufo/glyphs/layerinfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-Regular.ufo/glyphs/n.glif
+Tests/varLib/data/master_ufo/TestFamily3-Regular.ufo/glyphs/o.glif
+Tests/varLib/data/master_ufo/TestFamily3-Regular.ufo/glyphs/s.glif
+Tests/varLib/data/master_ufo/TestFamily3-Regular.ufo/glyphs/t.glif
+Tests/varLib/data/master_ufo/TestFamily3-SemiBold.ufo/fontinfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-SemiBold.ufo/groups.plist
+Tests/varLib/data/master_ufo/TestFamily3-SemiBold.ufo/kerning.plist
+Tests/varLib/data/master_ufo/TestFamily3-SemiBold.ufo/layercontents.plist
+Tests/varLib/data/master_ufo/TestFamily3-SemiBold.ufo/lib.plist
+Tests/varLib/data/master_ufo/TestFamily3-SemiBold.ufo/metainfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-SemiBold.ufo/glyphs/F_.glif
+Tests/varLib/data/master_ufo/TestFamily3-SemiBold.ufo/glyphs/T_.glif
+Tests/varLib/data/master_ufo/TestFamily3-SemiBold.ufo/glyphs/contents.plist
+Tests/varLib/data/master_ufo/TestFamily3-SemiBold.ufo/glyphs/l.glif
+Tests/varLib/data/master_ufo/TestFamily3-SemiBold.ufo/glyphs/layerinfo.plist
+Tests/varLib/data/master_ufo/TestFamily3-SemiBold.ufo/glyphs/n.glif
+Tests/varLib/data/master_ufo/TestFamily3-SemiBold.ufo/glyphs/o.glif
+Tests/varLib/data/master_ufo/TestFamily3-SemiBold.ufo/glyphs/s.glif
+Tests/varLib/data/master_ufo/TestFamily3-SemiBold.ufo/glyphs/t.glif
+Tests/varLib/data/master_ufo/TestFamily4-Italic15.ufo/features.fea
+Tests/varLib/data/master_ufo/TestFamily4-Italic15.ufo/fontinfo.plist
+Tests/varLib/data/master_ufo/TestFamily4-Italic15.ufo/groups.plist
+Tests/varLib/data/master_ufo/TestFamily4-Italic15.ufo/layercontents.plist
+Tests/varLib/data/master_ufo/TestFamily4-Italic15.ufo/lib.plist
+Tests/varLib/data/master_ufo/TestFamily4-Italic15.ufo/metainfo.plist
+Tests/varLib/data/master_ufo/TestFamily4-Italic15.ufo/glyphs/N_.glif
+Tests/varLib/data/master_ufo/TestFamily4-Italic15.ufo/glyphs/O_.glif
+Tests/varLib/data/master_ufo/TestFamily4-Italic15.ufo/glyphs/O_dieresis.glif
+Tests/varLib/data/master_ufo/TestFamily4-Italic15.ufo/glyphs/contents.plist
+Tests/varLib/data/master_ufo/TestFamily4-Italic15.ufo/glyphs/dieresiscomb.glif
+Tests/varLib/data/master_ufo/TestFamily4-Italic15.ufo/glyphs/n.glif
+Tests/varLib/data/master_ufo/TestFamily4-Italic15.ufo/glyphs/o.glif
+Tests/varLib/data/master_ufo/TestFamily4-Italic15.ufo/glyphs/odieresis.glif
+Tests/varLib/data/master_ufo/TestFamily4-Italic15.ufo/glyphs.public.background/N_.glif
+Tests/varLib/data/master_ufo/TestFamily4-Italic15.ufo/glyphs.public.background/O_.glif
+Tests/varLib/data/master_ufo/TestFamily4-Italic15.ufo/glyphs.public.background/contents.plist
+Tests/varLib/data/master_ufo/TestFamily4-Italic15.ufo/glyphs.public.background/dieresiscomb.glif
+Tests/varLib/data/master_ufo/TestFamily4-Italic15.ufo/glyphs.public.background/o.glif
+Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/features.fea
+Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/fontinfo.plist
+Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/groups.plist
+Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/kerning.plist
+Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/layercontents.plist
+Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/lib.plist
+Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/metainfo.plist
+Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/glyphs/N_.glif
+Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/glyphs/O_.glif
+Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/glyphs/O_dieresis.glif
+Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/glyphs/contents.plist
+Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/glyphs/dieresiscomb.glif
+Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/glyphs/n.glif
+Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/glyphs/o.glif
+Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/glyphs/odieresis.glif
+Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/glyphs.public.background/N_.glif
+Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/glyphs.public.background/O_.glif
+Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/glyphs.public.background/contents.plist
+Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/glyphs.public.background/dieresiscomb.glif
+Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/glyphs.public.background/n.glif
+Tests/varLib/data/master_ufo/TestFamily4-Regular.ufo/glyphs.public.background/o.glif
+Tests/varLib/data/master_vpal_test/master_vpal_test_0.ttx
+Tests/varLib/data/master_vpal_test/master_vpal_test_1.ttx
+Tests/varLib/data/master_vvar_cff2/TestVVAR.0.ttx
+Tests/varLib/data/master_vvar_cff2/TestVVAR.1.ttx
+Tests/varLib/data/test_results/Build.ttx
+Tests/varLib/data/test_results/BuildAvarEmptyAxis.ttx
+Tests/varLib/data/test_results/BuildAvarIdentityMaps.ttx
+Tests/varLib/data/test_results/BuildAvarSingleAxis.ttx
+Tests/varLib/data/test_results/BuildGvarCompositeExplicitDelta.ttx
+Tests/varLib/data/test_results/BuildMain.ttx
+Tests/varLib/data/test_results/BuildTestCFF2.ttx
+Tests/varLib/data/test_results/FeatureVars.ttx
+Tests/varLib/data/test_results/InterpolateLayout.ttx
+Tests/varLib/data/test_results/InterpolateLayout2.ttx
+Tests/varLib/data/test_results/InterpolateLayoutGPOS_1_diff.ttx
+Tests/varLib/data/test_results/InterpolateLayoutGPOS_1_diff2.ttx
+Tests/varLib/data/test_results/InterpolateLayoutGPOS_1_same.ttx
+Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_class_diff.ttx
+Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_class_diff2.ttx
+Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_class_same.ttx
+Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_spec_diff.ttx
+Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_spec_diff2.ttx
+Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_spec_same.ttx
+Tests/varLib/data/test_results/InterpolateLayoutGPOS_3_diff.ttx
+Tests/varLib/data/test_results/InterpolateLayoutGPOS_3_same.ttx
+Tests/varLib/data/test_results/InterpolateLayoutGPOS_4_diff.ttx
+Tests/varLib/data/test_results/InterpolateLayoutGPOS_4_same.ttx
+Tests/varLib/data/test_results/InterpolateLayoutGPOS_5_diff.ttx
+Tests/varLib/data/test_results/InterpolateLayoutGPOS_5_same.ttx
+Tests/varLib/data/test_results/InterpolateLayoutGPOS_6_diff.ttx
+Tests/varLib/data/test_results/InterpolateLayoutGPOS_6_same.ttx
+Tests/varLib/data/test_results/InterpolateLayoutGPOS_8_diff.ttx
+Tests/varLib/data/test_results/InterpolateLayoutGPOS_8_same.ttx
+Tests/varLib/data/test_results/InterpolateLayoutGPOS_size_feat_same.ttx
+Tests/varLib/data/test_results/InterpolateLayoutMain.ttx
+Tests/varLib/data/test_results/InterpolateTestCFF2VF.ttx
+Tests/varLib/data/test_results/Mutator.ttx
+Tests/varLib/data/test_results/Mutator_Getvar-instance.ttx
+Tests/varLib/data/test_results/Mutator_IUP-instance.ttx
+Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-100,100.ttx
+Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-100,62.5.ttx
+Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-400,100.ttx
+Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-400,62.5.ttx
+Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-900,100.ttx
+Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-900,62.5.ttx
+Tests/varLib/data/test_results/SparseMasters.ttx
+Tests/varLib/data/test_results/TestNonMarkingCFF2.ttx
+Tests/varLib/data/test_results/TestSparseCFF2VF.ttx
+Tests/varLib/data/test_results/TestVVAR.ttx
+Tests/varLib/data/test_results/test_vpal.ttx
+Tests/voltLib/lexer_test.py
+Tests/voltLib/parser_test.py
\ No newline at end of file
diff --git a/Lib/fonttools.egg-info/dependency_links.txt b/Lib/fonttools.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/Lib/fonttools.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/Lib/fonttools.egg-info/entry_points.txt b/Lib/fonttools.egg-info/entry_points.txt
new file mode 100644
index 0000000..2c235cf
--- /dev/null
+++ b/Lib/fonttools.egg-info/entry_points.txt
@@ -0,0 +1,6 @@
+[console_scripts]
+fonttools = fontTools.__main__:main
+pyftmerge = fontTools.merge:main
+pyftsubset = fontTools.subset:main
+ttx = fontTools.ttx:main
+
diff --git a/Lib/fonttools.egg-info/requires.txt b/Lib/fonttools.egg-info/requires.txt
new file mode 100644
index 0000000..46d1d13
--- /dev/null
+++ b/Lib/fonttools.egg-info/requires.txt
@@ -0,0 +1,76 @@
+
+[all]
+fs<3,>=2.2.0
+lxml<5,>=4.0
+zopfli>=0.1.4
+lz4>=1.7.4.2
+matplotlib
+sympy
+
+[all:platform_python_implementation != "PyPy"]
+brotli>=1.0.1
+scipy
+
+[all:platform_python_implementation == "PyPy"]
+brotlipy>=0.7.0
+munkres
+
+[all:python_version < "3.4"]
+enum34>=1.1.6
+singledispatch>=3.4.0.3
+typing>=3.6.4
+
+[all:python_version < "3.8" and platform_python_implementation != "PyPy"]
+unicodedata2>=12.0.0
+
+[all:sys_platform == "darwin"]
+xattr
+
+[graphite]
+lz4>=1.7.4.2
+
+[interpolatable]
+
+[interpolatable:platform_python_implementation != "PyPy"]
+scipy
+
+[interpolatable:platform_python_implementation == "PyPy"]
+munkres
+
+[lxml]
+lxml<5,>=4.0
+
+[lxml:python_version < "3.4"]
+singledispatch>=3.4.0.3
+typing>=3.6.4
+
+[plot]
+matplotlib
+
+[symfont]
+sympy
+
+[type1]
+
+[type1:sys_platform == "darwin"]
+xattr
+
+[ufo]
+fs<3,>=2.2.0
+
+[ufo:python_version < "3.4"]
+enum34>=1.1.6
+
+[unicode]
+
+[unicode:python_version < "3.8" and platform_python_implementation != "PyPy"]
+unicodedata2>=12.0.0
+
+[woff]
+zopfli>=0.1.4
+
+[woff:platform_python_implementation != "PyPy"]
+brotli>=1.0.1
+
+[woff:platform_python_implementation == "PyPy"]
+brotlipy>=0.7.0
diff --git a/Lib/fonttools.egg-info/top_level.txt b/Lib/fonttools.egg-info/top_level.txt
new file mode 100644
index 0000000..9af65ba
--- /dev/null
+++ b/Lib/fonttools.egg-info/top_level.txt
@@ -0,0 +1 @@
+fontTools
diff --git a/MANIFEST.in b/MANIFEST.in
index 8e2bcd1..1529112 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -11,9 +11,7 @@
 
 include *requirements.txt
 include tox.ini
-include mypy.ini
-
-recursive-include Lib/fontTools py.typed
+include run-tests.sh
 
 include .appveyor.yml
 include .codecov.yml
@@ -21,13 +19,8 @@
 include .travis.yml
 recursive-include .travis *.sh
 
-recursive-include Icons *.png *.pdf
-
 include Doc/Makefile
 include Doc/make.bat
-include Doc/docs-requirements.txt
-include Doc/README.md
-include Doc/source/assets/img/favicon.ico
 recursive-include Doc/man/man1 *.1
 recursive-include Doc/source *.py *.rst
 
@@ -39,5 +32,3 @@
 recursive-include Tests *.lwfn *.pfa *.pfb
 recursive-include Tests *.xml *.designspace *.bin
 recursive-include Tests *.afm
-recursive-include Tests *.json
-recursive-include Tests *.ufoz
diff --git a/METADATA b/METADATA
index 6ef136d..00ee9d7 100644
--- a/METADATA
+++ b/METADATA
@@ -1,6 +1,3 @@
-# *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS.  PLEASE
-#     CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE
-#     DEPENDING ON IT IN YOUR PROJECT. ***
 name: "fonttools"
 description: "fontTools is a library for manipulating fonts, written in Python."
 third_party {
@@ -10,13 +7,12 @@
   }
   url {
     type: ARCHIVE
-    value: "https://github.com/fonttools/fonttools/archive/4.22.0.zip"
+    value: "https://github.com/fonttools/fonttools/releases/download/3.44.0/fonttools-3.44.0.zip"
   }
-  version: "4.22.0"
-  license_type: BY_EXCEPTION_ONLY
+  version: "3.44.0"
   last_upgrade_date {
-    year: 2021
-    month: 4
-    day: 1
+    year: 2019
+    month: 8
+    day: 2
   }
 }
diff --git a/Makefile b/Makefile
index 21cad6c..bd91d7f 100644
--- a/Makefile
+++ b/Makefile
@@ -14,12 +14,9 @@
 	pip uninstall --yes fonttools
 
 check: all
-	pytest
+	./run-tests.sh
 
 clean:
 	./setup.py clean --all
 
-docs:
-	cd Doc && $(MAKE) html
-
-.PHONY: all dist install install-user uninstall check clean docs
+.PHONY: all dist install install-user uninstall check clean
diff --git a/MetaTools/buildTableList.py b/MetaTools/buildTableList.py
index c3766b9..eb9fb85 100755
--- a/MetaTools/buildTableList.py
+++ b/MetaTools/buildTableList.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python3
+#! /usr/bin/env python
 
 import sys
 import os
@@ -11,7 +11,7 @@
 fontToolsDir= os.path.normpath(fontToolsDir)
 tablesDir = os.path.join(fontToolsDir,
 		"Lib", "fontTools", "ttLib", "tables")
-docFile = os.path.join(fontToolsDir, "Doc/source/ttx.rst")
+docFile = os.path.join(fontToolsDir, "README.rst")
 
 names = glob.glob1(tablesDir, "*.py")
 
@@ -33,6 +33,9 @@
 with open(os.path.join(tablesDir, "__init__.py"), "w") as file:
 
 	file.write('''
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+
 # DON'T EDIT! This file is generated by MetaTools/buildTableList.py.
 def _moduleFinderHint():
 	"""Dummy function to let modulefinder know what tables may be
@@ -52,7 +55,7 @@
 ''')
 
 
-begin = ".. begin table list\n"
+begin = ".. begin table list\n.. code::\n"
 end = ".. end table list"
 with open(docFile) as f:
 	doc = f.read()
@@ -62,10 +65,9 @@
 endPos = doc.find(end)
 
 lines = textwrap.wrap(", ".join(tables[:-1]) + " and " + tables[-1], 66)
-intro = "The following tables are currently supported::\n\n"
 blockquote = "\n".join(" "*4 + line for line in lines) + "\n"
 
-doc = doc[:beginPos] + intro + blockquote + "\n" + doc[endPos:]
+doc = doc[:beginPos] + blockquote + doc[endPos:]
 
 with open(docFile, "w") as f:
 	f.write(doc)
diff --git a/MetaTools/buildUCD.py b/MetaTools/buildUCD.py
index 16ae150..12bd58f 100755
--- a/MetaTools/buildUCD.py
+++ b/MetaTools/buildUCD.py
@@ -1,8 +1,10 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
 """
 Tools to parse data files from the Unicode Character Database.
 """
 
+from __future__ import print_function, absolute_import, division
+from __future__ import unicode_literals
 
 try:
     from urllib.request import urlopen
diff --git a/MetaTools/roundTrip.py b/MetaTools/roundTrip.py
index f9094ab..648bc9d 100755
--- a/MetaTools/roundTrip.py
+++ b/MetaTools/roundTrip.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python3
+#! /usr/bin/env python
 
 """usage: ttroundtrip [options] font1 ... fontN
 
@@ -31,9 +31,9 @@
 
 def roundTrip(ttFile1, options, report):
 	fn = os.path.basename(ttFile1)
-	xmlFile1 = tempfile.mkstemp(".%s.ttx1" % fn)
-	ttFile2 = tempfile.mkstemp(".%s" % fn)
-	xmlFile2 = tempfile.mkstemp(".%s.ttx2" % fn)
+	xmlFile1 = tempfile.mktemp(".%s.ttx1" % fn)
+	ttFile2 = tempfile.mktemp(".%s" % fn)
+	xmlFile2 = tempfile.mktemp(".%s.ttx2" % fn)
 	
 	try:
 		ttx.ttDump(ttFile1, xmlFile1, options)
diff --git a/NEWS.rst b/NEWS.rst
index b07f5b1..2a00702 100644
--- a/NEWS.rst
+++ b/NEWS.rst
@@ -1,553 +1,3 @@
-4.22.0 (released 2021-04-01)
-----------------------------
-
-- [ttLib] Remove .Format from Coverage, ClassDef, SingleSubst, LigatureSubst,
-  AlternateSubst, MultipleSubst (#2238).
-  ATTENTION: This will change your TTX dumps!
-- [misc.arrayTools] move Vector to its own submodule, and rewrite as a tuple
-  subclass (#2201).
-- [docs] Added a terminology section for varLib (#2209).
-- [varLib] Move rounding to VariationModel, to avoid error accumulation from
-  multiple deltas (#2214)
-- [varLib] Explain merge errors in more human-friendly terms (#2223, #2226)
-- [otlLib] Correct some documentation (#2225)
-- [varLib/otlLib] Allow merging into VariationFont without first saving GPOS
-  PairPos2 (#2229)
-- [subset] Improve PairPosFormat2 subsetting (#2221)
-- [ttLib] TTFont.save: create file on disk as late as possible (#2253)
-- [cffLib] Add missing CFF2 dict operators LanguageGroup and ExpansionFactor
-  (#2249)
-  ATTENTION: This will change your TTX dumps!
-
-4.21.1 (released 2021-02-26)
-----------------------------
-
-- [pens] Reverted breaking change that turned ``AbstractPen`` and ``AbstractPointPen``
-  into abstract base classes (#2164, #2198).
-
-4.21.0 (released 2021-02-26)
-----------------------------
-
-- [feaLib] Indent anchor statements in ``asFea()`` to make them more legible and
-  diff-able (#2193).
-- [pens] Turn ``AbstractPen`` and ``AbstractPointPen`` into abstract base classes
-  (#2164).
-- [feaLib] Added support for parsing and building ``STAT`` table from AFDKO feature
-  files (#2039).
-- [instancer] Added option to update name table of generated instance using ``STAT``
-  table's axis values (#2189).
-- [bezierTools] Added functions to compute bezier point-at-time, as well as line-line,
-  curve-line and curve-curve intersections (#2192).
-
-4.20.0 (released 2021-02-15)
-----------------------------
-
-- [COLRv1] Added ``unbuildColrV1`` to deconstruct COLRv1 otTables to raw json-able
-  data structure; it does the reverse of ``buildColrV1`` (#2171).
-- [feaLib] Allow ``sub X by NULL`` sequence to delete a glyph (#2170).
-- [arrayTools] Fixed ``Vector`` division (#2173).
-- [COLRv1] Define new ``PaintSweepGradient`` (#2172).
-- [otTables] Moved ``Paint.Format`` enum class outside of ``Paint`` class definition,
-  now named ``PaintFormat``. It was clashing with paint instance ``Format`` attribute
-  and thus was breaking lazy load of COLR table which relies on magic ``__getattr__``
-  (#2175).
-- [COLRv1] Replace hand-coded builder functions with otData-driven dynamic
-  implementation (#2181).
-- [COLRv1] Define additional static (non-variable) Paint formats (#2181).
-- [subset] Added support for subsetting COLR v1 and CPAL tables (#2174, #2177).
-- [fontBuilder] Allow ``setupFvar`` to optionally take ``designspaceLib.AxisDescriptor``
-  objects. Added new ``setupAvar`` method. Support localised names for axes and
-  named instances (#2185).
-
-4.19.1 (released 2021-01-28)
-----------------------------
-
-- [woff2] An initial off-curve point with an overlap flag now stays an off-curve
-  point after compression.
-
-4.19.0 (released 2021-01-25)
-----------------------------
-
-- [codecs] Handle ``errors`` parameter different from 'strict' for the custom
-  extended mac encodings (#2137, #2132).
-- [featureVars] Raise better error message when a script is missing the required
-  default language system (#2154).
-- [COLRv1] Avoid abrupt change caused by rounding ``PaintRadialGradient.c0`` when
-  the start circle almost touches the end circle's perimeter (#2148).
-- [COLRv1] Support building unlimited lists of paints as 255-ary trees of
-  ``PaintColrLayers`` tables (#2153).
-- [subset] Prune redundant format-12 cmap subtables when all non-BMP characters
-  are dropped (#2146).
-- [basePen] Raise ``MissingComponentError`` instead of bare ``KeyError`` when a
-  referenced component is missing (#2145).
-
-4.18.2 (released 2020-12-16)
-----------------------------
-
-- [COLRv1] Implemented ``PaintTranslate`` paint format (#2129).
-- [varLib.cff] Fixed unbound local variable error (#1787).
-- [otlLib] Don't crash when creating OpenType class definitions if some glyphs
-  occur more than once (#2125).
-
-4.18.1 (released 2020-12-09)
-----------------------------
-
-- [colorLib] Speed optimization for ``LayerV1ListBuilder`` (#2119).
-- [mutator] Fixed missing tab in ``interpolate_cff2_metrics`` (0957dc7a).
-
-4.18.0 (released 2020-12-04)
-----------------------------
-
-- [COLRv1] Update to latest draft: added ``PaintRotate`` and ``PaintSkew`` (#2118).
-- [woff2] Support new ``brotlicffi`` bindings for PyPy (#2117).
-- [glifLib] Added ``expectContentsFile`` parameter to ``GlyphSet``, for use when
-  reading existing UFOs, to comply with the specification stating that a
-  ``contents.plist`` file must exist in a glyph set (#2114).
-- [subset] Allow ``LangSys`` tags in ``--layout-scripts`` option (#2112). For example:
-  ``--layout-scripts=arab.dflt,arab.URD,latn``; this will keep ``DefaultLangSys``
-  and ``URD`` language for ``arab`` script, and all languages for ``latn`` script.
-- [varLib.interpolatable] Allow UFOs to be checked; report open paths, non existant
-  glyphs; add a ``--json`` option to produce a machine-readable list of
-  incompatibilities
-- [pens] Added ``QuartzPen`` to create ``CGPath`` from glyph outlines on macOS.
-  Requires pyobjc (#2107).
-- [feaLib] You can export ``FONTTOOLS_LOOKUP_DEBUGGING=1`` to enable feature file
-  debugging info stored in ``Debg`` table (#2106).
-- [otlLib] Build more efficient format 1 and format 2 contextual lookups whenever
-  possible (#2101).
-
-4.17.1 (released 2020-11-16)
-----------------------------
-
-- [colorLib] Fixed regression in 4.17.0 when building COLR v0 table; when color
-  layers are stored in UFO lib plist, we can't distinguish tuples from lists so
-  we need to accept either types (e5439eb9, googlefonts/ufo2ft/issues#426).
-
-4.17.0 (released 2020-11-12)
-----------------------------
-
-- [colorLib/otData] Updated to latest draft ``COLR`` v1 spec (#2092).
-- [svgLib] Fixed parsing error when arc commands' boolean flags are not separated
-  by space or comma (#2094).
-- [varLib] Interpret empty non-default glyphs as 'missing', if the default glyph is
-  not empty (#2082).
-- [feaLib.builder] Only stash lookup location for ``Debg`` if ``Builder.buildLookups_``
-  has cooperated (#2065, #2067).
-- [varLib] Fixed bug in VarStore optimizer (#2073, #2083).
-- [varLib] Add designspace lib key for custom feavar feature tag (#2080).
-- Add HashPointPen adapted from psautohint. With this pen, a hash value of a glyph
-  can be computed, which can later be used to detect glyph changes (#2005).
-
-4.16.1 (released 2020-10-05)
-----------------------------
-
-- [varLib.instancer] Fixed ``TypeError`` exception when instantiating a VF with
-  a GSUB table 1.1 in which ``FeatureVariations`` attribute is present but set to
-  ``None`` -- indicating that optional ``FeatureVariations`` is missing (#2077).
-- [glifLib] Make ``x`` and ``y`` attributes of the ``point`` element required
-  even when validation is turned off, and raise a meaningful ``GlifLibError``
-  message when that happens (#2075).
-
-4.16.0 (released 2020-09-30)
-----------------------------
-
-- [removeOverlaps] Added new module and ``removeOverlaps`` function that merges
-  overlapping contours and components in TrueType glyphs. It requires the
-  `skia-pathops <https://github.com/fonttools/skia-pathops>`__ module.
-  Note that removing overlaps invalidates the TrueType hinting (#2068).
-- [varLib.instancer] Added ``--remove-overlaps`` command-line option.
-  The ``overlap`` option in ``instantiateVariableFont`` now takes an ``OverlapMode``
-  enum: 0: KEEP_AND_DONT_SET_FLAGS, 1: KEEP_AND_SET_FLAGS (default), and 2: REMOVE.
-  The latter is equivalent to calling ``removeOverlaps`` on the generated static
-  instance. The option continues to accept ``bool`` value for backward compatibility.
-
-
-4.15.0 (released 2020-09-21)
-----------------------------
-
-- [plistlib] Added typing annotations to plistlib module. Set up mypy static
-  typechecker to run automatically on CI (#2061).
-- [ttLib] Implement private ``Debg`` table, a reverse-DNS namespaced JSON dict.
-- [feaLib] Optionally add an entry into the ``Debg`` table with the original
-  lookup name (if any), feature name / script / language combination (if any),
-  and original source filename and line location. Annotate the ttx output for
-  a lookup with the information from the Debg table (#2052).
-- [sfnt] Disabled checksum checking by default in ``SFNTReader`` (#2058).
-- [Docs] Document ``mtiLib`` module (#2027).
-- [varLib.interpolatable] Added checks for contour node count and operation type
-  of each node (#2054).
-- [ttLib] Added API to register custom table packer/unpacker classes (#2055).
-
-4.14.0 (released 2020-08-19)
-----------------------------
-
-- [feaLib] Allow anonymous classes in LookupFlags definitions (#2037).
-- [Docs] Better document DesignSpace rules processing order (#2041).
-- [ttLib] Fixed 21-year old bug in ``maxp.maxComponentDepth`` calculation (#2044,
-  #2045).
-- [varLib.models] Fixed misspelled argument name in CLI entry point (81d0042a).
-- [subset] When subsetting GSUB v1.1, fixed TypeError by checking whether the
-  optional FeatureVariations table is present (e63ecc5b).
-- [Snippets] Added snippet to show how to decompose glyphs in a TTF (#2030).
-- [otlLib] Generate GSUB type 5 and GPOS type 7 contextual lookups where appropriate
-  (#2016).
-
-4.13.0 (released 2020-07-10)
-----------------------------
-
-- [feaLib/otlLib] Moved lookup subtable builders from feaLib to otlLib; refactored
-  some common code (#2004, #2007).
-- [docs] Document otlLib module (#2009).
-- [glifLib] Fixed bug with some UFO .glif filenames clashing on case-insensitive
-  filesystems (#2001, #2002).
-- [colorLib] Updated COLRv1 implementation following changes in the draft spec:
-  (#2008, googlefonts/colr-gradients-spec#24).
-
-4.12.1 (released 2020-06-16)
-----------------------------
-
-- [_n_a_m_e] Fixed error in ``addMultilingualName`` with one-character names.
-  Only attempt to recovered malformed UTF-16 data from a ``bytes`` string,
-  not from unicode ``str`` (#1997, #1998).
-
-4.12.0 (released 2020-06-09)
-----------------------------
-
-- [otlLib/varLib] Ensure that the ``AxisNameID`` in the ``STAT`` and ``fvar``
-  tables is grater than 255 as per OpenType spec (#1985, #1986).
-- [docs] Document more modules in ``fontTools.misc`` package: ``filenames``,
-  ``fixedTools``, ``intTools``, ``loggingTools``, ``macCreatorType``, ``macRes``,
-  ``plistlib`` (#1981).
-- [OS/2] Don't calculate whole sets of unicode codepoints, use faster and more memory
-  efficient ranges and bisect lookups (#1984).
-- [voltLib] Support writing back abstract syntax tree as VOLT data (#1983).
-- [voltLib] Accept DO_NOT_TOUCH_CMAP keyword (#1987).
-- [subset/merge] Fixed a namespace clash involving a private helper class (#1955).
-
-4.11.0 (released 2020-05-28)
-----------------------------
-
-- [feaLib] Introduced ``includeDir`` parameter on Parser and IncludingLexer to
-  explicitly specify the directory to search when ``include()`` statements are
-  encountered (#1973).
-- [ufoLib] Silently delete duplicate glyphs within the same kerning group when reading
-  groups (#1970).
-- [ttLib] Set version of COLR table when decompiling COLRv1 (commit 9d8a7e2).
-
-4.10.2 (released 2020-05-20)
-----------------------------
-
-- [sfnt] Fixed ``NameError: SimpleNamespace`` while reading TTC header. The regression
-  was introduced with 4.10.1 after removing ``py23`` star import.
-
-4.10.1 (released 2020-05-19)
-----------------------------
-
-- [sfnt] Make ``SFNTReader`` pickleable even when TTFont is loaded with lazy=True
-  option and thus keeps a reference to an external file (#1962, #1967).
-- [feaLib.ast] Restore backward compatibility (broken in 4.10 with #1905) for
-  ``ChainContextPosStatement`` and ``ChainContextSubstStatement`` classes.
-  Make them accept either list of lookups or list of lists of lookups (#1961).
-- [docs] Document some modules in ``fontTools.misc`` package: ``arrayTools``,
-  ``bezierTools`` ``cliTools`` and ``eexec`` (#1956).
-- [ttLib._n_a_m_e] Fixed ``findMultilingualName()`` when name record's ``string`` is
-  encoded as bytes sequence (#1963).
-
-4.10.0 (released 2020-05-15)
-----------------------------
-
-- [varLib] Allow feature variations to be active across the entire space (#1957).
-- [ufoLib] Added support for ``formatVersionMinor`` in UFO's ``fontinfo.plist`` and for
-  ``formatMinor`` attribute in GLIF file as discussed in unified-font-object/ufo-spec#78.
-  No changes in reading or writing UFOs until an upcoming (non-0) minor update of the
-  UFO specification is published (#1786).
-- [merge] Fixed merging fonts with different versions of ``OS/2`` table (#1865, #1952).
-- [subset] Fixed ``AttributeError`` while subsetting ``ContextSubst`` and ``ContextPos``
-  Format 3 subtable (#1879, #1944).
-- [ttLib.table._m_e_t_a] if data happens to be ascii, emit comment in TTX (#1938).
-- [feaLib] Support multiple lookups per glyph position (#1905).
-- [psCharStrings] Use inheritance to avoid repeated code in initializer (#1932).
-- [Doc] Improved documentation for the following modules: ``afmLib`` (#1933), ``agl``
-  (#1934), ``cffLib`` (#1935), ``cu2qu`` (#1937), ``encodings`` (#1940), ``feaLib``
-  (#1941), ``merge`` (#1949).
-- [Doc] Split off developer-centric info to new page, making front page of docs more
-  user-focused. List all utilities and sub-modules with brief descriptions.
-  Make README more concise and focused (#1914).
-- [otlLib] Add function to build STAT table from high-level description (#1926).
-- [ttLib._n_a_m_e] Add ``findMultilingualName()`` method (#1921).
-- [unicodedata] Update ``RTL_SCRIPTS`` for Unicode 13.0 (#1925).
-- [gvar] Sort ``gvar`` XML output by glyph name, not glyph order (#1907, #1908).
-- [Doc] Added help options to ``fonttools`` command line tool (#1913, #1920).
-  Ensure all fonttools CLI tools have help documentation (#1948).
-- [ufoLib] Only write fontinfo.plist when there actually is content (#1911).
-
-4.9.0 (released 2020-04-29)
----------------------------
-
-- [subset] Fixed subsetting of FeatureVariations table. The subsetter no longer drops
-  FeatureVariationRecords that have empty substitutions as that will keep the search
-  going and thus change the logic. It will only drop empty records that occur at the
-  end of the FeatureVariationRecords array (#1881).
-- [subset] Remove FeatureVariations table and downgrade GSUB/GPOS to version 0x10000
-  when FeatureVariations contain no FeatureVariationRecords after subsetting (#1903).
-- [agl] Add support for legacy Adobe Glyph List of glyph names in ``fontTools.agl``
-  (#1895).
-- [feaLib] Ignore superfluous script statements (#1883).
-- [feaLib] Hide traceback by default on ``fonttools feaLib`` command line.
-  Use ``--traceback`` option to show (#1898).
-- [feaLib] Check lookup index in chaining sub/pos lookups and print better error
-  message (#1896, #1897).
-- [feaLib] Fix building chained alt substitutions (#1902).
-- [Doc] Included all fontTools modules in the sphinx-generated documentation, and
-  published it to ReadTheDocs for continuous documentation of the fontTools project
-  (#1333). Check it out at https://fonttools.readthedocs.io/. Thanks to Chris Simpkins!
-- [transform] The ``Transform`` class is now subclass of ``typing.NamedTuple``. No
-  change in functionality (#1904).
-
-
-4.8.1 (released 2020-04-17)
----------------------------
-
-- [feaLib] Fixed ``AttributeError: 'NoneType' has no attribute 'getAlternateGlyphs'``
-  when ``aalt`` feature references a chain contextual substitution lookup
-  (googlefonts/fontmake#648, #1878).
-
-4.8.0 (released 2020-04-16)
----------------------------
-
-- [feaLib] If Parser is initialized without a ``glyphNames`` parameter, it cannot
-  distinguish between a glyph name containing an hyphen, or a range of glyph names;
-  instead of raising an error, it now interprets them as literal glyph names, while
-  also outputting a logging warning to alert user about the ambiguity (#1768, #1870).
-- [feaLib] When serializing AST to string, emit spaces around hyphens that denote
-  ranges. Also, fixed an issue with CID ranges when round-tripping AST->string->AST
-  (#1872).
-- [Snippets/otf2ttf] In otf2ttf.py script update LSB in hmtx to match xMin (#1873).
-- [colorLib] Added experimental support for building ``COLR`` v1 tables as per
-  the `colr-gradients-spec <https://github.com/googlefonts/colr-gradients-spec/blob/master/colr-gradients-spec.md>`__
-  draft proposal. **NOTE**: both the API and the XML dump of ``COLR`` v1 are
-  susceptible to change while the proposal is being discussed and formalized (#1822).
-
-4.7.0 (released 2020-04-03)
----------------------------
-
-- [cu2qu] Added ``fontTools.cu2qu`` package, imported from the original
-  `cu2qu <https://github.com/googlefonts/cu2qu>`__ project. The ``cu2qu.pens`` module
-  was moved to ``fontTools.pens.cu2quPen``. The optional cu2qu extension module
-  can be compiled by installing `Cython <https://cython.org/>`__ before installing
-  fonttools from source (i.e. git repo or sdist tarball). The wheel package that
-  is published on PyPI (i.e. the one ``pip`` downloads, unless ``--no-binary``
-  option is used), will continue to be pure-Python for now (#1868).
-
-4.6.0 (released 2020-03-24)
----------------------------
-
-- [varLib] Added support for building variable ``BASE`` table version 1.1 (#1858).
-- [CPAL] Added ``fromRGBA`` method to ``Color`` class (#1861).
-
-
-4.5.0 (released 2020-03-20)
----------------------------
-
-- [designspaceLib] Added ``add{Axis,Source,Instance,Rule}Descriptor`` methods to
-  ``DesignSpaceDocument`` class, to initialize new descriptor objects using keyword
-  arguments, and at the same time append them to the current document (#1860).
-- [unicodedata] Update to Unicode 13.0 (#1859).
-
-4.4.3 (released 2020-03-13)
----------------------------
-
-- [varLib] Always build ``gvar`` table for TrueType-flavored Variable Fonts,
-  even if it contains no variation data. The table is required according to
-  the OpenType spec (#1855, #1857).
-
-4.4.2 (released 2020-03-12)
----------------------------
-
-- [ttx] Annotate ``LookupFlag`` in XML dump with comment explaining what bits
-  are set and what they mean (#1850).
-- [feaLib] Added more descriptive message to ``IncludedFeaNotFound`` error (#1842).
-
-4.4.1 (released 2020-02-26)
----------------------------
-
-- [woff2] Skip normalizing ``glyf`` and ``loca`` tables if these are missing from
-  a font (e.g. in NotoColorEmoji using ``CBDT/CBLC`` tables).
-- [timeTools] Use non-localized date parsing in ``timestampFromString``, to fix
-  error when non-English ``LC_TIME`` locale is set (#1838, #1839).
-- [fontBuilder] Make sure the CFF table generated by fontBuilder can be used by varLib
-  without having to compile and decompile the table first. This was breaking in
-  converting the CFF table to CFF2 due to some unset attributes (#1836).
-
-4.4.0 (released 2020-02-18)
----------------------------
-
-- [colorLib] Added ``fontTools.colorLib.builder`` module, initially with ``buildCOLR``
-  and ``buildCPAL`` public functions. More color font formats will follow (#1827).
-- [fontBuilder] Added ``setupCOLR`` and ``setupCPAL`` methods (#1826).
-- [ttGlyphPen] Quantize ``GlyphComponent.transform`` floats to ``F2Dot14`` to fix
-  round-trip issue when computing bounding boxes of transformed components (#1830).
-- [glyf] If a component uses reference points (``firstPt`` and ``secondPt``) for
-  alignment (instead of X and Y offsets), compute the effective translation offset
-  *after* having applied any transform (#1831).
-- [glyf] When all glyphs have zero contours, compile ``glyf`` table data as a single
-  null byte in order to pass validation by OTS and Windows (#1829).
-- [feaLib] Parsing feature code now ensures that referenced glyph names are part of
-  the known glyph set, unless a glyph set was not provided.
-- [varLib] When filling in the default axis value for a missing location of a source or
-  instance, correctly map the value forward.
-- [varLib] The avar table can now contain mapping output values that are greater than
-  OR EQUAL to the preceeding value, as the avar specification allows this.
-- [varLib] The errors of the module are now ordered hierarchically below VarLibError. 
-  See #1821.
-
-4.3.0 (released 2020-02-03)
----------------------------
-
-- [EBLC/CBLC] Fixed incorrect padding length calculation for Format 3 IndexSubTable
-  (#1817, #1818).
-- [varLib] Fixed error when merging OTL tables and TTFonts were loaded as ``lazy=True``
-  (#1808, #1809).
-- [varLib] Allow to use master fonts containing ``CFF2`` table when building VF (#1816).
-- [ttLib] Make ``recalcBBoxes`` option work also with ``CFF2`` table (#1816).
-- [feaLib] Don't reset ``lookupflag`` in lookups defined inside feature blocks.
-  They will now inherit the current ``lookupflag`` of the feature. This is what
-  Adobe ``makeotf`` also does in this case (#1815).
-- [feaLib] Fixed bug with mixed single/multiple substitutions. If a single substitution
-  involved a glyph class, we were incorrectly using only the first glyph in the class
-  (#1814).
-
-4.2.5 (released 2020-01-29)
----------------------------
-
-- [feaLib] Do not fail on duplicate multiple substitutions, only warn (#1811).
-- [subset] Optimize SinglePos subtables to Format 1 if all ValueRecords are the same
-  (#1802).
-
-4.2.4 (released 2020-01-09)
----------------------------
-
-- [unicodedata] Update RTL_SCRIPTS for Unicode 11 and 12.
-
-4.2.3 (released 2020-01-07)
----------------------------
-
-- [otTables] Fixed bug when splitting `MarkBasePos` subtables as offsets overflow.
-  The mark class values in the split subtable were not being updated, leading to
-  invalid mark-base attachments (#1797, googlefonts/noto-source#145).
-- [feaLib] Only log a warning instead of error when features contain duplicate
-  substitutions (#1767).
-- [glifLib] Strip XML comments when parsing with lxml (#1784, #1785).
-
-4.2.2 (released 2019-12-12)
----------------------------
-
-- [subset] Fixed issue with subsetting FeatureVariations table when the index
-  of features changes as features get dropped. The feature index need to be
-  remapped to point to index of the remaining features (#1777, #1782).
-- [fontBuilder] Added `addFeatureVariations` method to `FontBuilder` class. This
-  is a shorthand for calling `featureVars.addFeatureVariations` on the builder's
-  TTFont object (#1781).
-- [glyf] Fixed the flags bug in glyph.drawPoints() like we did for glyph.draw()
-  (#1771, #1774).
-
-4.2.1 (released 2019-12-06)
----------------------------
-
-- [glyf] Use the ``flagOnCurve`` bit mask in ``glyph.draw()``, so that we ignore
-  the ``overlap`` flag that may be set when instantiating variable fonts (#1771).
-
-4.2.0 (released 2019-11-28)
----------------------------
-
-- [pens] Added the following pens:
-
-  * ``roundingPen.RoundingPen``: filter pen that rounds coordinates and components'
-    offsets to integer;
-  * ``roundingPen.RoundingPointPen``: like the above, but using PointPen protocol.
-  * ``filterPen.FilterPointPen``: base class for filter point pens;
-  * ``transformPen.TransformPointPen``: filter point pen to apply affine transform;
-  * ``recordingPen.RecordingPointPen``: records and replays point-pen commands.
-
-- [ttGlyphPen] Always round float coordinates and component offsets to integers
-  (#1763).
-- [ufoLib] When converting kerning groups from UFO2 to UFO3, avoid confusing
-  groups with the same name as one of the glyphs (#1761, #1762,
-  unified-font-object/ufo-spec#98).
-
-4.1.0 (released 2019-11-18)
----------------------------
-
-- [instancer] Implemented restricting axis ranges (level 3 partial instancing).
-  You can now pass ``{axis_tag: (min, max)}`` tuples as input to the
-  ``instantiateVariableFont`` function. Note that changing the default axis
-  position is not supported yet. The command-line script also accepts axis ranges
-  in the form of colon-separated float values, e.g. ``wght=400:700`` (#1753, #1537).
-- [instancer] Never drop STAT ``DesignAxis`` records, but only prune out-of-range
-  ``AxisValue`` records.
-- [otBase/otTables] Enforce that VarStore.RegionAxisCount == fvar.axisCount, even
-  when regions list is empty to appease OTS < v8.0 (#1752).
-- [designspaceLib] Defined new ``processing`` attribute for ``<rules>`` element,
-  with values "first" or "last", plus other editorial changes to DesignSpace
-  specification. Bumped format version to 4.1 (#1750).
-- [varLib] Improved error message when masters' glyph orders do not match (#1758,
-  #1759).
-- [featureVars] Allow to specify custom feature tag in ``addFeatureVariations``;
-  allow said feature to already exist, in which case we append new lookup indices
-  to existing features. Implemented ``<rules>`` attribute ``processing`` according to
-  DesignSpace specification update in #1750. Depending on this flag, we generate
-  either an 'rvrn' (always processed first) or a 'rclt' feature (follows lookup order,
-  therefore last) (#1747, #1625, #1371).
-- [ttCollection] Added support for context manager auto-closing via ``with`` statement
-  like with ``TTFont`` (#1751).
-- [unicodedata] Require unicodedata2 >= 12.1.0.
-- [py2.py3] Removed yet more PY2 vestiges (#1743).
-- [_n_a_m_e] Fixed issue when comparing NameRecords with different string types (#1742).
-- [fixedTools] Changed ``fixedToFloat`` to not do any rounding but simply return
-  ``value / (1 << precisionBits)``. Added ``floatToFixedToStr`` and
-  ``strToFixedToFloat`` functions to be used when loading from or dumping to XML.
-  Fixed values (e.g. fvar axes and instance coordinates, avar mappings, etc.) are
-  are now stored as un-rounded decimal floats upon decompiling (#1740, #737).
-- [feaLib] Fixed handling of multiple ``LigatureCaret`` statements for the same glyph.
-  Only the first rule per glyph is used, additional ones are ignored (#1733).
-
-4.0.2 (released 2019-09-26)
----------------------------
-
-- [voltLib] Added support for ``ALL`` and ``NONE`` in ``PROCESS_MARKS`` (#1732).
-- [Silf] Fixed issue in ``Silf`` table compilation and decompilation regarding str vs
-  bytes in python3 (#1728).
-- [merge] Handle duplicate glyph names better: instead of appending font index to
-  all glyph names, use similar code like we use in ``post`` and ``CFF`` tables (#1729).
-
-4.0.1 (released 2019-09-11)
----------------------------
-
-- [otTables] Support fixing offset overflows in ``MultipleSubst`` lookup subtables
-  (#1706).
-- [subset] Prune empty strikes in ``EBDT`` and ``CBDT`` table data (#1698, #1633).
-- [pens] Fixed issue in ``PointToSegmentPen`` when last point of closed contour has
-  same coordinates as the starting point and was incorrectly dropped (#1720).
-- [Graphite] Fixed ``Sill`` table output to pass OTS (#1705).
-- [name] Added ``removeNames`` method to ``table__n_a_m_e`` class (#1719).
-- [ttLib] Added aliases for renamed entries ``ascender`` and ``descender`` in
-  ``hhea`` table (#1715).
-
-4.0.0 (released 2019-08-22)
----------------------------
-
-- NOTE: The v4.x version series only supports Python 3.6 or greater. You can keep
-  using fonttools 3.x if you need support for Python 2.
-- [py23] Removed all the python2-only code since it is no longer reachable, thus
-  unused; only the Python3 symbols were kept, but these are no-op. The module is now
-  DEPRECATED and will removed in the future.
-- [ttLib] Fixed UnboundLocalError for empty loca/glyph tables (#1680). Also, allow
-  the glyf table to be incomplete when dumping to XML (#1681).
-- [varLib.models] Fixed KeyError while sorting masters and there are no on-axis for
-  a given axis (38a8eb0e).
-- [cffLib] Make sure glyph names are unique (#1699).
-- [feaLib] Fix feature parser to correctly handle octal numbers (#1700).
-
 3.44.0 (released 2019-08-02)
 ----------------------------
 
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..29e9467
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,1823 @@
+Metadata-Version: 2.1
+Name: fonttools
+Version: 3.44.0
+Summary: Tools to manipulate font files
+Home-page: http://github.com/fonttools/fonttools
+Author: Just van Rossum
+Author-email: just@letterror.com
+Maintainer: Behdad Esfahbod
+Maintainer-email: behdad@behdad.org
+License: MIT
+Description: |Travis Build Status| |Appveyor Build status| |Coverage Status| |PyPI| |Gitter Chat|
+        
+        What is this?
+        ~~~~~~~~~~~~~
+        
+        | fontTools is a library for manipulating fonts, written in Python. The
+          project includes the TTX tool, that can convert TrueType and OpenType
+          fonts to and from an XML text format, which is also called TTX. It
+          supports TrueType, OpenType, AFM and to an extent Type 1 and some
+          Mac-specific formats. The project has an `MIT open-source
+          licence <LICENSE>`__.
+        | Among other things this means you can use it free of charge.
+        
+        Installation
+        ~~~~~~~~~~~~
+        
+        FontTools requires `Python <http://www.python.org/download/>`__ 2.7, 3.4
+        or later.
+        
+        **NOTE** From August 2019, until no later than January 1 2020, the support
+        for *Python 2.7* will be limited to only critical bug fixes, and no new features
+        will be added to the ``py27`` branch. The upcoming FontTools 4.x series will require
+        *Python 3.6* or above. You can read more `here <https://python3statement.org>`__
+        and `here <https://github.com/fonttools/fonttools/issues/765>`__ for the
+        reasons behind this decision.
+        
+        The package is listed in the Python Package Index (PyPI), so you can
+        install it with `pip <https://pip.pypa.io>`__:
+        
+        .. code:: sh
+        
+            pip install fonttools
+        
+        If you would like to contribute to its development, you can clone the
+        repository from GitHub, install the package in 'editable' mode and
+        modify the source code in place. We recommend creating a virtual
+        environment, using `virtualenv <https://virtualenv.pypa.io>`__ or
+        Python 3 `venv <https://docs.python.org/3/library/venv.html>`__ module.
+        
+        .. code:: sh
+        
+            # download the source code to 'fonttools' folder
+            git clone https://github.com/fonttools/fonttools.git
+            cd fonttools
+        
+            # create new virtual environment called e.g. 'fonttools-venv', or anything you like
+            python -m virtualenv fonttools-venv
+        
+            # source the `activate` shell script to enter the environment (Un*x); to exit, just type `deactivate`
+            . fonttools-venv/bin/activate
+        
+            # to activate the virtual environment in Windows `cmd.exe`, do
+            fonttools-venv\Scripts\activate.bat
+        
+            # install in 'editable' mode
+            pip install -e .
+        
+        TTX – From OpenType and TrueType to XML and Back
+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+        
+        Once installed you can use the ``ttx`` command to convert binary font
+        files (``.otf``, ``.ttf``, etc) to the TTX XML format, edit them, and
+        convert them back to binary format. TTX files have a .ttx file
+        extension.
+        
+        .. code:: sh
+        
+            ttx /path/to/font.otf
+            ttx /path/to/font.ttx
+        
+        The TTX application can be used in two ways, depending on what
+        platform you run it on:
+        
+        -  As a command line tool (Windows/DOS, Unix, macOS)
+        -  By dropping files onto the application (Windows, macOS)
+        
+        TTX detects what kind of files it is fed: it will output a ``.ttx`` file
+        when it sees a ``.ttf`` or ``.otf``, and it will compile a ``.ttf`` or
+        ``.otf`` when the input file is a ``.ttx`` file. By default, the output
+        file is created in the same folder as the input file, and will have the
+        same name as the input file but with a different extension. TTX will
+        *never* overwrite existing files, but if necessary will append a unique
+        number to the output filename (before the extension) such as
+        ``Arial#1.ttf``
+        
+        When using TTX from the command line there are a bunch of extra options.
+        These are explained in the help text, as displayed when typing
+        ``ttx -h`` at the command prompt. These additional options include:
+        
+        -  specifying the folder where the output files are created
+        -  specifying which tables to dump or which tables to exclude
+        -  merging partial ``.ttx`` files with existing ``.ttf`` or ``.otf``
+           files
+        -  listing brief table info instead of dumping to ``.ttx``
+        -  splitting tables to separate ``.ttx`` files
+        -  disabling TrueType instruction disassembly
+        
+        The TTX file format
+        -------------------
+        
+        The following tables are currently supported:
+        
+        .. begin table list
+        .. code::
+        
+            BASE, CBDT, CBLC, CFF, CFF2, COLR, CPAL, DSIG, EBDT, EBLC, FFTM,
+            Feat, GDEF, GMAP, GPKG, GPOS, GSUB, Glat, Gloc, HVAR, JSTF, LTSH,
+            MATH, META, MVAR, OS/2, SING, STAT, SVG, Silf, Sill, TSI0, TSI1,
+            TSI2, TSI3, TSI5, TSIB, TSID, TSIJ, TSIP, TSIS, TSIV, TTFA, VDMX,
+            VORG, VVAR, ankr, avar, bsln, cidg, cmap, cvar, cvt, feat, fpgm,
+            fvar, gasp, gcid, glyf, gvar, hdmx, head, hhea, hmtx, kern, lcar,
+            loca, ltag, maxp, meta, mort, morx, name, opbd, post, prep, prop,
+            sbix, trak, vhea and vmtx
+        .. end table list
+        
+        Other tables are dumped as hexadecimal data.
+        
+        TrueType fonts use glyph indices (GlyphIDs) to refer to glyphs in most
+        places. While this is fine in binary form, it is really hard to work
+        with for humans. Therefore we use names instead.
+        
+        The glyph names are either extracted from the ``CFF`` table or the
+        ``post`` table, or are derived from a Unicode ``cmap`` table. In the
+        latter case the Adobe Glyph List is used to calculate names based on
+        Unicode values. If all of these methods fail, names are invented based
+        on GlyphID (eg ``glyph00142``)
+        
+        It is possible that different glyphs use the same name. If this happens,
+        we force the names to be unique by appending ``#n`` to the name (``n``
+        being an integer number.) The original names are being kept, so this has
+        no influence on a "round tripped" font.
+        
+        Because the order in which glyphs are stored inside the binary font is
+        important, we maintain an ordered list of glyph names in the font.
+        
+        Other Tools
+        ~~~~~~~~~~~
+        
+        Commands for merging and subsetting fonts are also available:
+        
+        .. code:: sh
+        
+            pyftmerge
+            pyftsubset
+        
+        fontTools Python Module
+        ~~~~~~~~~~~~~~~~~~~~~~~
+        
+        The fontTools Python module provides a convenient way to
+        programmatically edit font files.
+        
+        .. code:: py
+        
+            >>> from fontTools.ttLib import TTFont
+            >>> font = TTFont('/path/to/font.ttf')
+            >>> font
+            <fontTools.ttLib.TTFont object at 0x10c34ed50>
+            >>>
+        
+        A selection of sample Python programs is in the
+        `Snippets <https://github.com/fonttools/fonttools/blob/master/Snippets/>`__
+        directory.
+        
+        Optional Requirements
+        ---------------------
+        
+        The ``fontTools`` package currently has no (required) external dependencies
+        besides the modules included in the Python Standard Library.
+        However, a few extra dependencies are required by some of its modules, which
+        are needed to unlock optional features.
+        The ``fonttools`` PyPI distribution also supports so-called "extras", i.e. a
+        set of keywords that describe a group of additional dependencies, which can be
+        used when installing via pip, or when specifying a requirement.
+        For example:
+        
+        .. code:: sh
+        
+            pip install fonttools[ufo,lxml,woff,unicode]
+        
+        This command will install fonttools, as well as the optional dependencies that
+        are required to unlock the extra features named "ufo", etc.
+        
+        - ``Lib/fontTools/misc/etree.py``
+        
+          The module exports a ElementTree-like API for reading/writing XML files, and
+          allows to use as the backend either the built-in ``xml.etree`` module or
+          `lxml <https://http://lxml.de>`__. The latter is preferred whenever present,
+          as it is generally faster and more secure.
+        
+          *Extra:* ``lxml``
+        
+        - ``Lib/fontTools/ufoLib``
+        
+          Package for reading and writing UFO source files; it requires:
+        
+          * `fs <https://pypi.org/pypi/fs>`__: (aka ``pyfilesystem2``) filesystem
+            abstraction layer.
+        
+          * `enum34 <https://pypi.org/pypi/enum34>`__: backport for the built-in ``enum``
+            module (only required on Python < 3.4).
+        
+          *Extra:* ``ufo``
+        
+        - ``Lib/fontTools/ttLib/woff2.py``
+        
+          Module to compress/decompress WOFF 2.0 web fonts; it requires:
+        
+          * `brotli <https://pypi.python.org/pypi/Brotli>`__: Python bindings of
+            the Brotli compression library.
+        
+          *Extra:* ``woff``
+        
+        - ``Lib/fontTools/ttLib/sfnt.py``
+        
+          To better compress WOFF 1.0 web fonts, the following module can be used
+          instead of the built-in ``zlib`` library:
+        
+          * `zopfli <https://pypi.python.org/pypi/zopfli>`__: Python bindings of
+            the Zopfli compression library.
+        
+          *Extra:* ``woff``
+        
+        - ``Lib/fontTools/unicode.py``
+        
+          To display the Unicode character names when dumping the ``cmap`` table
+          with ``ttx`` we use the ``unicodedata`` module in the Standard Library.
+          The version included in there varies between different Python versions.
+          To use the latest available data, you can install:
+        
+          * `unicodedata2 <https://pypi.python.org/pypi/unicodedata2>`__:
+            ``unicodedata`` backport for Python 2.7 and 3.x updated to the latest
+            Unicode version 12.0. Note this is not necessary if you use Python 3.8
+            as the latter already comes with an up-to-date ``unicodedata``.
+        
+          *Extra:* ``unicode``
+        
+        - ``Lib/fontTools/varLib/interpolatable.py``
+        
+          Module for finding wrong contour/component order between different masters.
+          It requires one of the following packages in order to solve the so-called
+          "minimum weight perfect matching problem in bipartite graphs", or
+          the Assignment problem:
+        
+          * `scipy <https://pypi.python.org/pypi/scipy>`__: the Scientific Library
+            for Python, which internally uses `NumPy <https://pypi.python.org/pypi/numpy>`__
+            arrays and hence is very fast;
+          * `munkres <https://pypi.python.org/pypi/munkres>`__: a pure-Python
+            module that implements the Hungarian or Kuhn-Munkres algorithm.
+        
+          *Extra:* ``interpolatable``
+        
+        - ``Lib/fontTools/varLib/plot.py``
+        
+          Module for visualizing DesignSpaceDocument and resulting VariationModel.
+        
+          * `matplotlib <https://pypi.org/pypi/matplotlib>`__: 2D plotting library.
+        
+          *Extra:* ``plot``
+        
+        - ``Lib/fontTools/misc/symfont.py``
+        
+          Advanced module for symbolic font statistics analysis; it requires:
+        
+          * `sympy <https://pypi.python.org/pypi/sympy>`__: the Python library for
+            symbolic mathematics.
+        
+          *Extra:* ``symfont``
+        
+        - ``Lib/fontTools/t1Lib.py``
+        
+          To get the file creator and type of Macintosh PostScript Type 1 fonts
+          on Python 3 you need to install the following module, as the old ``MacOS``
+          module is no longer included in Mac Python:
+        
+          * `xattr <https://pypi.python.org/pypi/xattr>`__: Python wrapper for
+            extended filesystem attributes (macOS platform only).
+        
+          *Extra:* ``type1``
+        
+        - ``Lib/fontTools/pens/cocoaPen.py``
+        
+          Pen for drawing glyphs with Cocoa ``NSBezierPath``, requires:
+        
+          * `PyObjC <https://pypi.python.org/pypi/pyobjc>`__: the bridge between
+            Python and the Objective-C runtime (macOS platform only).
+        
+        - ``Lib/fontTools/pens/qtPen.py``
+        
+          Pen for drawing glyphs with Qt's ``QPainterPath``, requires:
+        
+          * `PyQt5 <https://pypi.python.org/pypi/PyQt5>`__: Python bindings for
+            the Qt cross platform UI and application toolkit.
+        
+        - ``Lib/fontTools/pens/reportLabPen.py``
+        
+          Pen to drawing glyphs as PNG images, requires:
+        
+          * `reportlab <https://pypi.python.org/pypi/reportlab>`__: Python toolkit
+            for generating PDFs and graphics.
+        
+        Testing
+        ~~~~~~~
+        
+        To run the test suite, you need to install `pytest <http://docs.pytest.org/en/latest/>`__.
+        When you run the ``pytest`` command, the tests will run against the
+        installed ``fontTools`` package, or the first one found in the
+        ``PYTHONPATH``.
+        
+        You can also use `tox <https://tox.readthedocs.io/en/latest/>`__ to
+        automatically run tests on different Python versions in isolated virtual
+        environments.
+        
+        .. code:: sh
+        
+            pip install tox
+            tox
+        
+        Note that when you run ``tox`` without arguments, the tests are executed
+        for all the environments listed in tox.ini's ``envlist``. In our case,
+        this includes Python 2.7 and 3.7, so for this to work the ``python2.7``
+        and ``python3.7`` executables must be available in your ``PATH``.
+        
+        You can specify an alternative environment list via the ``-e`` option,
+        or the ``TOXENV`` environment variable:
+        
+        .. code:: sh
+        
+            tox -e py27
+            TOXENV="py36-cov,htmlcov" tox
+        
+        Development Community
+        ~~~~~~~~~~~~~~~~~~~~~
+        
+        TTX/FontTools development is ongoing in an active community of
+        developers, that includes professional developers employed at major
+        software corporations and type foundries as well as hobbyists.
+        
+        Feature requests and bug reports are always welcome at
+        https://github.com/fonttools/fonttools/issues/
+        
+        The best place for discussions about TTX from an end-user perspective as
+        well as TTX/FontTools development is the
+        https://groups.google.com/d/forum/fonttools mailing list. There is also
+        a development https://groups.google.com/d/forum/fonttools-dev mailing
+        list for continuous integration notifications. You can also email Behdad
+        privately at behdad@behdad.org
+        
+        History
+        ~~~~~~~
+        
+        The fontTools project was started by Just van Rossum in 1999, and was
+        maintained as an open source project at
+        http://sourceforge.net/projects/fonttools/. In 2008, Paul Wise (pabs3)
+        began helping Just with stability maintenance. In 2013 Behdad Esfahbod
+        began a friendly fork, thoroughly reviewing the codebase and making
+        changes at https://github.com/behdad/fonttools to add new features and
+        support for new font formats.
+        
+        Acknowledgements
+        ~~~~~~~~~~~~~~~~
+        
+        In alphabetical order:
+        
+        Olivier Berten, Samyak Bhuta, Erik van Blokland, Petr van Blokland,
+        Jelle Bosma, Sascha Brawer, Tom Byrer, Frédéric Coiffier, Vincent
+        Connare, Dave Crossland, Simon Daniels, Peter Dekkers, Behdad Esfahbod,
+        Behnam Esfahbod, Hannes Famira, Sam Fishman, Matt Fontaine, Yannis
+        Haralambous, Greg Hitchcock, Jeremie Hornus, Khaled Hosny, John Hudson,
+        Denis Moyogo Jacquerye, Jack Jansen, Tom Kacvinsky, Jens Kutilek,
+        Antoine Leca, Werner Lemberg, Tal Leming, Peter Lofting, Cosimo Lupo,
+        Masaya Nakamura, Dave Opstad, Laurence Penney, Roozbeh Pournader, Garret
+        Rieger, Read Roberts, Guido van Rossum, Just van Rossum, Andreas Seidel,
+        Georg Seifert, Miguel Sousa, Adam Twardoch, Adrien Tétar, Vitaly Volkov,
+        Paul Wise.
+        
+        Copyrights
+        ~~~~~~~~~~
+        
+        | Copyright (c) 1999-2004 Just van Rossum, LettError
+          (just@letterror.com)
+        | See `LICENSE <LICENSE>`__ for the full license.
+        
+        Copyright (c) 2000 BeOpen.com. All Rights Reserved.
+        
+        Copyright (c) 1995-2001 Corporation for National Research Initiatives.
+        All Rights Reserved.
+        
+        Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. All
+        Rights Reserved.
+        
+        Have fun!
+        
+        .. |Travis Build Status| image:: https://travis-ci.org/fonttools/fonttools.svg
+           :target: https://travis-ci.org/fonttools/fonttools
+        .. |Appveyor Build status| image:: https://ci.appveyor.com/api/projects/status/0f7fmee9as744sl7/branch/master?svg=true
+           :target: https://ci.appveyor.com/project/fonttools/fonttools/branch/master
+        .. |Coverage Status| image:: https://codecov.io/gh/fonttools/fonttools/branch/master/graph/badge.svg
+           :target: https://codecov.io/gh/fonttools/fonttools
+        .. |PyPI| image:: https://img.shields.io/pypi/v/fonttools.svg
+           :target: https://pypi.org/project/FontTools
+        .. |Gitter Chat| image:: https://badges.gitter.im/fonttools-dev/Lobby.svg
+           :alt: Join the chat at https://gitter.im/fonttools-dev/Lobby
+           :target: https://gitter.im/fonttools-dev/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
+        
+        Changelog
+        ~~~~~~~~~
+        
+        3.44.0 (released 2019-08-02)
+        ----------------------------
+        
+        - NOTE: This is the last scheduled release to support Python 2.7. The upcoming fonttools
+          v4.x series is going to require Python 3.6 or greater.
+        - [varLib] Added new ``varLib.instancer`` module for partially instantiating variable
+          fonts. This extends (and will eventually replace) ``varLib.mutator`` module, as
+          it allows to create not just full static instances from a variable font, but also
+          "partial" or "less variable" fonts where some of the axes are dropped or
+          instantiated at a particular value.
+          Also available from the command-line as `fonttools varLib.instancer --help`
+          (#1537, #1628).
+        - [cffLib] Added support for ``FDSelect`` format 4 (#1677).
+        - [subset] Added support for subsetting ``sbix`` (Apple bitmap color font) table.
+        - [t1Lib] Fixed issue parsing ``eexec`` section in Type1 fonts when whitespace
+          characters are interspersed among the trailing zeros (#1676).
+        - [cffLib.specializer] Fixed bug in ``programToCommands`` with CFF2 charstrings (#1669).
+        
+        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)
+        ----------------------------
+        
+        - [subset] Fixed regression when passing ``--flavor=woff2`` option with an input font
+          that was already compressed as WOFF 1.0 (#1650).
+        
+        3.43.0 (released 2019-06-18)
+        ----------------------------
+        
+        - [woff2] Added support for compressing/decompressing WOFF2 fonts with non-transformed
+          ``glyf`` and ``loca`` tables, as well as with transformed ``hmtx`` table.
+          Removed ``Snippets/woff2_compress.py`` and ``Snippets/woff2_decompress.py`` scripts,
+          and replaced them with a new console entry point ``fonttools ttLib.woff2``
+          that provides two sub-commands ``compress`` and ``decompress``.
+        - [varLib.cff] Fixed bug when merging CFF2 ``PrivateDicts``. The ``PrivateDict``
+          data from the first region font was incorrecty used for all subsequent fonts.
+          The bug would only affect variable CFF2 fonts with hinting (#1643, #1644).
+          Also, fixed a merging bug when VF masters have no blends or marking glyphs (#1632,
+          #1642).
+        - [loggingTools] Removed unused backport of ``LastResortLogger`` class.
+        - [subset] Gracefully handle partial MATH table (#1635).
+        - [featureVars] Avoid duplicate references to ``rvrn`` feature record in
+          ``DefaultLangSys`` tables when calling ``addFeatureVariations`` on a font that
+          does not already have a ``GSUB`` table (aa8a5bc6).
+        - [varLib] Fixed merging of class-based kerning. Before, the process could introduce
+          rogue kerning values and variations for random classes against class zero (everything
+          not otherwise classed).
+        - [varLib] Fixed merging GPOS tables from master fonts with different number of
+          ``SinglePos`` subtables (#1621, #1641).
+        - [unicodedata] Updated Blocks, Scripts and ScriptExtensions to Unicode 12.1.
+        
+        3.42.0 (released 2019-05-28)
+        ----------------------------
+        
+        - [OS/2] Fixed sign of ``fsType``: it should be ``uint16``, not ``int16`` (#1619).
+        - [subset] Skip out-of-range class values in mark attachment (#1478).
+        - [fontBuilder] Add an empty ``DSIG`` table with ``setupDummyDSIG`` method (#1621).
+        - [varLib.merger] Fixed bug whereby ``GDEF.GlyphClassDef`` were being dropped
+          when generating instance via ``varLib.mutator`` (#1614).
+        - [varLib] Added command-line options ``-v`` and ``-q`` to configure logging (#1613).
+        - [subset] Update font extents in head table (#1612).
+        - [subset] Make --retain-gids truncate empty glyphs after the last non-empty glyph
+          (#1611).
+        - [requirements] Updated ``unicodedata2`` backport for Unicode 12.0.
+        
+        3.41.2 (released 2019-05-13)
+        ----------------------------
+        
+        - [cffLib] Fixed issue when importing a ``CFF2`` variable font from XML, whereby
+          the VarStore state was not propagated to PrivateDict (#1598).
+        - [varLib] Don't drop ``post`` glyph names when building CFF2 variable font (#1609).
+        
+        
+        3.41.1 (released 2019-05-13)
+        ----------------------------
+        
+        - [designspaceLib] Added ``loadSourceFonts`` method to load source fonts using
+          custom opener function (#1606).
+        - [head] Round font bounding box coordinates to integers to fix compile error
+          if CFF font has float coordinates (#1604, #1605).
+        - [feaLib] Don't write ``None`` in ``ast.ValueRecord.asFea()`` (#1599).
+        - [subset] Fixed issue ``AssertionError`` when using ``--desubroutinize`` option
+          (#1590, #1594).
+        - [graphite] Fixed bug in ``Silf`` table's ``decompile`` method unmasked by
+          previous typo fix (#1597). Decode languange code as UTF-8 in ``Sill`` table's
+          ``decompile`` method (#1600).
+        
+        3.41.0 (released 2019-04-29)
+        ----------------------------
+        
+        - [varLib/cffLib] Added support for building ``CFF2`` variable font from sparse
+          masters, or masters with more than one model (multiple ``VarStore.VarData``).
+          In ``cffLib.specializer``, added support for ``CFF2`` CharStrings with
+          ``blend`` operators (#1547, #1591).
+        - [subset] Fixed subsetting ``HVAR`` and ``VVAR`` with ``--retain-gids`` option,
+          and when advances mapping is null while sidebearings mappings are non-null
+          (#1587, #1588).
+        - Added ``otlLib.maxContextCalc`` module to compute ``OS/2.usMaxContext`` value.
+          Calculate it automatically when compiling features with feaLib. Added option
+          ``--recalc-max-context`` to ``subset`` module (#1582).
+        - [otBase/otTables] Fixed ``AttributeError`` on missing OT table fields after
+          importing font from TTX (#1584).
+        - [graphite] Fixed typo ``Silf`` table's ``decompile`` method (#1586).
+        - [otlLib] Better compress ``GPOS`` SinglePos (LookupType 1) subtables (#1539).
+        
+        3.40.0 (released 2019-04-08)
+        ----------------------------
+        
+        - [subset] Fixed error while subsetting ``VVAR`` with ``--retain-gids``
+          option (#1552).
+        - [designspaceLib] Use up-to-date default location in ``findDefault`` method
+          (#1554).
+        - [voltLib] Allow passing file-like object to Parser.
+        - [arrayTools/glyf] ``calcIntBounds`` (used to compute bounding boxes of glyf
+          table's glyphs) now uses ``otRound`` instead of ``round3`` (#1566).
+        - [svgLib] Added support for converting more SVG shapes to path ``d`` strings
+          (ellipse, line, polyline), as well as support for ``transform`` attributes.
+          Only ``matrix`` transformations are currently supported (#1564, #1564).
+        - [varLib] Added support for building ``VVAR`` table from ``vmtx`` and ``VORG``
+          tables (#1551).
+        - [fontBuilder] Enable making CFF2 fonts with ``post`` table format 2 (#1557).
+        - Fixed ``DeprecationWarning`` on invalid escape sequences (#1562).
+        
+        3.39.0 (released 2019-03-19)
+        ----------------------------
+        
+        - [ttLib/glyf] Raise more specific error when encountering recursive
+          component references (#1545, #1546).
+        - [Doc/designspaceLib] Defined new ``public.skipExportGlyphs`` lib key (#1534,
+          unified-font-object/ufo-spec#84).
+        - [varLib] Use ``vmtx`` to compute vertical phantom points; or ``hhea.ascent``
+          and ``head.unitsPerEM`` if ``vmtx`` is missing (#1528).
+        - [gvar/cvar] Sort XML element's min/value/max attributes in TupleVariation
+          toXML to improve readability of TTX dump (#1527).
+        - [varLib.plot] Added support for 2D plots with only 1 variation axis (#1522).
+        - [designspaceLib] Use axes maps when normalizing locations in
+          DesignSpaceDocument (#1226, #1521), and when finding default source (#1535).
+        - [mutator] Set ``OVERLAP_SIMPLE`` and ``OVERLAP_COMPOUND`` glyf flags by
+          default in ``instantiateVariableFont``. Added ``--no-overlap`` cli option
+          to disable this (#1518).
+        - [subset] Fixed subsetting ``VVAR`` table (#1516, #1517).  
+          Fixed subsetting an ``HVAR`` table that has an ``AdvanceWidthMap`` when the
+          option ``--retain-gids`` is used.
+        - [feaLib] Added ``forceChained`` in MultipleSubstStatement (#1511).  
+          Fixed double indentation of ``subtable`` statement (#1512).  
+          Added support for ``subtable`` statement in more places than just PairPos
+          lookups (#1520).  
+          Handle lookupflag 0 and lookupflag without a value (#1540).
+        - [varLib] In ``load_designspace``, provide a default English name for the
+          ``ital`` axis tag.
+        - Remove pyftinspect because it is unmaintained and bitrotted.
+        
+        3.38.0 (released 2019-02-18)
+        ----------------------------
+        
+        - [cffLib] Fixed RecursionError when unpickling or deepcopying TTFont with
+          CFF table (#1488, 649dc49).
+        - [subset] Fixed AttributeError when using --desubroutinize option (#1490).
+          Also, fixed desubroutinizing bug when subrs contain hints (#1499).
+        - [CPAL] Make Color a subclass of namedtuple (173a0f5).
+        - [feaLib] Allow hyphen in glyph class names.
+        - [feaLib] Added 'tables' option to __main__.py (#1497).
+        - [feaLib] Add support for special-case contextual positioning formatting
+          (#1501).
+        - [svgLib] Support converting SVG basic shapes (rect, circle, etc.) into
+          equivalent SVG paths (#1500, #1508).
+        - [Snippets] Added name-viewer.ipynb Jupyter notebook.
+        
+        
+        3.37.3 (released 2019-02-05)
+        ----------------------------
+        
+        - The previous release accidentally changed several files from Unix to DOS
+          line-endings. Fix that.
+        
+        3.37.2 (released 2019-02-05)
+        ----------------------------
+        
+        - [varLib] Temporarily revert the fix to ``load_masters()``, which caused a
+          crash in ``interpolate_layout()`` when ``deepcopy``-ing OTFs.
+        
+        3.37.1 (released 2019-02-05)
+        ----------------------------
+        
+        - [varLib] ``load_masters()`` now actually assigns the fonts it loads to the
+          source.font attributes.
+        - [varLib] Fixed an MVAR table generation crash when sparse masters were
+          involved.
+        - [voltLib] ``parse_coverage_()`` returns a tuple instead of an ast.Enum.
+        - [feaLib] A MarkClassDefinition inside a block is no longer doubly indented
+          compared to the rest of the block.
+        
+        3.37.0 (released 2019-01-28)
+        ----------------------------
+        
+        - [svgLib] Added support for converting elliptical arcs to cubic bezier curves
+          (#1464).
+        - [py23] Added backport for ``math.isfinite``.
+        - [varLib] Apply HIDDEN flag to fvar axis if designspace axis has attribute
+          ``hidden=1``.
+        - Fixed "DeprecationWarning: invalid escape sequence" in Python 3.7.
+        - [voltLib] Fixed parsing glyph groups. Distinguish different PROCESS_MARKS.
+          Accept COMPONENT glyph type.
+        - [feaLib] Distinguish missing value and explicit ``<NULL>`` for PairPos2
+          format A (#1459). Round-trip ``useExtension`` keyword. Implemented
+          ``ValueRecord.asFea`` method.
+        - [subset] Insert empty widths into hdmx when retaining gids (#1458).
+        
+        3.36.0 (released 2019-01-17)
+        ----------------------------
+        
+        - [ttx] Added ``--no-recalc-timestamp`` option to keep the original font's
+          ``head.modified`` timestamp (#1455, #46).
+        - [ttx/psCharStrings] Fixed issues while dumping and round-tripping CFF2 table
+          with ttx (#1451, #1452, #1456).
+        - [voltLib] Fixed check for duplicate anchors (#1450). Don't try to read past
+          the ``END`` operator in .vtp file (#1453).
+        - [varLib] Use sentinel value -0x8000 (-32768) to ignore post.underlineThickness
+          and post.underlinePosition when generating MVAR deltas (#1449,
+          googlei18n/ufo2ft#308).
+        - [subset] Added ``--retain-gids`` option to subset font without modifying the
+          current glyph indices (#1443, #1447).
+        - [ufoLib] Replace deprecated calls to ``getbytes`` and ``setbytes`` with new
+          equivalent ``readbytes`` and ``writebytes`` calls. ``fs`` >= 2.2 no required.
+        - [varLib] Allow loading masters from TTX files as well (#1441).
+        
+        3.35.2 (released 2019-01-14)
+        ----------------------------
+        
+        - [hmtx/vmtx]: Allow to compile/decompile ``hmtx`` and ``vmtx`` tables even
+          without the corresponding (required) metrics header tables, ``hhea`` and
+          ``vhea`` (#1439).
+        - [varLib] Added support for localized axes' ``labelname`` and named instances'
+          ``stylename`` (#1438).
+        
+        3.35.1 (released 2019-01-09)
+        ----------------------------
+        
+        - [_m_a_x_p] Include ``maxComponentElements`` in ``maxp`` table's recalculation.
+        
+        3.35.0 (released 2019-01-07)
+        ----------------------------
+        
+        - [psCharStrings] In ``encodeFloat`` function, use float's "general format" with
+          8 digits of precision (i.e. ``%8g``) instead of ``str()``. This works around
+          a macOS rendering issue when real numbers in CFF table are too long, and
+          also makes sure that floats are encoded with the same precision in python 2.7
+          and 3.x (#1430, googlei18n/ufo2ft#306).
+        - [_n_a_m_e/fontBuilder] Make ``_n_a_m_e_table.addMultilingualName`` also add
+          Macintosh (platformID=1) names by default. Added options to ``FontBuilder``
+          ``setupNameTable`` method to optionally disable Macintosh or Windows names.
+          (#1359, #1431).
+        - [varLib] Make ``build`` optionally accept a ``DesignSpaceDocument`` object,
+          instead of a designspace file path. The caller can now set the ``font``
+          attribute of designspace's sources to a TTFont object, thus allowing to
+          skip filenames manipulation altogether (#1416, #1425).
+        - [sfnt] Allow SFNTReader objects to be deep-copied.
+        - Require typing>=3.6.4 on py27 to fix issue with singledispatch (#1423).
+        - [designspaceLib/t1Lib/macRes] Fixed some cases where pathlib.Path objects were
+          not accepted (#1421).
+        - [varLib] Fixed merging of multiple PairPosFormat2 subtables (#1411).
+        - [varLib] The default STAT table version is now set to 1.1, to improve
+          compatibility with legacy applications (#1413).
+        
+        3.34.2 (released 2018-12-17)
+        ----------------------------
+        
+        - [merge] Fixed AssertionError when none of the script tables in GPOS/GSUB have
+          a DefaultLangSys record (#1408, 135a4a1).
+        
+        3.34.1 (released 2018-12-17)
+        ----------------------------
+        
+        - [varLib] Work around macOS rendering issue for composites without gvar entry (#1381).
+        
+        3.34.0 (released 2018-12-14)
+        ----------------------------
+        
+        - [varLib] Support generation of CFF2 variable fonts. ``model.reorderMasters()``
+          now supports arbitrary mapping. Fix handling of overlapping ranges for feature
+          variations (#1400).
+        - [cffLib, subset] Code clean-up and fixing related to CFF2 support.
+        - [ttLib.tables.ttProgram] Use raw strings for regex patterns (#1389).
+        - [fontbuilder] Initial support for building CFF2 fonts. Set CFF's
+          ``FontMatrix`` automatically from unitsPerEm.
+        - [plistLib] Accept the more general ``collections.Mapping`` instead of the
+          specific ``dict`` class to support custom data classes that should serialize
+          to dictionaries.
+        
+        3.33.0 (released 2018-11-30)
+        ----------------------------
+        - [subset] subsetter bug fix with variable fonts.
+        - [varLib.featureVar] Improve FeatureVariations generation with many rules.
+        - [varLib] Enable sparse masters when building variable fonts:
+          https://github.com/fonttools/fonttools/pull/1368#issuecomment-437257368
+        - [varLib.mutator] Add IDEF for GETVARIATION opcode, for handling hints in an
+          instance.
+        - [ttLib] Ignore the length of kern table subtable format 0
+        
+        3.32.0 (released 2018-11-01)
+        ----------------------------
+        
+        - [ufoLib] Make ``UFOWriter`` a subclass of ``UFOReader``, and use mixins
+          for shared methods (#1344).
+        - [featureVars] Fixed normalization error when a condition's minimum/maximum
+          attributes are missing in designspace ``<rule>`` (#1366).
+        - [setup.py] Added ``[plot]`` to extras, to optionally install ``matplotlib``,
+          needed to use the ``fonTools.varLib.plot`` module.
+        - [varLib] Take total bounding box into account when resolving model (7ee81c8).
+          If multiple axes have the same range ratio, cut across both (62003f4).
+        - [subset] Don't error if ``STAT`` has no ``AxisValue`` tables.
+        - [fontBuilder] Added a new submodule which contains a ``FontBuilder`` wrapper
+          class around ``TTFont`` that makes it easier to create a working TTF or OTF
+          font from scratch with code. NOTE: the API is still experimental and may
+          change in future versions.
+        
+        3.31.0 (released 2018-10-21)
+        ----------------------------
+        
+        - [ufoLib] Merged the `ufoLib <https://github.com/unified-font-objects/ufoLib>`__
+          master branch into a new ``fontTools.ufoLib`` package (#1335, #1095).
+          Moved ``ufoLib.pointPen`` module to ``fontTools.pens.pointPen``.
+          Moved ``ufoLib.etree`` module to ``fontTools.misc.etree``.
+          Moved ``ufoLib.plistlib`` module to ``fontTools.misc.plistlib``.
+          To use the new ``fontTools.ufoLib`` module you need to install fonttools
+          with the ``[ufo]`` extra, or you can manually install the required additional
+          dependencies (cf. README.rst).
+        - [morx] Support AAT action type to insert glyphs and clean up compilation
+          of AAT action tables (4a1871f, 2011ccf).
+        - [subset] The ``--no-hinting`` on a CFF font now also drops the optional
+          hinting keys in Private dict: ``ForceBold``, ``LanguageGroup``, and
+          ``ExpansionFactor`` (#1322).
+        - [subset] Include nameIDs referenced by STAT table (#1327).
+        - [loggingTools] Added ``msg=None`` argument to
+          ``CapturingLogHandler.assertRegex`` (0245f2c).
+        - [varLib.mutator] Implemented ``FeatureVariations`` instantiation (#1244).
+        - [g_l_y_f] Added PointPen support to ``_TTGlyph`` objects (#1334).
+        
+        3.30.0 (released 2018-09-18)
+        ----------------------------
+        
+        - [feaLib] Skip building noop class PairPos subtables when Coverage is NULL
+          (#1318).
+        - [ttx] Expose the previously reserved bit flag ``OVERLAP_SIMPLE`` of
+          glyf table's contour points in the TTX dump. This is used in some
+          implementations to specify a non-zero fill with overlapping contours (#1316).
+        - [ttLib] Added support for decompiling/compiling ``TS1C`` tables containing
+          VTT sources for ``cvar`` variation table (#1310).
+        - [varLib] Use ``fontTools.designspaceLib`` to read DesignSpaceDocument. The
+          ``fontTools.varLib.designspace`` module is now deprecated and will be removed
+          in future versions. The presence of an explicit ``axes`` element is now
+          required in order to build a variable font (#1224, #1313).
+        - [varLib] Implemented building GSUB FeatureVariations table from the ``rules``
+          element of DesignSpace document (#1240, #713, #1314).
+        - [subset] Added ``--no-layout-closure`` option to not expand the subset with
+          the glyphs produced by OpenType layout features. Instead, OpenType features
+          will be subset to only rules that are relevant to the otherwise-specified
+          glyph set (#43, #1121).
+        
+        3.29.1 (released 2018-09-10)
+        ----------------------------
+        
+        - [feaLib] Fixed issue whereby lookups from DFLT/dflt were not included in the
+          DFLT/non-dflt language systems (#1307).
+        - [graphite] Fixed issue on big-endian architectures (e.g. ppc64) (#1311).
+        - [subset] Added ``--layout-scripts`` option to add/exclude set of OpenType
+          layout scripts that will be preserved. By default all scripts are retained
+          (``'*'``) (#1303).
+        
+        3.29.0 (released 2018-07-26)
+        ----------------------------
+        
+        - [feaLib] In the OTL table builder, when the ``name`` table is excluded
+          from the list of tables to be build, skip compiling ``featureNames`` blocks,
+          as the records referenced in ``FeatureParams`` table don't exist (68951b7).
+        - [otBase] Try ``ExtensionLookup`` if other offset-overflow methods fail
+          (05f95f0).
+        - [feaLib] Added support for explicit ``subtable;`` break statements in
+          PairPos lookups; previously these were ignored (#1279, #1300, #1302).
+        - [cffLib.specializer] Make sure the stack depth does not exceed maxstack - 1,
+          so that a subroutinizer can insert subroutine calls (#1301,
+          https://github.com/googlei18n/ufo2ft/issues/266).
+        - [otTables] Added support for fixing offset overflow errors occurring inside
+          ``MarkBasePos`` subtables (#1297).
+        - [subset] Write the default output file extension based on ``--flavor`` option,
+          or the value of ``TTFont.sfntVersion`` (d7ac0ad).
+        - [unicodedata] Updated Blocks, Scripts and ScriptExtensions for Unicode 11
+          (452c85e).
+        - [xmlWriter] Added context manager to XMLWriter class to autoclose file
+          descriptor on exit (#1290).
+        - [psCharStrings] Optimize the charstring's bytecode by encoding as integers
+          all float values that have no decimal portion (8d7774a).
+        - [ttFont] Fixed missing import of ``TTLibError`` exception (#1285).
+        - [feaLib] Allow any languages other than ``dflt`` under ``DFLT`` script
+          (#1278, #1292).
+        
+        3.28.0 (released 2018-06-19)
+        ----------------------------
+        
+        - [featureVars] Added experimental module to build ``FeatureVariations``
+          tables. Still needs to be hooked up to ``varLib.build`` (#1240).
+        - [fixedTools] Added ``otRound`` to round floats to nearest integer towards
+          positive Infinity. This is now used where we deal with visual data like X/Y
+          coordinates, advance widths/heights, variation deltas, and similar (#1274,
+          #1248).
+        - [subset] Improved GSUB closure memoize algorithm.
+        - [varLib.models] Fixed regression in model resolution (180124, #1269).
+        - [feaLib.ast] Fixed error when converting ``SubtableStatement`` to string
+          (#1275).
+        - [varLib.mutator] Set ``OS/2.usWeightClass`` and ``usWidthClass``, and
+          ``post.italicAngle`` based on the 'wght', 'wdth' and 'slnt' axis values
+          (#1276, #1264).
+        - [py23/loggingTools] Don't automatically set ``logging.lastResort`` handler
+          on py27. Moved ``LastResortLogger`` to the ``loggingTools`` module (#1277).
+        
+        3.27.1 (released 2018-06-11)
+        ----------------------------
+        
+        - [ttGlyphPen] Issue a warning and skip building non-existing components
+          (https://github.com/googlei18n/fontmake/issues/411).
+        - [tests] Fixed issue running ttx_test.py from a tagged commit.
+        
+        3.27.0 (released 2018-06-11)
+        ----------------------------
+        
+        - [designspaceLib] Added new ``conditionSet`` element to ``rule`` element in
+          designspace document. Bumped ``format`` attribute to ``4.0`` (previously,
+          it was formatted as an integer). Removed ``checkDefault``, ``checkAxes``
+          methods, and any kind of guessing about the axes when the ``<axes>`` element
+          is missing. The default master is expected at the intersection of all default
+          values for each axis (#1254, #1255, #1267).
+        - [cffLib] Fixed issues when compiling CFF2 or converting from CFF when the
+          font has an FDArray (#1211, #1271).
+        - [varLib] Avoid attempting to build ``cvar`` table when ``glyf`` table is not
+          present, as is the case for CFF2 fonts.
+        - [subset] Handle None coverages in MarkGlyphSets; revert commit 02616ab that
+          sets empty Coverage tables in MarkGlyphSets to None, to make OTS happy.
+        - [ttFont] Allow to build glyph order from ``maxp.numGlyphs`` when ``post`` or
+          ``cmap`` are missing.
+        - [ttFont] Added ``__len__`` method to ``_TTGlyphSet``.
+        - [glyf] Ensure ``GlyphCoordinates`` never overflow signed shorts (#1230).
+        - [py23] Added alias for ``itertools.izip`` shadowing the built-in ``zip``.
+        - [loggingTools] Memoize ``log`` property of ``LogMixin`` class (fbab12).
+        - [ttx] Impoved test coverage (#1261).
+        - [Snippets] Addded script to append a suffix to all family names in a font.
+        - [varLib.plot] Make it work with matplotlib >= 2.1 (b38e2b).
+        
+        3.26.0 (released 2018-05-03)
+        ----------------------------
+        
+        - [designspace] Added a new optional ``layer`` attribute to the source element,
+          and a corresponding ``layerName`` attribute to the ``SourceDescriptor``
+          object (#1253).
+          Added ``conditionset`` element to the ``rule`` element to the spec, but not
+          implemented in designspace reader/writer yet (#1254).
+        - [varLib.models] Refine modeling one last time (0ecf5c5).
+        - [otBase] Fixed sharing of tables referred to by different offset sizes
+          (795f2f9).
+        - [subset] Don't drop a GDEF that only has VarStore (fc819d6). Set to None
+          empty Coverage tables in MarkGlyphSets (02616ab).
+        - [varLib]: Added ``--master-finder`` command-line option (#1249).
+        - [varLib.mutator] Prune fvar nameIDs from instance's name table (#1245).
+        - [otTables] Allow decompiling bad ClassDef tables with invalid format, with
+          warning (#1236).
+        - [varLib] Make STAT v1.2 and reuse nameIDs from fvar table (#1242).
+        - [varLib.plot] Show master locations. Set axis limits to -1, +1.
+        - [subset] Handle HVAR direct mapping. Passthrough 'cvar'.
+          Added ``--font-number`` command-line option for collections.
+        - [t1Lib] Allow a text encoding to be specified when parsing a Type 1 font
+          (#1234). Added ``kind`` argument to T1Font constructor (c5c161c).
+        - [ttLib] Added context manager API to ``TTFont`` class, so it can be used in
+          ``with`` statements to auto-close the file when exiting the context (#1232).
+        
+        3.25.0 (released 2018-04-03)
+        ----------------------------
+        
+        - [varLib] Improved support-resolution algorithm. Previously, the on-axis
+          masters would always cut the space. They don't anymore. That's more
+          consistent, and fixes the main issue Erik showed at TYPO Labs 2017.
+          Any varfont built that had an unusual master configuration will change
+          when rebuilt (42bef17, a523a697,
+          https://github.com/googlei18n/fontmake/issues/264).
+        - [varLib.models] Added a ``main()`` entry point, that takes positions and
+          prints model results.
+        - [varLib.plot] Added new module to plot a designspace's
+          VariationModel. Requires ``matplotlib``.
+        - [varLib.mutator] Added -o option to specify output file path (2ef60fa).
+        - [otTables] Fixed IndexError while pruning of HVAR pre-write (6b6c34a).
+        - [varLib.models] Convert delta array to floats if values overflows signed
+          short integer (0055f94).
+        
+        3.24.2 (released 2018-03-26)
+        ----------------------------
+        
+        - [otBase] Don't fail during ``ValueRecord`` copy if src has more items.
+          We drop hinting in the subsetter by simply changing ValueFormat, without
+          cleaning up the actual ValueRecords. This was causing assertion error if
+          a variable font was subsetted without hinting and then passed directly to
+          the mutator for instantiation without first it saving to disk.
+        
+        3.24.1 (released 2018-03-06)
+        ----------------------------
+        
+        - [varLib] Don't remap the same ``DeviceTable`` twice in VarStore optimizer
+          (#1206).
+        - [varLib] Add ``--disable-iup`` option to ``fonttools varLib`` script,
+          and a ``optimize=True`` keyword argument to ``varLib.build`` function,
+          to optionally disable IUP optimization while building varfonts.
+        - [ttCollection] Fixed issue while decompiling ttc with python3 (#1207).
+        
+        3.24.0 (released 2018-03-01)
+        ----------------------------
+        
+        - [ttGlyphPen] Decompose composite glyphs if any components' transform is too
+          large to fit a ``F2Dot14`` value, or clamp transform values that are
+          (almost) equal to +2.0 to make them fit and avoid decomposing (#1200,
+          #1204, #1205).
+        - [ttx] Added new ``-g`` option to dump glyphs from the ``glyf`` table
+          splitted as individual ttx files (#153, #1035, #1132, #1202).
+        - Copied ``ufoLib.filenames`` module to ``fontTools.misc.filenames``, used
+          for the ttx split-glyphs option (#1202).
+        - [feaLib] Added support for ``cvParameters`` blocks in Character Variant
+          feautures ``cv01-cv99`` (#860, #1169).
+        - [Snippets] Added ``checksum.py`` script to generate/check SHA1 hash of
+          ttx files (#1197).
+        - [varLib.mutator] Fixed issue while instantiating some variable fonts
+          whereby the horizontal advance width computed from ``gvar`` phantom points
+          could turn up to be negative (#1198).
+        - [varLib/subset] Fixed issue with subsetting GPOS variation data not
+          picking up ``ValueRecord`` ``Device`` objects (54fd71f).
+        - [feaLib/voltLib] In all AST elements, the ``location`` is no longer a
+          required positional argument, but an optional kewyord argument (defaults
+          to ``None``). This will make it easier to construct feature AST from
+          code (#1201).
+        
+        
+        3.23.0 (released 2018-02-26)
+        ----------------------------
+        
+        - [designspaceLib] Added an optional ``lib`` element to the designspace as a
+          whole, as well as to the instance elements, to store arbitrary data in a
+          property list dictionary, similar to the UFO's ``lib``. Added an optional
+          ``font`` attribute to the ``SourceDescriptor``, to allow operating on
+          in-memory font objects (#1175).
+        - [cffLib] Fixed issue with lazy-loading of attributes when attempting to
+          set the CFF TopDict.Encoding (#1177, #1187).
+        - [ttx] Fixed regression introduced in 3.22.0 that affected the split tables
+          ``-s`` option (#1188).
+        - [feaLib] Added ``IncludedFeaNotFound`` custom exception subclass, raised
+          when an included feature file cannot be found (#1186).
+        - [otTables] Changed ``VarIdxMap`` to use glyph names internally instead of
+          glyph indexes. The old ttx dumps of HVAR/VVAR tables that contain indexes
+          can still be imported (21cbab8, 38a0ffb).
+        - [varLib] Implemented VarStore optimizer (#1184).
+        - [subset] Implemented pruning of GDEF VarStore, HVAR and MVAR (#1179).
+        - [sfnt] Restore backward compatiblity with ``numFonts`` attribute of
+          ``SFNTReader`` object (#1181).
+        - [merge] Initial support for merging ``LangSysRecords`` (#1180).
+        - [ttCollection] don't seek(0) when writing to possibly unseekable strems.
+        - [subset] Keep all ``--name-IDs`` from 0 to 6 by default (#1170, #605, #114).
+        - [cffLib] Added ``width`` module to calculate optimal CFF default and
+          nominal glyph widths.
+        - [varLib] Don’t fail if STAT already in the master fonts (#1166).
+        
+        3.22.0 (released 2018-02-04)
+        ----------------------------
+        
+        - [subset] Support subsetting ``endchar`` acting as ``seac``-like components
+          in ``CFF`` (fixes #1162).
+        - [feaLib] Allow to build from pre-parsed ``ast.FeatureFile`` object.
+          Added ``tables`` argument to only build some tables instead of all (#1159,
+          #1163).
+        - [textTools] Replaced ``safeEval`` with ``ast.literal_eval`` (#1139).
+        - [feaLib] Added option to the parser to not resolve ``include`` statements
+          (#1154).
+        - [ttLib] Added new ``ttCollection`` module to read/write TrueType and
+          OpenType Collections. Exports a ``TTCollection`` class with a ``fonts``
+          attribute containing a list of ``TTFont`` instances, the methods ``save``
+          and ``saveXML``, plus some list-like methods. The ``importXML`` method is
+          not implemented yet (#17).
+        - [unicodeadata] Added ``ot_tag_to_script`` function that converts from
+          OpenType script tag to Unicode script code.
+        - Added new ``designspaceLib`` subpackage, originally from Erik Van Blokland's
+          ``designSpaceDocument``: https://github.com/LettError/designSpaceDocument
+          NOTE: this is not yet used internally by varLib, and the API may be subject
+          to changes (#911, #1110, LettError/designSpaceDocument#28).
+        - Added new FontTools icon images (8ee7c32).
+        - [unicodedata] Added ``script_horizontal_direction`` function that returns
+          either "LTR" or "RTL" given a unicode script code.
+        - [otConverters] Don't write descriptive name string as XML comment if the
+          NameID value is 0 (== NULL) (#1151, #1152).
+        - [unicodedata] Add ``ot_tags_from_script`` function to get the list of
+          OpenType script tags associated with unicode script code (#1150).
+        - [feaLib] Don't error when "enumerated" kern pairs conflict with preceding
+          single pairs; emit warning and chose the first value (#1147, #1148).
+        - [loggingTools] In ``CapturingLogHandler.assertRegex`` method, match the
+          fully formatted log message.
+        - [sbix] Fixed TypeError when concatenating str and bytes (#1154).
+        - [bezierTools] Implemented cusp support and removed ``approximate_fallback``
+          arg in ``calcQuadraticArcLength``. Added ``calcCubicArcLength`` (#1142).
+        
+        3.21.2 (released 2018-01-08)
+        ----------------------------
+        
+        - [varLib] Fixed merging PairPos Format1/2 with missing subtables (#1125).
+        
+        3.21.1 (released 2018-01-03)
+        ----------------------------
+        
+        - [feaLib] Allow mixed single/multiple substitutions (#612)
+        - Added missing ``*.afm`` test assets to MAINFEST.in (#1137).
+        - Fixed dumping ``SVG`` tables containing color palettes (#1124).
+        
+        3.21.0 (released 2017-12-18)
+        ----------------------------
+        
+        - [cmap] when compiling format6 subtable, don't assume gid0 is always called
+          '.notdef' (1e42224).
+        - [ot] Allow decompiling fonts with bad Coverage format number (1aafae8).
+        - Change FontTools licence to MIT (#1127).
+        - [post] Prune extra names already in standard Mac set (df1e8c7).
+        - [subset] Delete empty SubrsIndex after subsetting (#994, #1118).
+        - [varLib] Don't share points in cvar by default, as it currently fails on
+          some browsers (#1113).
+        - [afmLib] Make poor old afmLib work on python3.
+        
+        3.20.1 (released 2017-11-22)
+        ----------------------------
+        
+        - [unicodedata] Fixed issue with ``script`` and ``script_extension`` functions
+          returning inconsistent short vs long names. They both return the short four-
+          letter script codes now. Added ``script_name`` and ``script_code`` functions
+          to look up the long human-readable script name from the script code, and
+          viceversa (#1109, #1111).
+        
+        3.20.0 (released 2017-11-21)
+        ----------------------------
+        
+        - [unicodedata] Addded new module ``fontTools.unicodedata`` which exports the
+          same interface as the built-in ``unicodedata`` module, with the addition of
+          a few functions that are missing from the latter, such as ``script``,
+          ``script_extension`` and ``block``. Added a ``MetaTools/buildUCD.py`` script
+          to download and parse data files from the Unicode Character Database and
+          generate python modules containing lists of ranges and property values.
+        - [feaLib] Added ``__str__`` method to all ``ast`` elements (delegates to the
+          ``asFea`` method).
+        - [feaLib] ``Parser`` constructor now accepts a ``glyphNames`` iterable
+          instead of ``glyphMap`` dict. The latter still works but with a pending
+          deprecation warning (#1104).
+        - [bezierTools] Added arc length calculation functions originally from
+          ``pens.perimeterPen`` module (#1101).
+        - [varLib] Started generating STAT table (8af4309). Right now it just reflects
+          the axes, and even that with certain limitations:
+          * AxisOrdering is set to the order axes are defined,
+          * Name-table entries are not shared with fvar.
+        - [py23] Added backports for ``redirect_stdout`` and ``redirect_stderr``
+          context managers (#1097).
+        - [Graphite] Fixed some round-trip bugs (#1093).
+        
+        3.19.0 (released 2017-11-06)
+        ----------------------------
+        
+        - [varLib] Try set of used points instead of all points when testing whether to
+          share points between tuples (#1090).
+        - [CFF2] Fixed issue with reading/writing PrivateDict BlueValues to TTX file.
+          Read the commit message 8b02b5a and issue #1030 for more details.
+          NOTE: this change invalidates all the TTX files containing CFF2 tables
+          that where dumped with previous verisons of fonttools.
+          CFF2 Subr items can have values on the stack after the last operator, thus
+          a ``CFF2Subr`` class was added to accommodate this (#1091).
+        - [_k_e_r_n] Fixed compilation of AAT kern version=1.0 tables (#1089, #1094)
+        - [ttLib] Added getBestCmap() convenience method to TTFont class and cmap table
+          class that returns a preferred Unicode cmap subtable given a list of options
+          (#1092).
+        - [morx] Emit more meaningful subtable flags. Implement InsertionMorphAction
+        
+        3.18.0 (released 2017-10-30)
+        ----------------------------
+        
+        - [feaLib] Fixed writing back nested glyph classes (#1086).
+        - [TupleVariation] Reactivated shared points logic, bugfixes (#1009).
+        - [AAT] Implemented ``morx`` ligature subtables (#1082).
+        - [reverseContourPen] Keep duplicate lineTo following a moveTo (#1080,
+          https://github.com/googlei18n/cu2qu/issues/51).
+        - [varLib.mutator] Suport instantiation of GPOS, GDEF and MVAR (#1079).
+        - [sstruct] Fixed issue with ``unicode_literals`` and ``struct`` module in
+          old versions of python 2.7 (#993).
+        
+        3.17.0 (released 2017-10-16)
+        ----------------------------
+        
+        - [svgPathPen] Added an ``SVGPathPen`` that translates segment pen commands
+          into SVG path descriptions. Copied from Tal Leming's ``ufo2svg.svgPathPen``
+          https://github.com/typesupply/ufo2svg/blob/d69f992/Lib/ufo2svg/svgPathPen.py
+        - [reverseContourPen] Added ``ReverseContourPen``, a filter pen that draws
+          contours with the winding direction reversed, while keeping the starting
+          point (#1071).
+        - [filterPen] Added ``ContourFilterPen`` to manipulate contours as a whole
+          rather than segment by segment.
+        - [arrayTools] Added ``Vector`` class to apply math operations on an array
+          of numbers, and ``pairwise`` function to loop over pairs of items in an
+          iterable.
+        - [varLib] Added support for building and interpolation of ``cvar`` table
+          (f874cf6, a25a401).
+        
+        3.16.0 (released 2017-10-03)
+        ----------------------------
+        
+        - [head] Try using ``SOURCE_DATE_EPOCH`` environment variable when setting
+          the ``head`` modified timestamp to ensure reproducible builds (#1063).
+          See https://reproducible-builds.org/specs/source-date-epoch/
+        - [VTT] Decode VTT's ``TSI*`` tables text as UTF-8 (#1060).
+        - Added support for Graphite font tables: Feat, Glat, Gloc, Silf and Sill.
+          Thanks @mhosken! (#1054).
+        - [varLib] Default to using axis "name" attribute if "labelname" element
+          is missing (588f524).
+        - [merge] Added support for merging Script records. Remove unused features
+          and lookups after merge (d802580, 556508b).
+        - Added ``fontTools.svgLib`` package. Includes a parser for SVG Paths that
+          supports the Pen protocol (#1051). Also, added a snippet to convert SVG
+          outlines to UFO GLIF (#1053).
+        - [AAT] Added support for ``ankr``, ``bsln``, ``mort``, ``morx``, ``gcid``,
+          and ``cidg``.
+        - [subset] Implemented subsetting of ``prop``, ``opbd``, ``bsln``, ``lcar``.
+        
+        3.15.1 (released 2017-08-18)
+        ----------------------------
+        
+        - [otConverters] Implemented ``__add__`` and ``__radd__`` methods on
+          ``otConverters._LazyList`` that decompile a lazy list before adding
+          it to another list or ``_LazyList`` instance. Fixes an ``AttributeError``
+          in the ``subset`` module when attempting to sum ``_LazyList`` objects
+          (6ef48bd2, 1aef1683).
+        - [AAT] Support the `opbd` table with optical bounds (a47f6588).
+        - [AAT] Support `prop` table with glyph properties (d05617b4).
+        
+        
+        3.15.0 (released 2017-08-17)
+        ----------------------------
+        
+        - [AAT] Added support for AAT lookups. The ``lcar`` table can be decompiled
+          and recompiled; futher work needed to handle ``morx`` table (#1025).
+        - [subset] Keep (empty) DefaultLangSys for Script 'DFLT' (6eb807b5).
+        - [subset] Support GSUB/GPOS.FeatureVariations (fe01d87b).
+        - [varLib] In ``models.supportScalars``, ignore an axis when its peak value
+          is 0 (fixes #1020).
+        - [varLib] Add default mappings to all axes in avar to fix rendering issue
+          in some rasterizers (19c4b377, 04eacf13).
+        - [varLib] Flatten multiple tail PairPosFormat2 subtables before merging
+          (c55ef525).
+        - [ttLib] Added support for recalculating font bounding box in ``CFF`` and
+          ``head`` tables, and min/max values in ``hhea`` and ``vhea`` tables (#970).
+        
+        3.14.0 (released 2017-07-31)
+        ----------------------------
+        
+        - [varLib.merger] Remove Extensions subtables before merging (f7c20cf8).
+        - [varLib] Initialize the avar segment map with required default entries
+          (#1014).
+        - [varLib] Implemented optimal IUP optmiziation (#1019).
+        - [otData] Add ``AxisValueFormat4`` for STAT table v1.2 from OT v1.8.2
+          (#1015).
+        - [name] Fixed BCP46 language tag for Mac langID=9: 'si' -> 'sl'.
+        - [subset] Return value from ``_DehintingT2Decompiler.op_hintmask``
+          (c0d672ba).
+        - [cffLib] Allow to get TopDict by index as well as by name (dca96c9c).
+        - [cffLib] Removed global ``isCFF2`` state; use one set of classes for
+          both CFF and CFF2, maintaining backward compatibility existing code (#1007).
+        - [cffLib] Deprecated maxstack operator, per OpenType spec update 1.8.1.
+        - [cffLib] Added missing default (-100) for UnderlinePosition (#983).
+        - [feaLib] Enable setting nameIDs greater than 255 (#1003).
+        - [varLib] Recalculate ValueFormat when merging SinglePos (#996).
+        - [varLib] Do not emit MVAR if there are no entries in the variation store
+          (#987).
+        - [ttx] For ``-x`` option, pad with space if table tag length is < 4.
+        
+        3.13.1 (released 2017-05-30)
+        ----------------------------
+        
+        - [feaLib.builder] Removed duplicate lookups optimization. The original
+          lookup order and semantics of the feature file are preserved (#976).
+        
+        3.13.0 (released 2017-05-24)
+        ----------------------------
+        
+        - [varLib.mutator] Implement IUP optimization (#969).
+        - [_g_l_y_f.GlyphCoordinates] Changed ``__bool__()`` semantics to match those
+          of other iterables (e46f949). Removed ``__abs__()`` (3db5be2).
+        - [varLib.interpolate_layout] Added ``mapped`` keyword argument to
+          ``interpolate_layout`` to allow disabling avar mapping: if False (default),
+          the location is mapped using the map element of the axes in designspace file;
+          if True, it is assumed that location is in designspace's internal space and
+          no mapping is performed (#950, #975).
+        - [varLib.interpolate_layout] Import designspace-loading logic from varLib.
+        - [varLib] Fixed bug with recombining PairPosClass2 subtables (81498e5, #914).
+        - [cffLib.specializer] When copying iterables, cast to list (462b7f86).
+        
+        3.12.1 (released 2017-05-18)
+        ----------------------------
+        
+        - [pens.t2CharStringPen] Fixed AttributeError when calling addComponent in
+          T2CharStringPen (#965).
+        
+        3.12.0 (released 2017-05-17)
+        ----------------------------
+        
+        - [cffLib.specializer] Added new ``specializer`` module to optimize CFF
+          charstrings, used by the T2CharStringPen (#948).
+        - [varLib.mutator] Sort glyphs by component depth before calculating composite
+          glyphs' bounding boxes to ensure deltas are correctly caclulated (#945).
+        - [_g_l_y_f] Fixed loss of precision in GlyphCoordinates by using 'd' (double)
+          instead of 'f' (float) as ``array.array`` typecode (#963, #964).
+        
+        3.11.0 (released 2017-05-03)
+        ----------------------------
+        
+        - [t2CharStringPen] Initial support for specialized Type2 path operators:
+          vmoveto, hmoveto, vlineto, hlineto, vvcurveto, hhcurveto, vhcurveto and
+          hvcurveto. This should produce more compact charstrings (#940, #403).
+        - [Doc] Added Sphinx sources for the documentation. Thanks @gferreira (#935).
+        - [fvar] Expose flags in XML (#932)
+        - [name] Add helper function for building multi-lingual names (#921)
+        - [varLib] Fixed kern merging when a PairPosFormat2 has ClassDef1 with glyphs
+          that are NOT present in the Coverage (1b5e1c4, #939).
+        - [varLib] Fixed non-deterministic ClassDef order with PY3 (f056c12, #927).
+        - [feLib] Throw an error when the same glyph is defined in multiple mark
+          classes within the same lookup (3e3ff00, #453).
+        
+        3.10.0 (released 2017-04-14)
+        ----------------------------
+        
+        - [varLib] Added support for building ``avar`` table, using the designspace
+          ``<map>`` elements.
+        - [varLib] Removed unused ``build(..., axisMap)`` argument. Axis map should
+          be specified in designspace file now. We do not accept nonstandard axes
+          if ``<axes>`` element is not present.
+        - [varLib] Removed "custom" axis from the ``standard_axis_map``. This was
+          added before when glyphsLib was always exporting the (unused) custom axis.
+        - [varLib] Added partial support for building ``MVAR`` table; does not
+          implement ``gasp`` table variations yet.
+        - [pens] Added FilterPen base class, for pens that control another pen;
+          factored out ``addComponent`` method from BasePen into a separate abstract
+          DecomposingPen class; added DecomposingRecordingPen, which records
+          components decomposed as regular contours.
+        - [TSI1] Fixed computation of the textLength of VTT private tables (#913).
+        - [loggingTools] Added ``LogMixin`` class providing a ``log`` property to
+          subclasses, which returns a ``logging.Logger`` named after the latter.
+        - [loggingTools] Added ``assertRegex`` method to ``CapturingLogHandler``.
+        - [py23] Added backport for python 3's ``types.SimpleNamespace`` class.
+        - [EBLC] Fixed issue with python 3 ``zip`` iterator.
+        
+        3.9.2 (released 2017-04-08)
+        ---------------------------
+        
+        - [pens] Added pen to draw glyphs using WxPython ``GraphicsPath`` class:
+          https://wxpython.org/docs/api/wx.GraphicsPath-class.html
+        - [varLib.merger] Fixed issue with recombining multiple PairPosFormat2
+          subtables (#888)
+        - [varLib] Do not encode gvar deltas that are all zeroes, or if all values
+          are smaller than tolerance.
+        - [ttLib] _TTGlyphSet glyphs now also have ``height`` and ``tsb`` (top
+          side bearing) attributes from the ``vmtx`` table, if present.
+        - [glyf] In ``GlyphCoordintes`` class, added ``__bool__`` / ``__nonzero__``
+          methods, and ``array`` property to get raw array.
+        - [ttx] Support reading TTX files with BOM (#896)
+        - [CFF2] Fixed the reporting of the number of regions in the font.
+        
+        3.9.1 (released 2017-03-20)
+        ---------------------------
+        
+        - [varLib.merger] Fixed issue while recombining multiple PairPosFormat2
+          subtables if they were split because of offset overflows (9798c30).
+        - [varLib.merger] Only merge multiple PairPosFormat1 subtables if there is
+          at least one of the fonts with a non-empty Format1 subtable (0f5a46b).
+        - [varLib.merger] Fixed IndexError with empty ClassDef1 in PairPosFormat2
+          (aad0d46).
+        - [varLib.merger] Avoid reusing Class2Record (mutable) objects (e6125b3).
+        - [varLib.merger] Calculate ClassDef1 and ClassDef2's Format when merging
+          PairPosFormat2 (23511fd).
+        - [macUtils] Added missing ttLib import (b05f203).
+        
+        3.9.0 (released 2017-03-13)
+        ---------------------------
+        
+        - [feaLib] Added (partial) support for parsing feature file comments ``# ...``
+          appearing in between statements (#879).
+        - [feaLib] Cleaned up syntax tree for FeatureNames.
+        - [ttLib] Added support for reading/writing ``CFF2`` table (thanks to
+          @readroberts at Adobe), and ``TTFA`` (ttfautohint) table.
+        - [varLib] Fixed regression introduced with 3.8.0 in the calculation of
+          ``NumShorts``, i.e. the number of deltas in ItemVariationData's delta sets
+          that use a 16-bit representation (b2825ff).
+        
+        3.8.0 (released 2017-03-05)
+        ---------------------------
+        
+        - New pens: MomentsPen, StatisticsPen, RecordingPen, and TeePen.
+        - [misc] Added new ``fontTools.misc.symfont`` module, for symbolic font
+          statistical analysis; requires ``sympy`` (http://www.sympy.org/en/index.html)
+        - [varLib] Added experimental ``fontTools.varLib.interpolatable`` module for
+          finding wrong contour order between different masters
+        - [varLib] designspace.load() now returns a dictionary, instead of a tuple,
+          and supports <axes> element (#864); the 'masters' item was renamed 'sources',
+          like the <sources> element in the designspace document
+        - [ttLib] Fixed issue with recalculating ``head`` modified timestamp when
+          saving CFF fonts
+        - [ttLib] In TupleVariation, round deltas before compiling (#861, fixed #592)
+        - [feaLib] Ignore duplicate glyphs in classes used as MarkFilteringSet and
+          MarkAttachmentType (#863)
+        - [merge] Changed the ``gasp`` table merge logic so that only the one from
+          the first font is retained, similar to other hinting tables (#862)
+        - [Tests] Added tests for the ``varLib`` package, as well as test fonts
+          from the "Annotated OpenType Specification" (AOTS) to exercise ``ttLib``'s
+          table readers/writers (<https://github.com/adobe-type-tools/aots>)
+        
+        3.7.2 (released 2017-02-17)
+        ---------------------------
+        
+        - [subset] Keep advance widths when stripping ".notdef" glyph outline in
+          CID-keyed CFF fonts (#845)
+        - [feaLib] Zero values now produce the same results as makeotf (#633, #848)
+        - [feaLib] More compact encoding for “Contextual positioning with in-line
+          single positioning rules” (#514)
+        
+        3.7.1 (released 2017-02-15)
+        ---------------------------
+        
+        - [subset] Fixed issue with ``--no-hinting`` option whereby advance widths in
+          Type 2 charstrings were also being stripped (#709, #343)
+        - [feaLib] include statements now resolve relative paths like makeotf (#838)
+        - [feaLib] table ``name`` now handles Unicode codepoints beyond the Basic
+          Multilingual Plane, also supports old-style MacOS platform encodings (#842)
+        - [feaLib] correctly escape string literals when emitting feature syntax (#780)
+        
+        3.7.0 (released 2017-02-11)
+        ---------------------------
+        
+        - [ttx, mtiLib] Preserve ordering of glyph alternates in GSUB type 3 (#833).
+        - [feaLib] Glyph names can have dashes, as per new AFDKO syntax v1.20 (#559).
+        - [feaLib] feaLib.Parser now needs the font's glyph map for parsing.
+        - [varLib] Fix regression where GPOS values were stored as 0.
+        - [varLib] Allow merging of class-based kerning when ClassDefs are different
+        
+        3.6.3 (released 2017-02-06)
+        ---------------------------
+        
+        - [varLib] Fix building variation of PairPosFormat2 (b5c34ce).
+        - Populate defaults even for otTables that have postRead (e45297b).
+        - Fix compiling of MultipleSubstFormat1 with zero 'out' glyphs (b887860).
+        
+        3.6.2 (released 2017-01-30)
+        ---------------------------
+        
+        - [varLib.merger] Fixed "TypeError: reduce() of empty sequence with no
+          initial value" (3717dc6).
+        
+        3.6.1 (released 2017-01-28)
+        ---------------------------
+        
+        -  [py23] Fixed unhandled exception occurring at interpreter shutdown in
+           the "last resort" logging handler (972b3e6).
+        -  [agl] Ensure all glyph names are of native 'str' type; avoid mixing
+           'str' and 'unicode' in TTFont.glyphOrder (d8c4058).
+        -  Fixed inconsistent title levels in README.rst that caused PyPI to
+           incorrectly render the reStructuredText page.
+        
+        3.6.0 (released 2017-01-26)
+        ---------------------------
+        
+        -  [varLib] Refactored and improved the variation-font-building process.
+        -  Assembly code in the fpgm, prep, and glyf tables is now indented in
+           XML output for improved readability. The ``instruction`` element is
+           written as a simple tag if empty (#819).
+        -  [ttx] Fixed 'I/O operation on closed file' error when dumping
+           multiple TTXs to standard output with the '-o -' option.
+        -  The unit test modules (``*_test.py``) have been moved outside of the
+           fontTools package to the Tests folder, thus they are no longer
+           installed (#811).
+        
+        3.5.0 (released 2017-01-14)
+        ---------------------------
+        
+        -  Font tables read from XML can now be written back to XML with no
+           loss.
+        -  GSUB/GPOS LookupType is written out in XML as an element, not
+           comment. (#792)
+        -  When parsing cmap table, do not store items mapped to glyph id 0.
+           (#790)
+        -  [otlLib] Make ClassDef sorting deterministic. Fixes #766 (7d1ddb2)
+        -  [mtiLib] Added unit tests (#787)
+        -  [cvar] Implemented cvar table
+        -  [gvar] Renamed GlyphVariation to TupleVariation to match OpenType
+           terminology.
+        -  [otTables] Handle gracefully empty VarData.Item array when compiling
+           XML. (#797)
+        -  [varLib] Re-enabled generation of ``HVAR`` table for fonts with
+           TrueType outlines; removed ``--build-HVAR`` command-line option.
+        -  [feaLib] The parser can now be extended to support non-standard
+           statements in FEA code by using a customized Abstract Syntax Tree.
+           See, for example, ``feaLib.builder_test.test_extensions`` and
+           baseClass.feax (#794, fixes #773).
+        -  [feaLib] Added ``feaLib`` command to the 'fonttools' command-line
+           tool; applies a feature file to a font. ``fonttools feaLib -h`` for
+           help.
+        -  [pens] The ``T2CharStringPen`` now takes an optional
+           ``roundTolerance`` argument to control the rounding of coordinates
+           (#804, fixes #769).
+        -  [ci] Measure test coverage on all supported python versions and OSes,
+           combine coverage data and upload to
+           https://codecov.io/gh/fonttools/fonttools (#786)
+        -  [ci] Configured Travis and Appveyor for running tests on Python 3.6
+           (#785, 55c03bc)
+        -  The manual pages installation directory can be customized through
+           ``FONTTOOLS_MANPATH`` environment variable (#799, fixes #84).
+        -  [Snippets] Added otf2ttf.py, for converting fonts from CFF to
+           TrueType using the googlei18n/cu2qu module (#802)
+        
+        3.4.0 (released 2016-12-21)
+        ---------------------------
+        
+        -  [feaLib] Added support for generating FEA text from abstract syntax
+           tree (AST) objects (#776). Thanks @mhosken
+        -  Added ``agl.toUnicode`` function to convert AGL-compliant glyph names
+           to Unicode strings (#774)
+        -  Implemented MVAR table (b4d5381)
+        
+        3.3.1 (released 2016-12-15)
+        ---------------------------
+        
+        -  [setup] We no longer use versioneer.py to compute fonttools version
+           from git metadata, as this has caused issues for some users (#767).
+           Now we bump the version strings manually with a custom ``release``
+           command of setup.py script.
+        
+        3.3.0 (released 2016-12-06)
+        ---------------------------
+        
+        -  [ttLib] Implemented STAT table from OpenType 1.8 (#758)
+        -  [cffLib] Fixed decompilation of CFF fonts containing non-standard
+           key/value pairs in FontDict (issue #740; PR #744)
+        -  [py23] minor: in ``round3`` function, allow the second argument to be
+           ``None`` (#757)
+        -  The standalone ``sstruct`` and ``xmlWriter`` modules, deprecated
+           since vesion 3.2.0, have been removed. They can be imported from the
+           ``fontTools.misc`` package.
+        
+        3.2.3 (released 2016-12-02)
+        ---------------------------
+        
+        -  [py23] optimized performance of round3 function; added backport for
+           py35 math.isclose() (9d8dacb)
+        -  [subset] fixed issue with 'narrow' (UCS-2) Python 2 builds and
+           ``--text``/``--text-file`` options containing non-BMP chararcters
+           (16d0e5e)
+        -  [varLib] fixed issuewhen normalizing location values (8fa2ee1, #749)
+        -  [inspect] Made it compatible with both python2 and python3 (167ee60,
+           #748). Thanks @pnemade
+        
+        3.2.2 (released 2016-11-24)
+        ---------------------------
+        
+        -  [varLib] Do not emit null axes in fvar (1bebcec). Thanks @robmck-ms
+        -  [varLib] Handle fonts without GPOS (7915a45)
+        -  [merge] Ignore LangSys if None (a11bc56)
+        -  [subset] Fix subsetting MathVariants (78d3cbe)
+        -  [OS/2] Fix "Private Use (plane 15)" range (08a0d55). Thanks @mashabow
+        
+        3.2.1 (released 2016-11-03)
+        ---------------------------
+        
+        -  [OS/2] fix checking ``fsSelection`` bits matching ``head.macStyle``
+           bits
+        -  [varLib] added ``--build-HVAR`` option to generate ``HVAR`` table for
+           fonts with TrueType outlines. For ``CFF2``, it is enabled by default.
+        
+        3.2.0 (released 2016-11-02)
+        ---------------------------
+        
+        -  [varLib] Improve support for OpenType 1.8 Variable Fonts:
+        -  Implement GDEF's VariationStore
+        -  Implement HVAR/VVAR tables
+        -  Partial support for loading MutatorMath .designspace files with
+           varLib.designspace module
+        -  Add varLib.models with Variation fonts interpolation models
+        -  Implement GSUB/GPOS FeatureVariations
+        -  Initial support for interpolating and merging OpenType Layout tables
+           (see ``varLib.interpolate_layout`` and ``varLib.merger`` modules)
+        -  [API change] Change version to be an integer instead of a float in
+           XML output for GSUB, GPOS, GDEF, MATH, BASE, JSTF, HVAR, VVAR, feat,
+           hhea and vhea tables. Scripts that set the Version for those to 1.0
+           or other float values also need fixing. A warning is emitted when
+           code or XML needs fix.
+        -  several bug fixes to the cffLib module, contributed by Adobe's
+           @readroberts
+        -  The XML output for CFF table now has a 'major' and 'minor' elements
+           for specifying whether it's version 1.0 or 2.0 (support for CFF2 is
+           coming soon)
+        -  [setup.py] remove undocumented/deprecated ``extra_path`` Distutils
+           argument. This means that we no longer create a "FontTools" subfolder
+           in site-packages containing the actual fontTools package, as well as
+           the standalone xmlWriter and sstruct modules. The latter modules are
+           also deprecated, and scheduled for removal in upcoming releases.
+           Please change your import statements to point to from fontTools.misc
+           import xmlWriter and from fontTools.misc import sstruct.
+        -  [scripts] Add a 'fonttools' command-line tool that simply runs
+           ``fontTools.*`` sub-modules: e.g. ``fonttools ttx``,
+           ``fonttools subset``, etc.
+        -  [hmtx/vmts] Read advance width/heights as unsigned short (uint16);
+           automatically round float values to integers.
+        -  [ttLib/xmlWriter] add 'newlinestr=None' keyword argument to
+           ``TTFont.saveXML`` for overriding os-specific line endings (passed on
+           to ``XMLWriter`` instances).
+        -  [versioning] Use versioneer instead of ``setuptools_scm`` to
+           dynamically load version info from a git checkout at import time.
+        -  [feaLib] Support backslash-prefixed glyph names.
+        
+        3.1.2 (released 2016-09-27)
+        ---------------------------
+        
+        -  restore Makefile as an alternative way to build/check/install
+        -  README.md: update instructions for installing package from source,
+           and for running test suite
+        -  NEWS: Change log was out of sync with tagged release
+        
+        3.1.1 (released 2016-09-27)
+        ---------------------------
+        
+        -  Fix ``ttLibVersion`` attribute in TTX files still showing '3.0'
+           instead of '3.1'.
+        -  Use ``setuptools_scm`` to manage package versions.
+        
+        3.1.0 (released 2016-09-26)
+        ---------------------------
+        
+        -  [feaLib] New library to parse and compile Adobe FDK OpenType Feature
+           files.
+        -  [mtiLib] New library to parse and compile Monotype 'FontDame'
+           OpenType Layout Tables files.
+        -  [voltLib] New library to parse Microsoft VOLT project files.
+        -  [otlLib] New library to work with OpenType Layout tables.
+        -  [varLib] New library to work with OpenType Font Variations.
+        -  [pens] Add ttGlyphPen to draw to TrueType glyphs, and t2CharStringPen
+           to draw to Type 2 Charstrings (CFF); add areaPen and perimeterPen.
+        -  [ttLib.tables] Implement 'meta' and 'trak' tables.
+        -  [ttx] Add --flavor option for compiling to 'woff' or 'woff2'; add
+           ``--with-zopfli`` option to use Zopfli to compress WOFF 1.0 fonts.
+        -  [subset] Support subsetting 'COLR'/'CPAL' and 'CBDT'/'CBLC' color
+           fonts tables, and 'gvar' table for variation fonts.
+        -  [Snippets] Add ``symfont.py``, for symbolic font statistics analysis;
+           interpolatable.py, a preliminary script for detecting interpolation
+           errors; ``{merge,dump}_woff_metadata.py``.
+        -  [classifyTools] Helpers to classify things into classes.
+        -  [CI] Run tests on Windows, Linux and macOS using Appveyor and Travis
+           CI; check unit test coverage with Coverage.py/Coveralls; automatic
+           deployment to PyPI on tags.
+        -  [loggingTools] Use Python built-in logging module to print messages.
+        -  [py23] Make round() behave like Python 3 built-in round(); define
+           round2() and round3().
+        
+        3.0 (released 2015-09-01)
+        -------------------------
+        
+        -  Add Snippet scripts for cmap subtable format conversion, printing
+           GSUB/GPOS features, building a GX font from two masters
+        -  TTX WOFF2 support and a ``-f`` option to overwrite output file(s)
+        -  Support GX tables: ``avar``, ``gvar``, ``fvar``, ``meta``
+        -  Support ``feat`` and gzip-compressed SVG tables
+        -  Upgrade Mac East Asian encodings to native implementation if
+           available
+        -  Add Roman Croatian and Romanian encodings, codecs for mac-extended
+           East Asian encodings
+        -  Implement optimal GLYF glyph outline packing; disabled by default
+        
+        2.5 (released 2014-09-24)
+        -------------------------
+        
+        -  Add a Qt pen
+        -  Add VDMX table converter
+        -  Load all OpenType sub-structures lazily
+        -  Add support for cmap format 13.
+        -  Add pyftmerge tool
+        -  Update to Unicode 6.3.0d3
+        -  Add pyftinspect tool
+        -  Add support for Google CBLC/CBDT color bitmaps, standard EBLC/EBDT
+           embedded bitmaps, and ``SVG`` table (thanks to Read Roberts at Adobe)
+        -  Add support for loading, saving and ttx'ing WOFF file format
+        -  Add support for Microsoft COLR/CPAL layered color glyphs
+        -  Support PyPy
+        -  Support Jython, by replacing numpy with array/lists modules and
+           removed it, pure-Python StringIO, not cStringIO
+        -  Add pyftsubset and Subsetter object, supporting CFF and TTF
+        -  Add to ttx args for -q for quiet mode, -z to choose a bitmap dump
+           format
+        
+        2.4 (released 2013-06-22)
+        -------------------------
+        
+        -  Option to write to arbitrary files
+        -  Better dump format for DSIG
+        -  Better detection of OTF XML
+        -  Fix issue with Apple's kern table format
+        -  Fix mangling of TT glyph programs
+        -  Fix issues related to mona.ttf
+        -  Fix Windows Installer instructions
+        -  Fix some modern MacOS issues
+        -  Fix minor issues and typos
+        
+        2.3 (released 2009-11-08)
+        -------------------------
+        
+        -  TrueType Collection (TTC) support
+        -  Python 2.6 support
+        -  Update Unicode data to 5.2.0
+        -  Couple of bug fixes
+        
+        2.2 (released 2008-05-18)
+        -------------------------
+        
+        -  ClearType support
+        -  cmap format 1 support
+        -  PFA font support
+        -  Switched from Numeric to numpy
+        -  Update Unicode data to 5.1.0
+        -  Update AGLFN data to 1.6
+        -  Many bug fixes
+        
+        2.1 (released 2008-01-28)
+        -------------------------
+        
+        -  Many years worth of fixes and features
+        
+        2.0b2 (released 2002-??-??)
+        ---------------------------
+        
+        -  Be "forgiving" when interpreting the maxp table version field:
+           interpret any value as 1.0 if it's not 0.5. Fixes dumping of these
+           GPL fonts: http://www.freebsd.org/cgi/pds.cgi?ports/chinese/wangttf
+        -  Fixed ttx -l: it turned out this part of the code didn't work with
+           Python 2.2.1 and earlier. My bad to do most of my testing with a
+           different version than I shipped TTX with :-(
+        -  Fixed bug in ClassDef format 1 subtable (Andreas Seidel bumped into
+           this one).
+        
+        2.0b1 (released 2002-09-10)
+        ---------------------------
+        
+        -  Fixed embarrassing bug: the master checksum in the head table is now
+           calculated correctly even on little-endian platforms (such as Intel).
+        -  Made the cmap format 4 compiler smarter: the binary data it creates
+           is now more or less as compact as possible. TTX now makes more
+           compact data than in any shipping font I've tested it with.
+        -  Dump glyph names as a separate "GlyphOrder" pseudo table as opposed
+           to as part of the glyf table (obviously needed for CFF-OTF's).
+        -  Added proper support for the CFF table.
+        -  Don't barf on empty tables (questionable, but "there are font out
+           there...")
+        -  When writing TT glyf data, align glyphs on 4-byte boundaries. This
+           seems to be the current recommendation by MS. Also: don't barf on
+           fonts which are already 4-byte aligned.
+        -  Windows installer contributed bu Adam Twardoch! Yay!
+        -  Changed the command line interface again, now by creating one new
+           tool replacing the old ones: ttx It dumps and compiles, depending on
+           input file types. The options have changed somewhat.
+        -  The -d option is back (output dir)
+        -  ttcompile's -i options is now called -m (as in "merge"), to avoid
+           clash with dump's -i.
+        -  The -s option ("split tables") no longer creates a directory, but
+           instead outputs a small .ttx file containing references to the
+           individual table files. This is not a true link, it's a simple file
+           name, and the referenced file should be in the same directory so
+           ttcompile can find them.
+        -  compile no longer accepts a directory as input argument. Instead it
+           can parse the new "mini-ttx" format as output by "ttx -s".
+        -  all arguments are input files
+        -  Renamed the command line programs and moved them to the Tools
+           subdirectory. They are now installed by the setup.py install script.
+        -  Added OpenType support. BASE, GDEF, GPOS, GSUB and JSTF are (almost)
+           fully supported. The XML output is not yet final, as I'm still
+           considering to output certain subtables in a more human-friendly
+           manner.
+        -  Fixed 'kern' table to correctly accept subtables it doesn't know
+           about, as well as interpreting Apple's definition of the 'kern' table
+           headers correctly.
+        -  Fixed bug where glyphnames were not calculated from 'cmap' if it was
+           (one of the) first tables to be decompiled. More specifically: it
+           cmap was the first to ask for a glyphID -> glyphName mapping.
+        -  Switched XML parsers: use expat instead of xmlproc. Should be faster.
+        -  Removed my UnicodeString object: I now require Python 2.0 or up,
+           which has unicode support built in.
+        -  Removed assert in glyf table: redundant data at the end of the table
+           is now ignored instead of raising an error. Should become a warning.
+        -  Fixed bug in hmtx/vmtx code that only occured if all advances were
+           equal.
+        -  Fixed subtle bug in TT instruction disassembler.
+        -  Couple of fixes to the 'post' table.
+        -  Updated OS/2 table to latest spec.
+        
+        1.0b1 (released 2001-08-10)
+        ---------------------------
+        
+        -  Reorganized the command line interface for ttDump.py and
+           ttCompile.py, they now behave more like "normal" command line tool,
+           in that they accept multiple input files for batch processing.
+        -  ttDump.py and ttCompile.py don't silently override files anymore, but
+           ask before doing so. Can be overridden by -f.
+        -  Added -d option to both ttDump.py and ttCompile.py.
+        -  Installation is now done with distutils. (Needs work for environments
+           without compilers.)
+        -  Updated installation instructions.
+        -  Added some workarounds so as to handle certain buggy fonts more
+           gracefully.
+        -  Updated Unicode table to Unicode 3.0 (Thanks Antoine!)
+        -  Included a Python script by Adam Twardoch that adds some useful stuff
+           to the Windows registry.
+        -  Moved the project to SourceForge.
+        
+        1.0a6 (released 2000-03-15)
+        ---------------------------
+        
+        -  Big reorganization: made ttLib a subpackage of the new fontTools
+           package, changed several module names. Called the entire suite
+           "FontTools"
+        -  Added several submodules to fontTools, some new, some older.
+        -  Added experimental CFF/GPOS/GSUB support to ttLib, read-only (but XML
+           dumping of GPOS/GSUB is for now disabled)
+        -  Fixed hdmx endian bug
+        -  Added -b option to ttCompile.py, it disables recalculation of
+           bounding boxes, as requested by Werner Lemberg.
+        -  Renamed tt2xml.pt to ttDump.py and xml2tt.py to ttCompile.py
+        -  Use ".ttx" as file extension instead of ".xml".
+        -  TTX is now the name of the XML-based *format* for TT fonts, and not
+           just an application.
+        
+        1.0a5
+        -----
+        
+        Never released
+        
+        -  More tables supported: hdmx, vhea, vmtx
+        
+        1.0a3 & 1.0a4
+        -------------
+        
+        Never released
+        
+        -  fixed most portability issues
+        -  retracted the "Euro_or_currency" change from 1.0a2: it was
+           nonsense!
+        
+        1.0a2 (released 1999-05-02)
+        ---------------------------
+        
+        -  binary release for MacOS
+        -  genenates full FOND resources: including width table, PS font name
+           info and kern table if applicable.
+        -  added cmap format 4 support. Extra: dumps Unicode char names as XML
+           comments!
+        -  added cmap format 6 support
+        -  now accepts true type files starting with "true" (instead of just
+           0x00010000 and "OTTO")
+        -  'glyf' table support is now complete: I added support for composite
+           scale, xy-scale and two-by-two for the 'glyf' table. For now,
+           component offset scale behaviour defaults to Apple-style. This only
+           affects the (re)calculation of the glyph bounding box.
+        -  changed "Euro" to "Euro_or_currency" in the Standard Apple Glyph
+           order list, since we cannot tell from the 'post' table which is
+           meant. I should probably doublecheck with a Unicode encoding if
+           available. (This does not affect the output!)
+        
+        Fixed bugs: - 'hhea' table is now recalculated correctly - fixed wrong
+        assumption about sfnt resource names
+        
+        1.0a1 (released 1999-04-27)
+        ---------------------------
+        
+        -  initial binary release for MacOS
+        
+Platform: Any
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Console
+Classifier: Environment :: Other Environment
+Classifier: Intended Audience :: Developers
+Classifier: Intended Audience :: End Users/Desktop
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Natural Language :: English
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
+Classifier: Topic :: Text Processing :: Fonts
+Classifier: Topic :: Multimedia :: Graphics
+Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
+Provides-Extra: woff
+Provides-Extra: all
+Provides-Extra: symfont
+Provides-Extra: interpolatable
+Provides-Extra: unicode
+Provides-Extra: type1
+Provides-Extra: lxml
+Provides-Extra: ufo
+Provides-Extra: plot
+Provides-Extra: graphite
diff --git a/README.rst b/README.rst
index 97d23e4..cd7c02a 100644
--- a/README.rst
+++ b/README.rst
@@ -1,4 +1,4 @@
-|CI Build Status| |Coverage Status| |PyPI| |Gitter Chat|
+|Travis Build Status| |Appveyor Build status| |Coverage Status| |PyPI| |Gitter Chat|
 
 What is this?
 ~~~~~~~~~~~~~
@@ -11,19 +11,16 @@
   licence <LICENSE>`__.
 | Among other things this means you can use it free of charge.
 
-`User documentation <https://fonttools.readthedocs.io/en/latest/>`_ and
-`developer documentation <https://fonttools.readthedocs.io/en/latest/developer.html>`_
-are available at `Read the Docs <https://fonttools.readthedocs.io/>`_.
-
 Installation
 ~~~~~~~~~~~~
 
-FontTools 4.x requires `Python <http://www.python.org/download/>`__ 3.6
-or later. FontTools 3.x requires Python 2.7 or later.
+FontTools requires `Python <http://www.python.org/download/>`__ 2.7, 3.4
+or later.
 
 **NOTE** From August 2019, until no later than January 1 2020, the support
 for *Python 2.7* will be limited to only critical bug fixes, and no new features
-will be added to the ``py27`` branch. You can read more `here <https://python3statement.org>`__
+will be added to the ``py27`` branch. The upcoming FontTools 4.x series will require
+*Python 3.6* or above. You can read more `here <https://python3statement.org>`__
 and `here <https://github.com/fonttools/fonttools/issues/765>`__ for the
 reasons behind this decision.
 
@@ -58,6 +55,112 @@
     # install in 'editable' mode
     pip install -e .
 
+TTX – From OpenType and TrueType to XML and Back
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Once installed you can use the ``ttx`` command to convert binary font
+files (``.otf``, ``.ttf``, etc) to the TTX XML format, edit them, and
+convert them back to binary format. TTX files have a .ttx file
+extension.
+
+.. code:: sh
+
+    ttx /path/to/font.otf
+    ttx /path/to/font.ttx
+
+The TTX application can be used in two ways, depending on what
+platform you run it on:
+
+-  As a command line tool (Windows/DOS, Unix, macOS)
+-  By dropping files onto the application (Windows, macOS)
+
+TTX detects what kind of files it is fed: it will output a ``.ttx`` file
+when it sees a ``.ttf`` or ``.otf``, and it will compile a ``.ttf`` or
+``.otf`` when the input file is a ``.ttx`` file. By default, the output
+file is created in the same folder as the input file, and will have the
+same name as the input file but with a different extension. TTX will
+*never* overwrite existing files, but if necessary will append a unique
+number to the output filename (before the extension) such as
+``Arial#1.ttf``
+
+When using TTX from the command line there are a bunch of extra options.
+These are explained in the help text, as displayed when typing
+``ttx -h`` at the command prompt. These additional options include:
+
+-  specifying the folder where the output files are created
+-  specifying which tables to dump or which tables to exclude
+-  merging partial ``.ttx`` files with existing ``.ttf`` or ``.otf``
+   files
+-  listing brief table info instead of dumping to ``.ttx``
+-  splitting tables to separate ``.ttx`` files
+-  disabling TrueType instruction disassembly
+
+The TTX file format
+-------------------
+
+The following tables are currently supported:
+
+.. begin table list
+.. code::
+
+    BASE, CBDT, CBLC, CFF, CFF2, COLR, CPAL, DSIG, EBDT, EBLC, FFTM,
+    Feat, GDEF, GMAP, GPKG, GPOS, GSUB, Glat, Gloc, HVAR, JSTF, LTSH,
+    MATH, META, MVAR, OS/2, SING, STAT, SVG, Silf, Sill, TSI0, TSI1,
+    TSI2, TSI3, TSI5, TSIB, TSID, TSIJ, TSIP, TSIS, TSIV, TTFA, VDMX,
+    VORG, VVAR, ankr, avar, bsln, cidg, cmap, cvar, cvt, feat, fpgm,
+    fvar, gasp, gcid, glyf, gvar, hdmx, head, hhea, hmtx, kern, lcar,
+    loca, ltag, maxp, meta, mort, morx, name, opbd, post, prep, prop,
+    sbix, trak, vhea and vmtx
+.. end table list
+
+Other tables are dumped as hexadecimal data.
+
+TrueType fonts use glyph indices (GlyphIDs) to refer to glyphs in most
+places. While this is fine in binary form, it is really hard to work
+with for humans. Therefore we use names instead.
+
+The glyph names are either extracted from the ``CFF`` table or the
+``post`` table, or are derived from a Unicode ``cmap`` table. In the
+latter case the Adobe Glyph List is used to calculate names based on
+Unicode values. If all of these methods fail, names are invented based
+on GlyphID (eg ``glyph00142``)
+
+It is possible that different glyphs use the same name. If this happens,
+we force the names to be unique by appending ``#n`` to the name (``n``
+being an integer number.) The original names are being kept, so this has
+no influence on a "round tripped" font.
+
+Because the order in which glyphs are stored inside the binary font is
+important, we maintain an ordered list of glyph names in the font.
+
+Other Tools
+~~~~~~~~~~~
+
+Commands for merging and subsetting fonts are also available:
+
+.. code:: sh
+
+    pyftmerge
+    pyftsubset
+
+fontTools Python Module
+~~~~~~~~~~~~~~~~~~~~~~~
+
+The fontTools Python module provides a convenient way to
+programmatically edit font files.
+
+.. code:: py
+
+    >>> from fontTools.ttLib import TTFont
+    >>> font = TTFont('/path/to/font.ttf')
+    >>> font
+    <fontTools.ttLib.TTFont object at 0x10c34ed50>
+    >>>
+
+A selection of sample Python programs is in the
+`Snippets <https://github.com/fonttools/fonttools/blob/master/Snippets/>`__
+directory.
+
 Optional Requirements
 ---------------------
 
@@ -81,7 +184,7 @@
 
   The module exports a ElementTree-like API for reading/writing XML files, and
   allows to use as the backend either the built-in ``xml.etree`` module or
-  `lxml <https://lxml.de>`__. The latter is preferred whenever present,
+  `lxml <https://http://lxml.de>`__. The latter is preferred whenever present,
   as it is generally faster and more secure.
 
   *Extra:* ``lxml``
@@ -174,19 +277,9 @@
 
   *Extra:* ``type1``
 
-- ``Lib/fontTools/ttLib/removeOverlaps.py``
+- ``Lib/fontTools/pens/cocoaPen.py``
 
-  Simplify TrueType glyphs by merging overlapping contours and components.
-
-  * `skia-pathops <https://pypi.python.org/pypy/skia-pathops>`__: Python
-    bindings for the Skia library's PathOps module, performing boolean
-    operations on paths (union, intersection, etc.).
-
-  *Extra:* ``pathops``
-
-- ``Lib/fontTools/pens/cocoaPen.py`` and ``Lib/fontTools/pens/quartzPen.py``
-
-  Pens for drawing glyphs with Cocoa ``NSBezierPath`` or ``CGPath`` require:
+  Pen for drawing glyphs with Cocoa ``NSBezierPath``, requires:
 
   * `PyObjC <https://pypi.python.org/pypi/pyobjc>`__: the bridge between
     Python and the Objective-C runtime (macOS platform only).
@@ -205,22 +298,79 @@
   * `reportlab <https://pypi.python.org/pypi/reportlab>`__: Python toolkit
     for generating PDFs and graphics.
 
+Testing
+~~~~~~~
+
+To run the test suite, you need to install `pytest <http://docs.pytest.org/en/latest/>`__.
+When you run the ``pytest`` command, the tests will run against the
+installed ``fontTools`` package, or the first one found in the
+``PYTHONPATH``.
+
+You can also use `tox <https://tox.readthedocs.io/en/latest/>`__ to
+automatically run tests on different Python versions in isolated virtual
+environments.
+
+.. code:: sh
+
+    pip install tox
+    tox
+
+Note that when you run ``tox`` without arguments, the tests are executed
+for all the environments listed in tox.ini's ``envlist``. In our case,
+this includes Python 2.7 and 3.7, so for this to work the ``python2.7``
+and ``python3.7`` executables must be available in your ``PATH``.
+
+You can specify an alternative environment list via the ``-e`` option,
+or the ``TOXENV`` environment variable:
+
+.. code:: sh
+
+    tox -e py27
+    TOXENV="py36-cov,htmlcov" tox
+
+Development Community
+~~~~~~~~~~~~~~~~~~~~~
+
+TTX/FontTools development is ongoing in an active community of
+developers, that includes professional developers employed at major
+software corporations and type foundries as well as hobbyists.
+
+Feature requests and bug reports are always welcome at
+https://github.com/fonttools/fonttools/issues/
+
+The best place for discussions about TTX from an end-user perspective as
+well as TTX/FontTools development is the
+https://groups.google.com/d/forum/fonttools mailing list. There is also
+a development https://groups.google.com/d/forum/fonttools-dev mailing
+list for continuous integration notifications. You can also email Behdad
+privately at behdad@behdad.org
+
+History
+~~~~~~~
+
+The fontTools project was started by Just van Rossum in 1999, and was
+maintained as an open source project at
+http://sourceforge.net/projects/fonttools/. In 2008, Paul Wise (pabs3)
+began helping Just with stability maintenance. In 2013 Behdad Esfahbod
+began a friendly fork, thoroughly reviewing the codebase and making
+changes at https://github.com/behdad/fonttools to add new features and
+support for new font formats.
+
 Acknowledgements
 ~~~~~~~~~~~~~~~~
 
 In alphabetical order:
 
 Olivier Berten, Samyak Bhuta, Erik van Blokland, Petr van Blokland,
-Jelle Bosma, Sascha Brawer, Tom Byrer, Antonio Cavedoni, Frédéric 
-Coiffier, Vincent Connare, David Corbett, Simon Cozens, Dave Crossland, 
-Simon Daniels, Peter Dekkers, Behdad Esfahbod, Behnam Esfahbod, Hannes 
-Famira, Sam Fishman, Matt Fontaine, Yannis Haralambous, Greg Hitchcock, 
-Jeremie Hornus, Khaled Hosny, John Hudson, Denis Moyogo Jacquerye, Jack 
-Jansen, Tom Kacvinsky, Jens Kutilek, Antoine Leca, Werner Lemberg, Tal 
-Leming, Peter Lofting, Cosimo Lupo, Masaya Nakamura, Dave Opstad, 
-Laurence Penney, Roozbeh Pournader, Garret Rieger, Read Roberts, Guido 
-van Rossum, Just van Rossum, Andreas Seidel, Georg Seifert, Chris 
-Simpkins, Miguel Sousa, Adam Twardoch, Adrien Tétar, Vitaly Volkov, 
+Jelle Bosma, Sascha Brawer, Tom Byrer, Frédéric Coiffier, Vincent
+Connare, Dave Crossland, Simon Daniels, Peter Dekkers, Behdad Esfahbod,
+Behnam Esfahbod, Hannes Famira, Sam Fishman, Matt Fontaine, Yannis
+Haralambous, Greg Hitchcock, Jeremie Hornus, Khaled Hosny, John Hudson,
+Denis Moyogo Jacquerye, Jack Jansen, Tom Kacvinsky, Jens Kutilek,
+Antoine Leca, Werner Lemberg, Tal Leming, Peter Lofting, Cosimo Lupo,
+Masaya Nakamura, Dave Opstad, Laurence Penney, Roozbeh Pournader, Garret
+Rieger, Read Roberts, Guido van Rossum, Just van Rossum, Andreas Seidel,
+Georg Seifert, Miguel Sousa, Adam Twardoch, Adrien Tétar, Vitaly Volkov,
 Paul Wise.
 
 Copyrights
@@ -240,8 +390,10 @@
 
 Have fun!
 
-.. |CI Build Status| image:: https://github.com/fonttools/fonttools/workflows/Test/badge.svg
-   :target: https://github.com/fonttools/fonttools/actions?query=workflow%3ATest
+.. |Travis Build Status| image:: https://travis-ci.org/fonttools/fonttools.svg
+   :target: https://travis-ci.org/fonttools/fonttools
+.. |Appveyor Build status| image:: https://ci.appveyor.com/api/projects/status/0f7fmee9as744sl7/branch/master?svg=true
+   :target: https://ci.appveyor.com/project/fonttools/fonttools/branch/master
 .. |Coverage Status| image:: https://codecov.io/gh/fonttools/fonttools/branch/master/graph/badge.svg
    :target: https://codecov.io/gh/fonttools/fonttools
 .. |PyPI| image:: https://img.shields.io/pypi/v/fonttools.svg
diff --git a/Snippets/cmap-format.py b/Snippets/cmap-format.py
index 0a78670..0cee39c 100755
--- a/Snippets/cmap-format.py
+++ b/Snippets/cmap-format.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python3
+#! /usr/bin/env python
 
 # Sample script to convert legacy cmap subtables to format-4
 # subtables.  Note that this is rarely what one needs.  You
@@ -10,6 +10,8 @@
 # getEncoding() of subtable and use that encoding to map the
 # characters to Unicode...  TODO: Extend this script to do that.
 
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.ttLib import TTFont
 from fontTools.ttLib.tables._c_m_a_p import CmapSubtable
 import sys
diff --git a/Snippets/decompose-ttf.py b/Snippets/decompose-ttf.py
deleted file mode 100755
index bccaf72..0000000
--- a/Snippets/decompose-ttf.py
+++ /dev/null
@@ -1,53 +0,0 @@
-#! /usr/bin/env python3
-
-# Example script to decompose the composite glyphs in a TTF into
-# non-composite outlines.
-
-
-import sys
-from fontTools.ttLib import TTFont
-from fontTools.pens.recordingPen import DecomposingRecordingPen
-from fontTools.pens.ttGlyphPen import TTGlyphPen
-
-try:
-    import pathops
-except ImportError:
-    sys.exit(
-        "This script requires the skia-pathops module. "
-        "`pip install skia-pathops` and then retry."
-    )
-
-
-if len(sys.argv) != 3:
-    print("usage: decompose-ttf.py fontfile.ttf outfile.ttf")
-    sys.exit(1)
-
-src = sys.argv[1]
-dst = sys.argv[2]
-
-with TTFont(src) as f:
-    glyfTable = f["glyf"]
-    glyphSet = f.getGlyphSet()
-
-    for glyphName in glyphSet.keys():
-        if not glyfTable[glyphName].isComposite():
-            continue
-
-        # record TTGlyph outlines without components
-        dcPen = DecomposingRecordingPen(glyphSet)
-        glyphSet[glyphName].draw(dcPen)
-
-        # replay recording onto a skia-pathops Path
-        path = pathops.Path()
-        pathPen = path.getPen()
-        dcPen.replay(pathPen)
-
-        # remove overlaps
-        path.simplify()
-
-        # create new TTGlyph from Path
-        ttPen = TTGlyphPen(None)
-        path.draw(ttPen)
-        glyfTable[glyphName] = ttPen.glyph()
-
-    f.save(dst)
diff --git a/Snippets/dump_woff_metadata.py b/Snippets/dump_woff_metadata.py
index c9ea574..0023a10 100644
--- a/Snippets/dump_woff_metadata.py
+++ b/Snippets/dump_woff_metadata.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 import sys
 from fontTools.ttx import makeOutputFileName
 from fontTools.ttLib import TTFont
diff --git a/Snippets/fix-dflt-langsys.py b/Snippets/fix-dflt-langsys.py
index c072117..d8eccb4 100644
--- a/Snippets/fix-dflt-langsys.py
+++ b/Snippets/fix-dflt-langsys.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
 
 import argparse
 import logging
diff --git a/Snippets/fontTools b/Snippets/fontTools
deleted file mode 100755
index 9a21c02..0000000
--- a/Snippets/fontTools
+++ /dev/null
@@ -1 +0,0 @@
-../Lib/fontTools
\ No newline at end of file
diff --git a/Snippets/interpolate.py b/Snippets/interpolate.py
index 063046c..7ed822d 100755
--- a/Snippets/interpolate.py
+++ b/Snippets/interpolate.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python3
+#! /usr/bin/env python
 
 # Illustrates how a fonttools script can construct variable fonts.
 #
@@ -21,6 +21,8 @@
 # $ ./interpolate.py && open Roboto.ttf
 
 
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.ttLib import TTFont
 from fontTools.ttLib.tables._n_a_m_e import NameRecord
 from fontTools.ttLib.tables._f_v_a_r import table__f_v_a_r, Axis, NamedInstance
diff --git a/Snippets/layout-features.py b/Snippets/layout-features.py
index 53e9735..25522cd 100755
--- a/Snippets/layout-features.py
+++ b/Snippets/layout-features.py
@@ -1,5 +1,7 @@
-#! /usr/bin/env python3
+#! /usr/bin/env python
 
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.ttLib import TTFont
 from fontTools.ttLib.tables import otTables
 import sys
diff --git a/Snippets/merge_woff_metadata.py b/Snippets/merge_woff_metadata.py
index d6e858f..669de46 100644
--- a/Snippets/merge_woff_metadata.py
+++ b/Snippets/merge_woff_metadata.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 import sys
 import os
 from fontTools.ttx import makeOutputFileName
diff --git a/Snippets/name-viewer.ipynb b/Snippets/name-viewer.ipynb
deleted file mode 100644
index 11722bc..0000000
--- a/Snippets/name-viewer.ipynb
+++ /dev/null
@@ -1,117 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## name-viewer.ipynb\n",
-    "\n",
-    "### Usage\n",
-    "\n",
-    "1. Install `jupyter`, `plotly`, `fonttools` dependencies with pip\n",
-    "2. Modify the `FONT_PATH` setting in the Python source block below by clicking next to it and typing a new path in your web browser window\n",
-    "3. Execute the block of Python source by selecting the code block below and clicking the \"Run\" button above\n",
-    "4. Repeat from step 2 with modified font paths to view tables in other fonts\n"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import plotly as py\n",
-    "import plotly.graph_objs as go\n",
-    "\n",
-    "from fontTools.ttLib import TTFont\n",
-    "\n",
-    "py.offline.init_notebook_mode(connected=True)\n",
-    "\n",
-    "# EDIT HERE ------------------------------------------------------\n",
-    "#\n",
-    "# Path to font file\n",
-    "FONT_PATH = \"path/to/font.ttf\"\n",
-    "#\n",
-    "# Table height\n",
-    "#    - adjust for the length of output from the font file\n",
-    "HEIGHT = 700\n",
-    "#\n",
-    "# END EDIT -------------------------------------------------------\n",
-    "\n",
-    "record_list = []\n",
-    "nameID_list = []\n",
-    "ppelangID_list = []\n",
-    "value_list = []\n",
-    "\n",
-    "tt = TTFont(FONT_PATH)\n",
-    "namerecord_list = tt[\"name\"].names\n",
-    "\n",
-    "for record in namerecord_list:\n",
-    "    nameID_list.append(record.nameID)\n",
-    "    ppelangID_list.append(\"{} {} {}\".format(record.platformID, \n",
-    "                                            record.platEncID, \n",
-    "                                            record.langID))\n",
-    "    value_list.append(\"{}\".format(record.string.decode('utf-8').strip()))\n",
-    "    \n",
-    "\n",
-    "record_list.append(nameID_list)\n",
-    "record_list.append(ppelangID_list)\n",
-    "record_list.append(value_list)\n",
-    "\n",
-    "\n",
-    "trace0 = go.Table(\n",
-    "  columnorder = [1,2,3],\n",
-    "  columnwidth = [80,80,400],\n",
-    "  header = dict(\n",
-    "    values = [['<b>nameID</b>'],\n",
-    "              ['<b>p-pE-lang</b>'],\n",
-    "              ['<b>Value</b>']\n",
-    "             ],\n",
-    "    line = dict(color = '#506784'),\n",
-    "    fill = dict(color = '#FFDE00'),\n",
-    "    align = ['center','center', 'center'],\n",
-    "    font = dict(color = 'black', size = 16),\n",
-    "  ),\n",
-    "  cells = dict(\n",
-    "    values = record_list,\n",
-    "    line = dict(color = '#506784'),\n",
-    "    fill = dict(color = ['#000000', 'white']),\n",
-    "    align = ['center', 'center', 'left'],\n",
-    "    font = dict(color = ['#F8F8F5', '#000000', '#000000'], size = 14),\n",
-    "    height = 30,\n",
-    "    ))\n",
-    "\n",
-    "data1 = [trace0]\n",
-    "\n",
-    "layout1 = go.Layout(\n",
-    "    autosize=True,\n",
-    "    height=HEIGHT,\n",
-    ")\n",
-    "\n",
-    "fig1 = dict(data=data1, layout=layout1)\n",
-    "py.offline.iplot(fig1)"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  },
-  "language_info": {
-   "codemirror_mode": {
-    "name": "ipython",
-    "version": 3
-   },
-   "file_extension": ".py",
-   "mimetype": "text/x-python",
-   "name": "python",
-   "nbconvert_exporter": "python",
-   "pygments_lexer": "ipython3",
-   "version": "3.7.2"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/Snippets/otf2ttf.py b/Snippets/otf2ttf.py
index b925b33..62b4f73 100755
--- a/Snippets/otf2ttf.py
+++ b/Snippets/otf2ttf.py
@@ -1,11 +1,12 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function, division, absolute_import
 
 import argparse
 import logging
 import os
 import sys
 
-from fontTools.pens.cu2quPen import Cu2QuPen
+from cu2qu.pens import Cu2QuPen
 from fontTools import configLogger
 from fontTools.misc.cliTools import makeOutputFileName
 from fontTools.pens.ttGlyphPen import TTGlyphPen
@@ -38,13 +39,6 @@
     return quadGlyphs
 
 
-def update_hmtx(ttFont, glyf):
-    hmtx = ttFont["hmtx"]
-    for glyphName, glyph in glyf.glyphs.items():
-        if hasattr(glyph, 'xMin'):
-            hmtx[glyphName] = (hmtx[glyphName][0], glyph.xMin)
-
-
 def otf_to_ttf(ttFont, post_format=POST_FORMAT, **kwargs):
     assert ttFont.sfntVersion == "OTTO"
     assert "CFF " in ttFont
@@ -57,7 +51,6 @@
     glyf.glyphs = glyphs_to_quadratic(ttFont.getGlyphSet(), **kwargs)
     del ttFont["CFF "]
     glyf.compile(ttFont)
-    update_hmtx(ttFont, glyf)
 
     ttFont["maxp"] = maxp = newTable("maxp")
     maxp.tableVersion = 0x00010000
diff --git a/Snippets/rename-fonts.py b/Snippets/rename-fonts.py
index 0a43dc2..ddfce10 100755
--- a/Snippets/rename-fonts.py
+++ b/Snippets/rename-fonts.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
 """Script to add a suffix to all family names in the input font's `name` table,
 and to optionally rename the output files with the given suffix.
 
@@ -6,6 +6,7 @@
 and 21, and if found the suffix is inserted after it; or else the suffix is
 appended at the end.
 """
+from __future__ import print_function, absolute_import, unicode_literals
 import os
 import argparse
 import logging
diff --git a/Snippets/subset-fpgm.py b/Snippets/subset-fpgm.py
index d06c3f5..c20c05f 100755
--- a/Snippets/subset-fpgm.py
+++ b/Snippets/subset-fpgm.py
@@ -1,5 +1,7 @@
-#! /usr/bin/env python3
+#! /usr/bin/env python
 
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.ttLib import TTFont
 import sys
 
diff --git a/Snippets/svg2glif.py b/Snippets/svg2glif.py
index 22fcc7d..aed3100 100755
--- a/Snippets/svg2glif.py
+++ b/Snippets/svg2glif.py
@@ -1,8 +1,9 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
 """ Convert SVG paths to UFO glyphs. """
 
+from __future__ import print_function, absolute_import
 
-__requires__ = ["fontTools"]
+__requires__ = ["FontTools", "ufoLib"]
 
 from fontTools.misc.py23 import SimpleNamespace
 from fontTools.svgLib import SVGPath
diff --git a/Tests/afmLib/afmLib_test.py b/Tests/afmLib/afmLib_test.py
index 3e9d9d8..97fcf8d 100644
--- a/Tests/afmLib/afmLib_test.py
+++ b/Tests/afmLib/afmLib_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 import unittest
 import os
 from fontTools import afmLib
diff --git a/Tests/agl_test.py b/Tests/agl_test.py
index f2fb72d..8754e6a 100644
--- a/Tests/agl_test.py
+++ b/Tests/agl_test.py
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+from __future__ import (print_function, division, absolute_import,
+                        unicode_literals)
+from fontTools.misc.py23 import *
 from fontTools import agl
 import unittest
 
@@ -5,15 +9,21 @@
 class AglToUnicodeTest(unittest.TestCase):
     def test_spec_examples(self):
         # https://github.com/adobe-type-tools/agl-specification#3-examples
-        self.assertEqual(agl.toUnicode("Lcommaaccent"), "Ļ")
+        #
+        # TODO: Currently, we only handle AGLFN instead of legacy AGL names.
+        # Therefore, the test cases below use Iogonek instead of Lcommaaccent.
+        # Change Iogonek to Lcommaaccent as soon as the implementation has
+        # been fixed to also support legacy AGL names.
+        # https://github.com/fonttools/fonttools/issues/775
+        self.assertEqual(agl.toUnicode("Iogonek"), "Į")
         self.assertEqual(agl.toUnicode("uni20AC0308"), "\u20AC\u0308")
         self.assertEqual(agl.toUnicode("u1040C"), "\U0001040C")
         self.assertEqual(agl.toUnicode("uniD801DC0C"), "")
         self.assertEqual(agl.toUnicode("uni20ac"), "")
         self.assertEqual(
-            agl.toUnicode("Lcommaaccent_uni20AC0308_u1040C.alternate"),
-            "\u013B\u20AC\u0308\U0001040C")
-        self.assertEqual(agl.toUnicode("Lcommaaccent_uni013B_u013B"), "ĻĻĻ")
+            agl.toUnicode("Iogonek_uni20AC0308_u1040C.alternate"),
+            "\u012E\u20AC\u0308\U0001040C")
+        self.assertEqual(agl.toUnicode("Iogonek_uni012E_u012E"), "ĮĮĮ")
         self.assertEqual(agl.toUnicode("foo"), "")
         self.assertEqual(agl.toUnicode(".notdef"), "")
 
diff --git a/Tests/cffLib/cffLib_test.py b/Tests/cffLib/cffLib_test.py
index 7a6e921..cc9d336 100644
--- a/Tests/cffLib/cffLib_test.py
+++ b/Tests/cffLib/cffLib_test.py
@@ -1,3 +1,4 @@
+from __future__ import print_function, division, absolute_import
 from fontTools.cffLib import TopDict, PrivateDict, CharStrings
 from fontTools.misc.testTools import parseXML, DataFilesHandler
 from fontTools.ttLib import TTFont
@@ -92,21 +93,6 @@
         self.assertEqual(topDict2.FDSelect.format, 4)
         self.assertEqual(topDict2.FDSelect.gidArray, [0, 0, 1])
 
-    def test_unique_glyph_names(self):
-        font_path = self.getpath('LinLibertine_RBI.otf')
-        font = TTFont(font_path, recalcBBoxes=False, recalcTimestamp=False)
-
-        glyphOrder = font.getGlyphOrder()
-        self.assertEqual(len(glyphOrder), len(set(glyphOrder)))
-
-        self.temp_dir()
-        save_path = os.path.join(self.tempdir, 'TestOTF.otf')
-        font.save(save_path)
-
-        font2 = TTFont(save_path)
-        glyphOrder = font2.getGlyphOrder()
-        self.assertEqual(len(glyphOrder), len(set(glyphOrder)))
-
 
 if __name__ == "__main__":
     sys.exit(unittest.main())
diff --git a/Tests/cffLib/data/LinLibertine_RBI.otf b/Tests/cffLib/data/LinLibertine_RBI.otf
deleted file mode 100755
index c1a4ff7..0000000
--- a/Tests/cffLib/data/LinLibertine_RBI.otf
+++ /dev/null
Binary files differ
diff --git a/Tests/cffLib/data/TestCFF2Widths.ttx b/Tests/cffLib/data/TestCFF2Widths.ttx
index e3a3c9c..bbac612 100644
--- a/Tests/cffLib/data/TestCFF2Widths.ttx
+++ b/Tests/cffLib/data/TestCFF2Widths.ttx
@@ -375,7 +375,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="1">
       <ClassDef glyph="A" class="1"/>
       <ClassDef glyph="B" class="1"/>
     </GlyphClassDef>
diff --git a/Tests/cffLib/specializer_test.py b/Tests/cffLib/specializer_test.py
index a9b778c..d45782e 100644
--- a/Tests/cffLib/specializer_test.py
+++ b/Tests/cffLib/specializer_test.py
@@ -1,3 +1,4 @@
+from __future__ import print_function, division, absolute_import
 from fontTools.cffLib.specializer import (programToString, stringToProgram,
                                           generalizeProgram, specializeProgram,
                                           programToCommands, commandsToProgram,
diff --git a/Tests/colorLib/__init__.py b/Tests/colorLib/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/Tests/colorLib/__init__.py
+++ /dev/null
diff --git a/Tests/colorLib/builder_test.py b/Tests/colorLib/builder_test.py
deleted file mode 100644
index 81da281..0000000
--- a/Tests/colorLib/builder_test.py
+++ /dev/null
@@ -1,1662 +0,0 @@
-from fontTools.ttLib import newTable
-from fontTools.ttLib.tables import otTables as ot
-from fontTools.colorLib import builder
-from fontTools.colorLib.geometry import round_start_circle_stable_containment, Circle
-from fontTools.colorLib.builder import LayerV1ListBuilder, _build_n_ary_tree
-from fontTools.colorLib.table_builder import TableBuilder
-from fontTools.colorLib.errors import ColorLibError
-import pytest
-from typing import List
-
-
-def _build(cls, source):
-    return LayerV1ListBuilder().tableBuilder.build(cls, source)
-
-
-def _buildPaint(source):
-    return LayerV1ListBuilder().buildPaint(source)
-
-
-def test_buildCOLR_v0():
-    color_layer_lists = {
-        "a": [("a.color0", 0), ("a.color1", 1)],
-        "b": [("b.color1", 1), ("b.color0", 0)],
-    }
-
-    colr = builder.buildCOLR(color_layer_lists)
-
-    assert colr.tableTag == "COLR"
-    assert colr.version == 0
-    assert colr.ColorLayers["a"][0].name == "a.color0"
-    assert colr.ColorLayers["a"][0].colorID == 0
-    assert colr.ColorLayers["a"][1].name == "a.color1"
-    assert colr.ColorLayers["a"][1].colorID == 1
-    assert colr.ColorLayers["b"][0].name == "b.color1"
-    assert colr.ColorLayers["b"][0].colorID == 1
-    assert colr.ColorLayers["b"][1].name == "b.color0"
-    assert colr.ColorLayers["b"][1].colorID == 0
-
-
-def test_buildCOLR_v0_layer_as_list():
-    # when COLRv0 layers are encoded as plist in UFO lib, both python tuples and
-    # lists are encoded as plist array elements; but the latter are always decoded
-    # as python lists, thus after roundtripping a plist tuples become lists.
-    # Before FontTools 4.17.0 we were treating tuples and lists as equivalent;
-    # with 4.17.0, a paint of type list is used to identify a PaintColrLayers.
-    # This broke backward compatibility as ufo2ft is simply passing through the
-    # color layers as read from the UFO lib plist, and as such the latter use lists
-    # instead of tuples for COLRv0 layers (layerGlyph, paletteIndex) combo.
-    # We restore backward compat by accepting either tuples or lists (of length 2
-    # and only containing a str and an int) as individual top-level layers.
-    # https://github.com/googlefonts/ufo2ft/issues/426
-    color_layer_lists = {
-        "a": [["a.color0", 0], ["a.color1", 1]],
-        "b": [["b.color1", 1], ["b.color0", 0]],
-    }
-
-    colr = builder.buildCOLR(color_layer_lists)
-
-    assert colr.tableTag == "COLR"
-    assert colr.version == 0
-    assert colr.ColorLayers["a"][0].name == "a.color0"
-    assert colr.ColorLayers["a"][0].colorID == 0
-    assert colr.ColorLayers["a"][1].name == "a.color1"
-    assert colr.ColorLayers["a"][1].colorID == 1
-    assert colr.ColorLayers["b"][0].name == "b.color1"
-    assert colr.ColorLayers["b"][0].colorID == 1
-    assert colr.ColorLayers["b"][1].name == "b.color0"
-    assert colr.ColorLayers["b"][1].colorID == 0
-
-
-def test_buildCPAL_v0():
-    palettes = [
-        [(0.68, 0.20, 0.32, 1.0), (0.45, 0.68, 0.21, 1.0)],
-        [(0.68, 0.20, 0.32, 0.6), (0.45, 0.68, 0.21, 0.6)],
-        [(0.68, 0.20, 0.32, 0.3), (0.45, 0.68, 0.21, 0.3)],
-    ]
-
-    cpal = builder.buildCPAL(palettes)
-
-    assert cpal.tableTag == "CPAL"
-    assert cpal.version == 0
-    assert cpal.numPaletteEntries == 2
-
-    assert len(cpal.palettes) == 3
-    assert [tuple(c) for c in cpal.palettes[0]] == [
-        (82, 51, 173, 255),
-        (54, 173, 115, 255),
-    ]
-    assert [tuple(c) for c in cpal.palettes[1]] == [
-        (82, 51, 173, 153),
-        (54, 173, 115, 153),
-    ]
-    assert [tuple(c) for c in cpal.palettes[2]] == [
-        (82, 51, 173, 76),
-        (54, 173, 115, 76),
-    ]
-
-
-def test_buildCPAL_palettes_different_lengths():
-    with pytest.raises(ColorLibError, match="have different lengths"):
-        builder.buildCPAL([[(1, 1, 1, 1)], [(0, 0, 0, 1), (0.5, 0.5, 0.5, 1)]])
-
-
-def test_buildPaletteLabels():
-    name_table = newTable("name")
-    name_table.names = []
-
-    name_ids = builder.buildPaletteLabels(
-        [None, "hi", {"en": "hello", "de": "hallo"}], name_table
-    )
-
-    assert name_ids == [0xFFFF, 256, 257]
-
-    assert len(name_table.names) == 3
-    assert str(name_table.names[0]) == "hi"
-    assert name_table.names[0].nameID == 256
-
-    assert str(name_table.names[1]) == "hallo"
-    assert name_table.names[1].nameID == 257
-
-    assert str(name_table.names[2]) == "hello"
-    assert name_table.names[2].nameID == 257
-
-
-def test_build_CPAL_v1_types_no_labels():
-    palettes = [
-        [(0.1, 0.2, 0.3, 1.0), (0.4, 0.5, 0.6, 1.0)],
-        [(0.1, 0.2, 0.3, 0.6), (0.4, 0.5, 0.6, 0.6)],
-        [(0.1, 0.2, 0.3, 0.3), (0.4, 0.5, 0.6, 0.3)],
-    ]
-    paletteTypes = [
-        builder.ColorPaletteType.USABLE_WITH_LIGHT_BACKGROUND,
-        builder.ColorPaletteType.USABLE_WITH_DARK_BACKGROUND,
-        builder.ColorPaletteType.USABLE_WITH_LIGHT_BACKGROUND
-        | builder.ColorPaletteType.USABLE_WITH_DARK_BACKGROUND,
-    ]
-
-    cpal = builder.buildCPAL(palettes, paletteTypes=paletteTypes)
-
-    assert cpal.tableTag == "CPAL"
-    assert cpal.version == 1
-    assert cpal.numPaletteEntries == 2
-    assert len(cpal.palettes) == 3
-
-    assert cpal.paletteTypes == paletteTypes
-    assert cpal.paletteLabels == [cpal.NO_NAME_ID] * len(palettes)
-    assert cpal.paletteEntryLabels == [cpal.NO_NAME_ID] * cpal.numPaletteEntries
-
-
-def test_build_CPAL_v1_labels():
-    palettes = [
-        [(0.1, 0.2, 0.3, 1.0), (0.4, 0.5, 0.6, 1.0)],
-        [(0.1, 0.2, 0.3, 0.6), (0.4, 0.5, 0.6, 0.6)],
-        [(0.1, 0.2, 0.3, 0.3), (0.4, 0.5, 0.6, 0.3)],
-    ]
-    paletteLabels = ["First", {"en": "Second", "it": "Seconda"}, None]
-    paletteEntryLabels = ["Foo", "Bar"]
-
-    with pytest.raises(TypeError, match="nameTable is required"):
-        builder.buildCPAL(palettes, paletteLabels=paletteLabels)
-    with pytest.raises(TypeError, match="nameTable is required"):
-        builder.buildCPAL(palettes, paletteEntryLabels=paletteEntryLabels)
-
-    name_table = newTable("name")
-    name_table.names = []
-
-    cpal = builder.buildCPAL(
-        palettes,
-        paletteLabels=paletteLabels,
-        paletteEntryLabels=paletteEntryLabels,
-        nameTable=name_table,
-    )
-
-    assert cpal.tableTag == "CPAL"
-    assert cpal.version == 1
-    assert cpal.numPaletteEntries == 2
-    assert len(cpal.palettes) == 3
-
-    assert cpal.paletteTypes == [cpal.DEFAULT_PALETTE_TYPE] * len(palettes)
-    assert cpal.paletteLabels == [256, 257, cpal.NO_NAME_ID]
-    assert cpal.paletteEntryLabels == [258, 259]
-
-    assert name_table.getDebugName(256) == "First"
-    assert name_table.getDebugName(257) == "Second"
-    assert name_table.getDebugName(258) == "Foo"
-    assert name_table.getDebugName(259) == "Bar"
-
-
-def test_invalid_ColorPaletteType():
-    with pytest.raises(ValueError, match="not a valid ColorPaletteType"):
-        builder.ColorPaletteType(-1)
-    with pytest.raises(ValueError, match="not a valid ColorPaletteType"):
-        builder.ColorPaletteType(4)
-    with pytest.raises(ValueError, match="not a valid ColorPaletteType"):
-        builder.ColorPaletteType("abc")
-
-
-def test_buildCPAL_v1_invalid_args_length():
-    with pytest.raises(ColorLibError, match="Expected 2 paletteTypes, got 1"):
-        builder.buildCPAL([[(0, 0, 0, 0)], [(1, 1, 1, 1)]], paletteTypes=[1])
-
-    with pytest.raises(ColorLibError, match="Expected 2 paletteLabels, got 1"):
-        builder.buildCPAL(
-            [[(0, 0, 0, 0)], [(1, 1, 1, 1)]],
-            paletteLabels=["foo"],
-            nameTable=newTable("name"),
-        )
-
-    with pytest.raises(ColorLibError, match="Expected 1 paletteEntryLabels, got 0"):
-        cpal = builder.buildCPAL(
-            [[(0, 0, 0, 0)], [(1, 1, 1, 1)]],
-            paletteEntryLabels=[],
-            nameTable=newTable("name"),
-        )
-
-
-def test_buildCPAL_invalid_color():
-    with pytest.raises(
-        ColorLibError,
-        match=r"In palette\[0\]\[1\]: expected \(R, G, B, A\) tuple, got \(1, 1, 1\)",
-    ):
-        builder.buildCPAL([[(1, 1, 1, 1), (1, 1, 1)]])
-
-    with pytest.raises(
-        ColorLibError,
-        match=(
-            r"palette\[1\]\[0\] has invalid out-of-range "
-            r"\[0..1\] color: \(1, 1, -1, 2\)"
-        ),
-    ):
-        builder.buildCPAL([[(0, 0, 0, 0)], [(1, 1, -1, 2)]])
-
-
-def test_buildColorIndex_Minimal():
-    c = _build(ot.ColorIndex, 1)
-    assert c.PaletteIndex == 1
-    assert c.Alpha == 1.0
-
-
-def test_buildVarColorIndex_Minimal():
-    c = _build(ot.VarColorIndex, 1)
-    assert c.PaletteIndex == 1
-    assert c.Alpha.value == 1.0
-    assert c.Alpha.varIdx == 0
-
-
-def test_buildColorIndex():
-    c = _build(ot.ColorIndex, (1, 0.5))
-    assert c.PaletteIndex == 1
-    assert c.Alpha == 0.5
-
-
-def test_buildVarColorIndex():
-    c = _build(ot.VarColorIndex, (3, builder.VariableFloat(0.5, varIdx=2)))
-    assert c.PaletteIndex == 3
-    assert c.Alpha.value == 0.5
-    assert c.Alpha.varIdx == 2
-
-
-def test_buildPaintSolid():
-    p = _buildPaint((ot.PaintFormat.PaintSolid, 0))
-    assert p.Format == ot.PaintFormat.PaintSolid
-    assert p.Color.PaletteIndex == 0
-    assert p.Color.Alpha == 1.0
-
-
-def test_buildPaintSolid_Alpha():
-    p = _buildPaint((ot.PaintFormat.PaintSolid, (1, 0.5)))
-    assert p.Format == ot.PaintFormat.PaintSolid
-    assert p.Color.PaletteIndex == 1
-    assert p.Color.Alpha == 0.5
-
-
-def test_buildPaintVarSolid():
-    p = _buildPaint(
-        (ot.PaintFormat.PaintVarSolid, (3, builder.VariableFloat(0.5, varIdx=2)))
-    )
-    assert p.Format == ot.PaintFormat.PaintVarSolid
-    assert p.Color.PaletteIndex == 3
-    assert p.Color.Alpha.value == 0.5
-    assert p.Color.Alpha.varIdx == 2
-
-
-def test_buildVarColorStop_DefaultAlpha():
-    s = _build(ot.ColorStop, (0.1, 2))
-    assert s.StopOffset == 0.1
-    assert s.Color.PaletteIndex == 2
-    assert s.Color.Alpha == builder._DEFAULT_ALPHA.value
-
-
-def test_buildVarColorStop_DefaultAlpha():
-    s = _build(ot.VarColorStop, (0.1, 2))
-    assert s.StopOffset == builder.VariableFloat(0.1)
-    assert s.Color.PaletteIndex == 2
-    assert s.Color.Alpha == builder._DEFAULT_ALPHA
-
-
-def test_buildColorStop():
-    s = _build(
-        ot.ColorStop, {"StopOffset": 0.2, "Color": {"PaletteIndex": 3, "Alpha": 0.4}}
-    )
-    assert s.StopOffset == 0.2
-    assert s.Color == _build(ot.ColorIndex, (3, 0.4))
-
-
-def test_buildColorStop_Variable():
-    s = _build(
-        ot.VarColorStop,
-        {
-            "StopOffset": builder.VariableFloat(0.0, varIdx=1),
-            "Color": {
-                "PaletteIndex": 0,
-                "Alpha": builder.VariableFloat(0.3, varIdx=2),
-            },
-        },
-    )
-    assert s.StopOffset == builder.VariableFloat(0.0, varIdx=1)
-    assert s.Color.PaletteIndex == 0
-    assert s.Color.Alpha == builder.VariableFloat(0.3, varIdx=2)
-
-
-def test_buildColorLine_StopList():
-    stops = [(0.0, 0), (0.5, 1), (1.0, 2)]
-
-    cline = _build(ot.ColorLine, {"ColorStop": stops})
-    assert cline.Extend == builder.ExtendMode.PAD
-    assert cline.StopCount == 3
-    assert [(cs.StopOffset, cs.Color.PaletteIndex) for cs in cline.ColorStop] == stops
-
-    cline = _build(ot.ColorLine, {"Extend": "pad", "ColorStop": stops})
-    assert cline.Extend == builder.ExtendMode.PAD
-
-    cline = _build(
-        ot.ColorLine, {"ColorStop": stops, "Extend": builder.ExtendMode.REPEAT}
-    )
-    assert cline.Extend == builder.ExtendMode.REPEAT
-
-    cline = _build(
-        ot.ColorLine, {"ColorStop": stops, "Extend": builder.ExtendMode.REFLECT}
-    )
-    assert cline.Extend == builder.ExtendMode.REFLECT
-
-    cline = _build(
-        ot.ColorLine, {"ColorStop": [_build(ot.ColorStop, s) for s in stops]}
-    )
-    assert [(cs.StopOffset, cs.Color.PaletteIndex) for cs in cline.ColorStop] == stops
-
-
-def test_buildVarColorLine_StopMap():
-    stops = [
-        {"StopOffset": (0.0, (1,)), "Color": {"PaletteIndex": 0, "Alpha": (0.5, 2)}},
-        {"StopOffset": (1.0, (3,)), "Color": {"PaletteIndex": 1, "Alpha": (0.3, 4)}},
-    ]
-    cline = _build(ot.VarColorLine, {"ColorStop": stops})
-    assert [
-        {
-            "StopOffset": cs.StopOffset,
-            "Color": {
-                "PaletteIndex": cs.Color.PaletteIndex,
-                "Alpha": cs.Color.Alpha,
-            },
-        }
-        for cs in cline.ColorStop
-    ] == stops
-
-
-def checkBuildAffine2x3(cls, resultMapFn):
-    matrix = _build(cls, (1.5, 0, 0.5, 2.0, 1.0, -3.0))
-    assert matrix.xx == resultMapFn(1.5)
-    assert matrix.yx == resultMapFn(0.0)
-    assert matrix.xy == resultMapFn(0.5)
-    assert matrix.yy == resultMapFn(2.0)
-    assert matrix.dx == resultMapFn(1.0)
-    assert matrix.dy == resultMapFn(-3.0)
-
-
-def test_buildAffine2x3():
-    checkBuildAffine2x3(ot.Affine2x3, lambda v: v)
-
-
-def test_buildVarAffine2x3():
-    checkBuildAffine2x3(ot.VarAffine2x3, builder.VariableFloat)
-
-
-def _sample_stops(cls):
-    return [
-        _build(cls, (0.0, 0)),
-        _build(cls, (0.5, 1)),
-        _build(cls, (1.0, (2, 0.8))),
-    ]
-
-
-def _is_var(fmt):
-    return fmt.name.startswith("PaintVar")
-
-
-def checkBuildPaintLinearGradient(fmt):
-    if _is_var(fmt):
-        inputMapFn = builder.VariableInt
-        outputMapFn = lambda v: v.value
-        color_stops = _sample_stops(ot.VarColorStop)
-    else:
-        inputMapFn = outputMapFn = lambda v: v
-        color_stops = _sample_stops(ot.ColorStop)
-
-    x0, y0, x1, y1, x2, y2 = tuple(inputMapFn(v) for v in (1, 2, 3, 4, 5, 6))
-    gradient = _buildPaint(
-        {
-            "Format": fmt,
-            "ColorLine": {"ColorStop": color_stops},
-            "x0": x0,
-            "y0": y0,
-            "x1": x1,
-            "y1": y1,
-            "x2": x2,
-            "y2": y2,
-        },
-    )
-    assert gradient.ColorLine.Extend == builder.ExtendMode.PAD
-    assert gradient.ColorLine.ColorStop == color_stops
-
-    gradient = _buildPaint(gradient)
-    assert (outputMapFn(gradient.x0), outputMapFn(gradient.y0)) == (1, 2)
-    assert (outputMapFn(gradient.x1), outputMapFn(gradient.y1)) == (3, 4)
-    assert (outputMapFn(gradient.x2), outputMapFn(gradient.y2)) == (5, 6)
-
-
-def test_buildPaintLinearGradient():
-    assert not _is_var(ot.PaintFormat.PaintLinearGradient)
-    checkBuildPaintLinearGradient(ot.PaintFormat.PaintLinearGradient)
-
-
-def test_buildVarPaintLinearGradient():
-    assert _is_var(ot.PaintFormat.PaintVarLinearGradient)
-    checkBuildPaintLinearGradient(ot.PaintFormat.PaintVarLinearGradient)
-
-
-def checkBuildPaintRadialGradient(fmt):
-    if _is_var(fmt):
-        inputMapFn = builder.VariableInt
-        outputMapFn = lambda v: v
-        color_stops = _sample_stops(ot.VarColorStop)
-        line_cls = ot.VarColorLine
-    else:
-        inputMapFn = outputMapFn = lambda v: v
-        color_stops = _sample_stops(ot.ColorStop)
-        line_cls = ot.ColorLine
-
-    color_line = _build(
-        line_cls, {"ColorStop": color_stops, "Extend": builder.ExtendMode.REPEAT}
-    )
-    c0 = (inputMapFn(100), inputMapFn(200))
-    c1 = (inputMapFn(150), inputMapFn(250))
-    r0 = inputMapFn(10)
-    r1 = inputMapFn(5)
-
-    gradient = _build(ot.Paint, (fmt, color_line, *c0, r0, *c1, r1))
-    assert gradient.Format == fmt
-    assert gradient.ColorLine == color_line
-    assert (outputMapFn(gradient.x0), outputMapFn(gradient.y0)) == c0
-    assert (outputMapFn(gradient.x1), outputMapFn(gradient.y1)) == c1
-    assert outputMapFn(gradient.r0) == r0
-    assert outputMapFn(gradient.r1) == r1
-
-    gradient = _build(
-        ot.Paint,
-        {
-            "Format": fmt,
-            "ColorLine": {"ColorStop": color_stops},
-            "x0": c0[0],
-            "y0": c0[1],
-            "x1": c1[0],
-            "y1": c1[1],
-            "r0": r0,
-            "r1": r1,
-        },
-    )
-    assert gradient.ColorLine.Extend == builder.ExtendMode.PAD
-    assert gradient.ColorLine.ColorStop == color_stops
-    assert (outputMapFn(gradient.x0), outputMapFn(gradient.y0)) == c0
-    assert (outputMapFn(gradient.x1), outputMapFn(gradient.y1)) == c1
-    assert outputMapFn(gradient.r0) == r0
-    assert outputMapFn(gradient.r1) == r1
-
-
-def test_buildPaintRadialGradient():
-    assert not _is_var(ot.PaintFormat.PaintRadialGradient)
-    checkBuildPaintRadialGradient(ot.PaintFormat.PaintRadialGradient)
-
-
-def test_buildPaintVarRadialGradient():
-    assert _is_var(ot.PaintFormat.PaintVarRadialGradient)
-    checkBuildPaintRadialGradient(ot.PaintFormat.PaintVarRadialGradient)
-
-
-def checkPaintSweepGradient(fmt):
-    if _is_var(fmt):
-        outputMapFn = lambda v: v.value
-    else:
-        outputMapFn = lambda v: v
-
-    paint = _buildPaint(
-        {
-            "Format": fmt,
-            "ColorLine": {
-                "ColorStop": (
-                    (0.0, 0),
-                    (0.5, 1),
-                    (1.0, (2, 0.8)),
-                )
-            },
-            "centerX": 127,
-            "centerY": 129,
-            "startAngle": 15,
-            "endAngle": 42,
-        }
-    )
-
-    assert paint.Format == fmt
-    assert outputMapFn(paint.centerX) == 127
-    assert outputMapFn(paint.centerY) == 129
-    assert outputMapFn(paint.startAngle) == 15
-    assert outputMapFn(paint.endAngle) == 42
-
-
-def test_buildPaintSweepGradient():
-    assert not _is_var(ot.PaintFormat.PaintSweepGradient)
-    checkPaintSweepGradient(ot.PaintFormat.PaintSweepGradient)
-
-
-def test_buildPaintVarSweepGradient():
-    assert _is_var(ot.PaintFormat.PaintVarSweepGradient)
-    checkPaintSweepGradient(ot.PaintFormat.PaintVarSweepGradient)
-
-
-def test_buildPaintGlyph_Solid():
-    layer = _build(
-        ot.Paint,
-        (
-            ot.PaintFormat.PaintGlyph,
-            (
-                ot.PaintFormat.PaintSolid,
-                2,
-            ),
-            "a",
-        ),
-    )
-    assert layer.Format == ot.PaintFormat.PaintGlyph
-    assert layer.Glyph == "a"
-    assert layer.Paint.Format == ot.PaintFormat.PaintSolid
-    assert layer.Paint.Color.PaletteIndex == 2
-
-    layer = _build(
-        ot.Paint,
-        (
-            ot.PaintFormat.PaintGlyph,
-            (
-                ot.PaintFormat.PaintSolid,
-                (3, 0.9),
-            ),
-            "a",
-        ),
-    )
-    assert layer.Paint.Format == ot.PaintFormat.PaintSolid
-    assert layer.Paint.Color.PaletteIndex == 3
-    assert layer.Paint.Color.Alpha == 0.9
-
-
-def test_buildPaintGlyph_VarLinearGradient():
-    layer = _build(
-        ot.Paint,
-        {
-            "Format": ot.PaintFormat.PaintGlyph,
-            "Glyph": "a",
-            "Paint": {
-                "Format": ot.PaintFormat.PaintVarLinearGradient,
-                "ColorLine": {"ColorStop": [(0.0, 3), (1.0, 4)]},
-                "x0": 100,
-                "y0": 200,
-                "x1": 150,
-                "y1": 250,
-            },
-        },
-    )
-
-    assert layer.Format == ot.PaintFormat.PaintGlyph
-    assert layer.Glyph == "a"
-    assert layer.Paint.Format == ot.PaintFormat.PaintVarLinearGradient
-    assert layer.Paint.ColorLine.ColorStop[0].StopOffset.value == 0.0
-    assert layer.Paint.ColorLine.ColorStop[0].Color.PaletteIndex == 3
-    assert layer.Paint.ColorLine.ColorStop[1].StopOffset.value == 1.0
-    assert layer.Paint.ColorLine.ColorStop[1].Color.PaletteIndex == 4
-    assert layer.Paint.x0.value == 100
-    assert layer.Paint.y0.value == 200
-    assert layer.Paint.x1.value == 150
-    assert layer.Paint.y1.value == 250
-
-
-def test_buildPaintGlyph_RadialGradient():
-    layer = _build(
-        ot.Paint,
-        (
-            int(ot.PaintFormat.PaintGlyph),
-            (
-                ot.PaintFormat.PaintRadialGradient,
-                (
-                    "pad",
-                    [
-                        (0.0, 5),
-                        {"StopOffset": 0.5, "Color": {"PaletteIndex": 6, "Alpha": 0.8}},
-                        (1.0, 7),
-                    ],
-                ),
-                50,
-                50,
-                30,
-                75,
-                75,
-                10,
-            ),
-            "a",
-        ),
-    )
-    assert layer.Format == ot.PaintFormat.PaintGlyph
-    assert layer.Paint.Format == ot.PaintFormat.PaintRadialGradient
-    assert layer.Paint.ColorLine.ColorStop[0].StopOffset == 0.0
-    assert layer.Paint.ColorLine.ColorStop[0].Color.PaletteIndex == 5
-    assert layer.Paint.ColorLine.ColorStop[1].StopOffset == 0.5
-    assert layer.Paint.ColorLine.ColorStop[1].Color.PaletteIndex == 6
-    assert layer.Paint.ColorLine.ColorStop[1].Color.Alpha == 0.8
-    assert layer.Paint.ColorLine.ColorStop[2].StopOffset == 1.0
-    assert layer.Paint.ColorLine.ColorStop[2].Color.PaletteIndex == 7
-    assert layer.Paint.x0 == 50
-    assert layer.Paint.y0 == 50
-    assert layer.Paint.r0 == 30
-    assert layer.Paint.x1 == 75
-    assert layer.Paint.y1 == 75
-    assert layer.Paint.r1 == 10
-
-
-def test_buildPaintGlyph_Dict_Solid():
-    layer = _build(
-        ot.Paint,
-        (
-            int(ot.PaintFormat.PaintGlyph),
-            (int(ot.PaintFormat.PaintSolid), 1),
-            "a",
-        ),
-    )
-    assert layer.Format == ot.PaintFormat.PaintGlyph
-    assert layer.Format == ot.PaintFormat.PaintGlyph
-    assert layer.Glyph == "a"
-    assert layer.Paint.Format == ot.PaintFormat.PaintSolid
-    assert layer.Paint.Color.PaletteIndex == 1
-
-
-def test_buildPaintGlyph_Dict_VarLinearGradient():
-    layer = _build(
-        ot.Paint,
-        {
-            "Format": ot.PaintFormat.PaintGlyph,
-            "Glyph": "a",
-            "Paint": {
-                "Format": int(ot.PaintFormat.PaintVarLinearGradient),
-                "ColorLine": {"ColorStop": [(0.0, 0), (1.0, 1)]},
-                "x0": 0,
-                "y0": 0,
-                "x1": 10,
-                "y1": 10,
-            },
-        },
-    )
-    assert layer.Format == ot.PaintFormat.PaintGlyph
-    assert layer.Glyph == "a"
-    assert layer.Paint.Format == ot.PaintFormat.PaintVarLinearGradient
-    assert layer.Paint.ColorLine.ColorStop[0].StopOffset.value == 0.0
-
-
-def test_buildPaintGlyph_Dict_RadialGradient():
-    layer = _buildPaint(
-        {
-            "Glyph": "a",
-            "Paint": {
-                "Format": int(ot.PaintFormat.PaintRadialGradient),
-                "ColorLine": {"ColorStop": [(0.0, 0), (1.0, 1)]},
-                "x0": 0,
-                "y0": 0,
-                "r0": 4,
-                "x1": 10,
-                "y1": 10,
-                "r1": 0,
-            },
-            "Format": int(ot.PaintFormat.PaintGlyph),
-        },
-    )
-    assert layer.Paint.Format == ot.PaintFormat.PaintRadialGradient
-    assert layer.Paint.r0 == 4
-
-
-def test_buildPaintColrGlyph():
-    paint = _buildPaint((int(ot.PaintFormat.PaintColrGlyph), "a"))
-    assert paint.Format == ot.PaintFormat.PaintColrGlyph
-    assert paint.Glyph == "a"
-
-
-def checkBuildPaintTransform(fmt):
-    if _is_var(fmt):
-        inputMapFn = builder.VariableFloat
-        outputMapFn = lambda v: v.value
-        affine_cls = ot.VarAffine2x3
-    else:
-        inputMapFn = outputMapFn = lambda v: v
-        affine_cls = ot.Affine2x3
-
-    paint = _buildPaint(
-        (
-            int(fmt),
-            (ot.PaintFormat.PaintGlyph, (ot.PaintFormat.PaintSolid, (0, 1.0)), "a"),
-            _build(affine_cls, (1, 2, 3, 4, 5, 6)),
-        ),
-    )
-
-    assert paint.Format == fmt
-    assert paint.Paint.Format == ot.PaintFormat.PaintGlyph
-    assert paint.Paint.Paint.Format == ot.PaintFormat.PaintSolid
-
-    assert outputMapFn(paint.Transform.xx) == 1.0
-    assert outputMapFn(paint.Transform.yx) == 2.0
-    assert outputMapFn(paint.Transform.xy) == 3.0
-    assert outputMapFn(paint.Transform.yy) == 4.0
-    assert outputMapFn(paint.Transform.dx) == 5.0
-    assert outputMapFn(paint.Transform.dy) == 6.0
-
-    paint = _build(
-        ot.Paint,
-        {
-            "Format": fmt,
-            "Transform": (1, 2, 3, 0.3333, 10, 10),
-            "Paint": {
-                "Format": int(ot.PaintFormat.PaintRadialGradient),
-                "ColorLine": {"ColorStop": [(0.0, 0), (1.0, 1)]},
-                "x0": 100,
-                "y0": 101,
-                "x1": 102,
-                "y1": 103,
-                "r0": 0,
-                "r1": 50,
-            },
-        },
-    )
-
-    assert paint.Format == fmt
-    assert outputMapFn(paint.Transform.xx) == 1.0
-    assert outputMapFn(paint.Transform.yx) == 2.0
-    assert outputMapFn(paint.Transform.xy) == 3.0
-    assert outputMapFn(paint.Transform.yy) == 0.3333
-    assert outputMapFn(paint.Transform.dx) == 10
-    assert outputMapFn(paint.Transform.dy) == 10
-    assert paint.Paint.Format == ot.PaintFormat.PaintRadialGradient
-
-
-def test_buildPaintTransform():
-    assert not _is_var(ot.PaintFormat.PaintTransform)
-    checkBuildPaintTransform(ot.PaintFormat.PaintTransform)
-
-
-def test_buildPaintVarTransform():
-    assert _is_var(ot.PaintFormat.PaintVarTransform)
-    checkBuildPaintTransform(ot.PaintFormat.PaintVarTransform)
-
-
-def test_buildPaintComposite():
-    composite = _build(
-        ot.Paint,
-        {
-            "Format": int(ot.PaintFormat.PaintComposite),
-            "CompositeMode": "src_over",
-            "SourcePaint": {
-                "Format": ot.PaintFormat.PaintComposite,
-                "CompositeMode": "src_over",
-                "SourcePaint": {
-                    "Format": int(ot.PaintFormat.PaintGlyph),
-                    "Glyph": "c",
-                    "Paint": (ot.PaintFormat.PaintSolid, 2),
-                },
-                "BackdropPaint": {
-                    "Format": int(ot.PaintFormat.PaintGlyph),
-                    "Glyph": "b",
-                    "Paint": (ot.PaintFormat.PaintSolid, 1),
-                },
-            },
-            "BackdropPaint": {
-                "Format": ot.PaintFormat.PaintGlyph,
-                "Glyph": "a",
-                "Paint": {
-                    "Format": ot.PaintFormat.PaintSolid,
-                    "Color": (0, 1.0),
-                },
-            },
-        },
-    )
-
-    assert composite.Format == ot.PaintFormat.PaintComposite
-    assert composite.SourcePaint.Format == ot.PaintFormat.PaintComposite
-    assert composite.SourcePaint.SourcePaint.Format == ot.PaintFormat.PaintGlyph
-    assert composite.SourcePaint.SourcePaint.Glyph == "c"
-    assert composite.SourcePaint.SourcePaint.Paint.Format == ot.PaintFormat.PaintSolid
-    assert composite.SourcePaint.SourcePaint.Paint.Color.PaletteIndex == 2
-    assert composite.SourcePaint.CompositeMode == ot.CompositeMode.SRC_OVER
-    assert composite.SourcePaint.BackdropPaint.Format == ot.PaintFormat.PaintGlyph
-    assert composite.SourcePaint.BackdropPaint.Glyph == "b"
-    assert composite.SourcePaint.BackdropPaint.Paint.Format == ot.PaintFormat.PaintSolid
-    assert composite.SourcePaint.BackdropPaint.Paint.Color.PaletteIndex == 1
-    assert composite.CompositeMode == ot.CompositeMode.SRC_OVER
-    assert composite.BackdropPaint.Format == ot.PaintFormat.PaintGlyph
-    assert composite.BackdropPaint.Glyph == "a"
-    assert composite.BackdropPaint.Paint.Format == ot.PaintFormat.PaintSolid
-    assert composite.BackdropPaint.Paint.Color.PaletteIndex == 0
-
-
-def checkBuildPaintTranslate(fmt):
-    if _is_var(fmt):
-        inputMapFn = builder.VariableInt
-        outputMapFn = lambda v: v.value
-    else:
-        inputMapFn = outputMapFn = lambda v: v
-
-    paint = _build(
-        ot.Paint,
-        {
-            "Format": fmt,
-            "Paint": (
-                ot.PaintFormat.PaintGlyph,
-                (ot.PaintFormat.PaintSolid, (0, 1.0)),
-                "a",
-            ),
-            "dx": 123,
-            "dy": -345,
-        },
-    )
-
-    assert paint.Format == fmt
-    assert paint.Paint.Format == ot.PaintFormat.PaintGlyph
-    assert outputMapFn(paint.dx) == 123
-    assert outputMapFn(paint.dy) == -345
-
-
-def test_buildPaintTranslate():
-    assert not _is_var(ot.PaintFormat.PaintTranslate)
-    checkBuildPaintTranslate(ot.PaintFormat.PaintTranslate)
-
-
-def test_buildPaintVarTranslate():
-    assert _is_var(ot.PaintFormat.PaintVarTranslate)
-    checkBuildPaintTranslate(ot.PaintFormat.PaintVarTranslate)
-
-
-def checkBuildPaintRotate(fmt):
-    if _is_var(fmt):
-        inputMapFn = builder.VariableInt
-        outputMapFn = lambda v: v.value
-    else:
-        inputMapFn = outputMapFn = lambda v: v
-
-    paint = _build(
-        ot.Paint,
-        {
-            "Format": fmt,
-            "Paint": (
-                ot.PaintFormat.PaintGlyph,
-                (ot.PaintFormat.PaintSolid, (0, 1.0)),
-                "a",
-            ),
-            "angle": 15,
-            "centerX": 127,
-            "centerY": 129,
-        },
-    )
-
-    assert paint.Format == fmt
-    assert paint.Paint.Format == ot.PaintFormat.PaintGlyph
-    assert outputMapFn(paint.angle) == 15
-    assert outputMapFn(paint.centerX) == 127
-    assert outputMapFn(paint.centerY) == 129
-
-
-def test_buildPaintRotate():
-    assert not _is_var(ot.PaintFormat.PaintRotate)
-    checkBuildPaintRotate(ot.PaintFormat.PaintRotate)
-
-
-def test_buildPaintVarRotate():
-    assert _is_var(ot.PaintFormat.PaintVarRotate)
-    checkBuildPaintRotate(ot.PaintFormat.PaintVarRotate)
-
-
-def checkBuildPaintSkew(fmt):
-    if _is_var(fmt):
-        inputMapFn = builder.VariableInt
-        outputMapFn = lambda v: v.value
-    else:
-        inputMapFn = outputMapFn = lambda v: v
-
-    paint = _build(
-        ot.Paint,
-        {
-            "Format": fmt,
-            "Paint": (
-                ot.PaintFormat.PaintGlyph,
-                (ot.PaintFormat.PaintSolid, (0, 1.0)),
-                "a",
-            ),
-            "xSkewAngle": 15,
-            "ySkewAngle": 42,
-            "centerX": 127,
-            "centerY": 129,
-        },
-    )
-
-    assert paint.Format == fmt
-    assert paint.Paint.Format == ot.PaintFormat.PaintGlyph
-    assert outputMapFn(paint.xSkewAngle) == 15
-    assert outputMapFn(paint.ySkewAngle) == 42
-    assert outputMapFn(paint.centerX) == 127
-    assert outputMapFn(paint.centerY) == 129
-
-
-def test_buildPaintSkew():
-    assert not _is_var(ot.PaintFormat.PaintSkew)
-    checkBuildPaintSkew(ot.PaintFormat.PaintSkew)
-
-
-def test_buildPaintVarSkew():
-    assert _is_var(ot.PaintFormat.PaintVarSkew)
-    checkBuildPaintSkew(ot.PaintFormat.PaintVarSkew)
-
-
-def test_buildColrV1():
-    colorGlyphs = {
-        "a": (
-            ot.PaintFormat.PaintColrLayers,
-            [
-                (ot.PaintFormat.PaintGlyph, (ot.PaintFormat.PaintSolid, 0), "b"),
-                (ot.PaintFormat.PaintGlyph, (ot.PaintFormat.PaintVarSolid, 1), "c"),
-            ],
-        ),
-        "d": (
-            ot.PaintFormat.PaintColrLayers,
-            [
-                (
-                    ot.PaintFormat.PaintGlyph,
-                    {
-                        "Format": int(ot.PaintFormat.PaintSolid),
-                        "Color": {"PaletteIndex": 2, "Alpha": 0.8},
-                    },
-                    "e",
-                ),
-                (
-                    ot.PaintFormat.PaintGlyph,
-                    {
-                        "Format": int(ot.PaintFormat.PaintVarRadialGradient),
-                        "ColorLine": {
-                            "ColorStop": [(0.0, 3), (1.0, 4)],
-                            "Extend": "reflect",
-                        },
-                        "x0": 0,
-                        "y0": 0,
-                        "x1": 0,
-                        "y1": 0,
-                        "r0": 10,
-                        "r1": 0,
-                    },
-                    "f",
-                ),
-            ],
-        ),
-        "g": (
-            ot.PaintFormat.PaintColrLayers,
-            [(ot.PaintFormat.PaintGlyph, (ot.PaintFormat.PaintSolid, 5), "h")],
-        ),
-    }
-    glyphMap = {
-        ".notdef": 0,
-        "a": 4,
-        "b": 3,
-        "c": 2,
-        "d": 1,
-        "e": 5,
-        "f": 6,
-        "g": 7,
-        "h": 8,
-    }
-
-    # TODO(anthrotype) should we split into two tests? - seems two distinct validations
-    layers, baseGlyphs = builder.buildColrV1(colorGlyphs, glyphMap)
-    assert baseGlyphs.BaseGlyphCount == len(colorGlyphs)
-    assert baseGlyphs.BaseGlyphV1Record[0].BaseGlyph == "d"
-    assert baseGlyphs.BaseGlyphV1Record[1].BaseGlyph == "a"
-    assert baseGlyphs.BaseGlyphV1Record[2].BaseGlyph == "g"
-
-    layers, baseGlyphs = builder.buildColrV1(colorGlyphs)
-    assert baseGlyphs.BaseGlyphCount == len(colorGlyphs)
-    assert baseGlyphs.BaseGlyphV1Record[0].BaseGlyph == "a"
-    assert baseGlyphs.BaseGlyphV1Record[1].BaseGlyph == "d"
-    assert baseGlyphs.BaseGlyphV1Record[2].BaseGlyph == "g"
-
-
-def test_buildColrV1_more_than_255_paints():
-    num_paints = 364
-    colorGlyphs = {
-        "a": (
-            ot.PaintFormat.PaintColrLayers,
-            [
-                {
-                    "Format": int(ot.PaintFormat.PaintGlyph),
-                    "Paint": (ot.PaintFormat.PaintSolid, 0),
-                    "Glyph": name,
-                }
-                for name in (f"glyph{i}" for i in range(num_paints))
-            ],
-        ),
-    }
-    layers, baseGlyphs = builder.buildColrV1(colorGlyphs)
-    paints = layers.Paint
-
-    assert len(paints) == num_paints + 1
-
-    assert all(paints[i].Format == ot.PaintFormat.PaintGlyph for i in range(255))
-
-    assert paints[255].Format == ot.PaintFormat.PaintColrLayers
-    assert paints[255].FirstLayerIndex == 0
-    assert paints[255].NumLayers == 255
-
-    assert all(
-        paints[i].Format == ot.PaintFormat.PaintGlyph
-        for i in range(256, num_paints + 1)
-    )
-
-    assert baseGlyphs.BaseGlyphCount == len(colorGlyphs)
-    assert baseGlyphs.BaseGlyphV1Record[0].BaseGlyph == "a"
-    assert (
-        baseGlyphs.BaseGlyphV1Record[0].Paint.Format == ot.PaintFormat.PaintColrLayers
-    )
-    assert baseGlyphs.BaseGlyphV1Record[0].Paint.FirstLayerIndex == 255
-    assert baseGlyphs.BaseGlyphV1Record[0].Paint.NumLayers == num_paints + 1 - 255
-
-
-def test_split_color_glyphs_by_version():
-    layerBuilder = LayerV1ListBuilder()
-    colorGlyphs = {
-        "a": [
-            ("b", 0),
-            ("c", 1),
-            ("d", 2),
-            ("e", 3),
-        ]
-    }
-
-    colorGlyphsV0, colorGlyphsV1 = builder._split_color_glyphs_by_version(colorGlyphs)
-
-    assert colorGlyphsV0 == {"a": [("b", 0), ("c", 1), ("d", 2), ("e", 3)]}
-    assert not colorGlyphsV1
-
-    colorGlyphs = {"a": (ot.PaintFormat.PaintGlyph, 0, "b")}
-
-    colorGlyphsV0, colorGlyphsV1 = builder._split_color_glyphs_by_version(colorGlyphs)
-
-    assert not colorGlyphsV0
-    assert colorGlyphsV1 == colorGlyphs
-
-    colorGlyphs = {
-        "a": [("b", 0)],
-        "c": [
-            ("d", 1),
-            (
-                "e",
-                {
-                    "format": 3,
-                    "colorLine": {"stops": [(0.0, 2), (1.0, 3)]},
-                    "p0": (0, 0),
-                    "p1": (10, 10),
-                },
-            ),
-        ],
-    }
-
-    colorGlyphsV0, colorGlyphsV1 = builder._split_color_glyphs_by_version(colorGlyphs)
-
-    assert colorGlyphsV0 == {"a": [("b", 0)]}
-    assert "a" not in colorGlyphsV1
-    assert "c" in colorGlyphsV1
-    assert len(colorGlyphsV1["c"]) == 2
-
-
-def assertIsColrV1(colr):
-    assert colr.version == 1
-    assert not hasattr(colr, "ColorLayers")
-    assert hasattr(colr, "table")
-    assert isinstance(colr.table, ot.COLR)
-
-
-def assertNoV0Content(colr):
-    assert colr.table.BaseGlyphRecordCount == 0
-    assert colr.table.BaseGlyphRecordArray is None
-    assert colr.table.LayerRecordCount == 0
-    assert colr.table.LayerRecordArray is None
-
-
-def test_build_layerv1list_empty():
-    # Nobody uses PaintColrLayers, no layerlist
-    colr = builder.buildCOLR(
-        {
-            # BaseGlyph, tuple form
-            "a": (
-                int(ot.PaintFormat.PaintGlyph),
-                (2, (2, 0.8)),
-                "b",
-            ),
-            # BaseGlyph, map form
-            "b": {
-                "Format": int(ot.PaintFormat.PaintGlyph),
-                "Paint": {
-                    "Format": int(ot.PaintFormat.PaintLinearGradient),
-                    "ColorLine": {
-                        "ColorStop": [(0.0, 2), (1.0, 3)],
-                        "Extend": "reflect",
-                    },
-                    "x0": 1,
-                    "y0": 2,
-                    "x1": 3,
-                    "y1": 4,
-                    "x2": 2,
-                    "y2": 2,
-                },
-                "Glyph": "bb",
-            },
-        },
-        version=1,
-    )
-
-    assertIsColrV1(colr)
-    assertNoV0Content(colr)
-
-    # 2 v1 glyphs, none in LayerV1List
-    assert colr.table.BaseGlyphV1List.BaseGlyphCount == 2
-    assert len(colr.table.BaseGlyphV1List.BaseGlyphV1Record) == 2
-    assert colr.table.LayerV1List.LayerCount == 0
-    assert len(colr.table.LayerV1List.Paint) == 0
-
-
-def _paint_names(paints) -> List[str]:
-    # prints a predictable string from a paint list to enable
-    # semi-readable assertions on a LayerV1List order.
-    result = []
-    for paint in paints:
-        if paint.Format == int(ot.PaintFormat.PaintGlyph):
-            result.append(paint.Glyph)
-        elif paint.Format == int(ot.PaintFormat.PaintColrLayers):
-            result.append(
-                f"Layers[{paint.FirstLayerIndex}:{paint.FirstLayerIndex+paint.NumLayers}]"
-            )
-    return result
-
-
-def test_build_layerv1list_simple():
-    # Two colr glyphs, each with two layers the first of which is common
-    # All layers use the same solid paint
-    solid_paint = {"Format": 2, "Color": {"PaletteIndex": 2, "Alpha": 0.8}}
-    backdrop = {
-        "Format": int(ot.PaintFormat.PaintGlyph),
-        "Paint": solid_paint,
-        "Glyph": "back",
-    }
-    a_foreground = {
-        "Format": int(ot.PaintFormat.PaintGlyph),
-        "Paint": solid_paint,
-        "Glyph": "a_fore",
-    }
-    b_foreground = {
-        "Format": int(ot.PaintFormat.PaintGlyph),
-        "Paint": solid_paint,
-        "Glyph": "b_fore",
-    }
-
-    # list => PaintColrLayers, contents should land in LayerV1List
-    colr = builder.buildCOLR(
-        {
-            "a": (
-                ot.PaintFormat.PaintColrLayers,
-                [
-                    backdrop,
-                    a_foreground,
-                ],
-            ),
-            "b": {
-                "Format": ot.PaintFormat.PaintColrLayers,
-                "Layers": [
-                    backdrop,
-                    b_foreground,
-                ],
-            },
-        },
-        version=1,
-    )
-
-    assertIsColrV1(colr)
-    assertNoV0Content(colr)
-
-    # 2 v1 glyphs, 4 paints in LayerV1List
-    # A single shared backdrop isn't worth accessing by slice
-    assert colr.table.BaseGlyphV1List.BaseGlyphCount == 2
-    assert len(colr.table.BaseGlyphV1List.BaseGlyphV1Record) == 2
-    assert colr.table.LayerV1List.LayerCount == 4
-    assert _paint_names(colr.table.LayerV1List.Paint) == [
-        "back",
-        "a_fore",
-        "back",
-        "b_fore",
-    ]
-
-
-def test_build_layerv1list_with_sharing():
-    # Three colr glyphs, each with two layers in common
-    solid_paint = {"Format": 2, "Color": (2, 0.8)}
-    backdrop = [
-        {
-            "Format": int(ot.PaintFormat.PaintGlyph),
-            "Paint": solid_paint,
-            "Glyph": "back1",
-        },
-        {
-            "Format": ot.PaintFormat.PaintGlyph,
-            "Paint": solid_paint,
-            "Glyph": "back2",
-        },
-    ]
-    a_foreground = {
-        "Format": ot.PaintFormat.PaintGlyph,
-        "Paint": solid_paint,
-        "Glyph": "a_fore",
-    }
-    b_background = {
-        "Format": ot.PaintFormat.PaintGlyph,
-        "Paint": solid_paint,
-        "Glyph": "b_back",
-    }
-    b_foreground = {
-        "Format": ot.PaintFormat.PaintGlyph,
-        "Paint": solid_paint,
-        "Glyph": "b_fore",
-    }
-    c_background = {
-        "Format": ot.PaintFormat.PaintGlyph,
-        "Paint": solid_paint,
-        "Glyph": "c_back",
-    }
-
-    # list => PaintColrLayers, which means contents should be in LayerV1List
-    colr = builder.buildCOLR(
-        {
-            "a": (ot.PaintFormat.PaintColrLayers, backdrop + [a_foreground]),
-            "b": (
-                ot.PaintFormat.PaintColrLayers,
-                [b_background] + backdrop + [b_foreground],
-            ),
-            "c": (ot.PaintFormat.PaintColrLayers, [c_background] + backdrop),
-        },
-        version=1,
-    )
-
-    assertIsColrV1(colr)
-    assertNoV0Content(colr)
-
-    # 2 v1 glyphs, 4 paints in LayerV1List
-    # A single shared backdrop isn't worth accessing by slice
-    baseGlyphs = colr.table.BaseGlyphV1List.BaseGlyphV1Record
-    assert colr.table.BaseGlyphV1List.BaseGlyphCount == 3
-    assert len(baseGlyphs) == 3
-    assert _paint_names([b.Paint for b in baseGlyphs]) == [
-        "Layers[0:3]",
-        "Layers[3:6]",
-        "Layers[6:8]",
-    ]
-    assert _paint_names(colr.table.LayerV1List.Paint) == [
-        "back1",
-        "back2",
-        "a_fore",
-        "b_back",
-        "Layers[0:2]",
-        "b_fore",
-        "c_back",
-        "Layers[0:2]",
-    ]
-    assert colr.table.LayerV1List.LayerCount == 8
-
-
-def test_build_layerv1list_with_overlaps():
-    paints = [
-        {
-            "Format": ot.PaintFormat.PaintGlyph,
-            "Paint": {
-                "Format": ot.PaintFormat.PaintSolid,
-                "Color": {"PaletteIndex": 2, "Alpha": 0.8},
-            },
-            "Glyph": c,
-        }
-        for c in "abcdefghi"
-    ]
-
-    # list => PaintColrLayers, which means contents should be in LayerV1List
-    colr = builder.buildCOLR(
-        {
-            "a": (ot.PaintFormat.PaintColrLayers, paints[0:4]),
-            "b": (ot.PaintFormat.PaintColrLayers, paints[0:6]),
-            "c": (ot.PaintFormat.PaintColrLayers, paints[2:8]),
-        },
-        version=1,
-    )
-
-    assertIsColrV1(colr)
-    assertNoV0Content(colr)
-
-    baseGlyphs = colr.table.BaseGlyphV1List.BaseGlyphV1Record
-    # assert colr.table.BaseGlyphV1List.BaseGlyphCount == 2
-
-    assert _paint_names(colr.table.LayerV1List.Paint) == [
-        "a",
-        "b",
-        "c",
-        "d",
-        "Layers[0:4]",
-        "e",
-        "f",
-        "Layers[2:4]",
-        "Layers[5:7]",
-        "g",
-        "h",
-    ]
-    assert _paint_names([b.Paint for b in baseGlyphs]) == [
-        "Layers[0:4]",
-        "Layers[4:7]",
-        "Layers[7:11]",
-    ]
-    assert colr.table.LayerV1List.LayerCount == 11
-
-
-def test_explicit_version_1():
-    colr = builder.buildCOLR(
-        {
-            "a": (
-                ot.PaintFormat.PaintColrLayers,
-                [
-                    (ot.PaintFormat.PaintGlyph, (ot.PaintFormat.PaintSolid, 0), "b"),
-                    (ot.PaintFormat.PaintGlyph, (ot.PaintFormat.PaintSolid, 1), "c"),
-                ],
-            )
-        },
-        version=1,
-    )
-    assert colr.version == 1
-    assert not hasattr(colr, "ColorLayers")
-    assert hasattr(colr, "table")
-    assert isinstance(colr.table, ot.COLR)
-    assert colr.table.VarStore is None
-
-
-class BuildCOLRTest(object):
-    def test_automatic_version_all_solid_color_glyphs(self):
-        colr = builder.buildCOLR({"a": [("b", 0), ("c", 1)]})
-        assert colr.version == 0
-        assert hasattr(colr, "ColorLayers")
-        assert colr.ColorLayers["a"][0].name == "b"
-        assert colr.ColorLayers["a"][1].name == "c"
-
-    def test_automatic_version_no_solid_color_glyphs(self):
-        colr = builder.buildCOLR(
-            {
-                "a": (
-                    ot.PaintFormat.PaintColrLayers,
-                    [
-                        (
-                            ot.PaintFormat.PaintGlyph,
-                            {
-                                "Format": int(ot.PaintFormat.PaintRadialGradient),
-                                "ColorLine": {
-                                    "ColorStop": [(0.0, 0), (1.0, 1)],
-                                    "Extend": "repeat",
-                                },
-                                "x0": 1,
-                                "y0": 0,
-                                "x1": 10,
-                                "y1": 0,
-                                "r0": 4,
-                                "r1": 2,
-                            },
-                            "b",
-                        ),
-                        (
-                            ot.PaintFormat.PaintGlyph,
-                            {"Format": 2, "Color": {"PaletteIndex": 2, "Alpha": 0.8}},
-                            "c",
-                        ),
-                    ],
-                ),
-                "d": (
-                    ot.PaintFormat.PaintColrLayers,
-                    [
-                        {
-                            "Format": ot.PaintFormat.PaintGlyph,
-                            "Glyph": "e",
-                            "Paint": {
-                                "Format": ot.PaintFormat.PaintLinearGradient,
-                                "ColorLine": {
-                                    "ColorStop": [(0.0, 2), (1.0, 3)],
-                                    "Extend": "reflect",
-                                },
-                                "x0": 1,
-                                "y0": 2,
-                                "x1": 3,
-                                "y1": 4,
-                                "x2": 2,
-                                "y2": 2,
-                            },
-                        }
-                    ],
-                ),
-            }
-        )
-        assertIsColrV1(colr)
-        assert colr.table.BaseGlyphRecordCount == 0
-        assert colr.table.BaseGlyphRecordArray is None
-        assert colr.table.LayerRecordCount == 0
-        assert colr.table.LayerRecordArray is None
-
-    def test_automatic_version_mixed_solid_and_gradient_glyphs(self):
-        colr = builder.buildCOLR(
-            {
-                "a": [("b", 0), ("c", 1)],
-                "d": (
-                    ot.PaintFormat.PaintColrLayers,
-                    [
-                        (
-                            ot.PaintFormat.PaintGlyph,
-                            {
-                                "Format": ot.PaintFormat.PaintLinearGradient,
-                                "ColorLine": {"ColorStop": [(0.0, 2), (1.0, 3)]},
-                                "x0": 1,
-                                "y0": 2,
-                                "x1": 3,
-                                "y1": 4,
-                                "x2": 2,
-                                "y2": 2,
-                            },
-                            "e",
-                        ),
-                        (
-                            ot.PaintFormat.PaintGlyph,
-                            (ot.PaintFormat.PaintSolid, (2, 0.8)),
-                            "f",
-                        ),
-                    ],
-                ),
-            }
-        )
-        assertIsColrV1(colr)
-        assert colr.table.VarStore is None
-
-        assert colr.table.BaseGlyphRecordCount == 1
-        assert isinstance(colr.table.BaseGlyphRecordArray, ot.BaseGlyphRecordArray)
-        assert colr.table.LayerRecordCount == 2
-        assert isinstance(colr.table.LayerRecordArray, ot.LayerRecordArray)
-
-        assert isinstance(colr.table.BaseGlyphV1List, ot.BaseGlyphV1List)
-        assert colr.table.BaseGlyphV1List.BaseGlyphCount == 1
-        assert isinstance(
-            colr.table.BaseGlyphV1List.BaseGlyphV1Record[0], ot.BaseGlyphV1Record
-        )
-        assert colr.table.BaseGlyphV1List.BaseGlyphV1Record[0].BaseGlyph == "d"
-        assert isinstance(colr.table.LayerV1List, ot.LayerV1List)
-        assert colr.table.LayerV1List.Paint[0].Glyph == "e"
-
-    def test_explicit_version_0(self):
-        colr = builder.buildCOLR({"a": [("b", 0), ("c", 1)]}, version=0)
-        assert colr.version == 0
-        assert hasattr(colr, "ColorLayers")
-
-    def test_explicit_version_1(self):
-        colr = builder.buildCOLR(
-            {
-                "a": (
-                    ot.PaintFormat.PaintColrLayers,
-                    [
-                        (
-                            ot.PaintFormat.PaintGlyph,
-                            (ot.PaintFormat.PaintSolid, 0),
-                            "b",
-                        ),
-                        (
-                            ot.PaintFormat.PaintGlyph,
-                            (ot.PaintFormat.PaintSolid, 1),
-                            "c",
-                        ),
-                    ],
-                )
-            },
-            version=1,
-        )
-        assert colr.version == 1
-        assert not hasattr(colr, "ColorLayers")
-        assert hasattr(colr, "table")
-        assert isinstance(colr.table, ot.COLR)
-        assert colr.table.VarStore is None
-
-    def test_paint_one_colr_layers(self):
-        # A set of one layers should flip to just that layer
-        colr = builder.buildCOLR(
-            {
-                "a": (
-                    ot.PaintFormat.PaintColrLayers,
-                    [
-                        (
-                            ot.PaintFormat.PaintGlyph,
-                            (ot.PaintFormat.PaintSolid, 0),
-                            "b",
-                        ),
-                    ],
-                )
-            },
-        )
-
-        assert len(colr.table.LayerV1List.Paint) == 0, "PaintColrLayers should be gone"
-        assert colr.table.BaseGlyphV1List.BaseGlyphCount == 1
-        paint = colr.table.BaseGlyphV1List.BaseGlyphV1Record[0].Paint
-        assert paint.Format == ot.PaintFormat.PaintGlyph
-        assert paint.Paint.Format == ot.PaintFormat.PaintSolid
-
-
-class TrickyRadialGradientTest:
-    @staticmethod
-    def circle_inside_circle(c0, r0, c1, r1, rounded=False):
-        if rounded:
-            return Circle(c0, r0).round().inside(Circle(c1, r1).round())
-        else:
-            return Circle(c0, r0).inside(Circle(c1, r1))
-
-    def round_start_circle(self, c0, r0, c1, r1, inside=True):
-        assert self.circle_inside_circle(c0, r0, c1, r1) is inside
-        assert self.circle_inside_circle(c0, r0, c1, r1, rounded=True) is not inside
-        r = round_start_circle_stable_containment(c0, r0, c1, r1)
-        assert (
-            self.circle_inside_circle(r.centre, r.radius, c1, r1, rounded=True)
-            is inside
-        )
-        return r.centre, r.radius
-
-    def test_noto_emoji_mosquito_u1f99f(self):
-        # https://github.com/googlefonts/picosvg/issues/158
-        c0 = (385.23508, 70.56727999999998)
-        r0 = 0
-        c1 = (642.99108, 104.70327999999995)
-        r1 = 260.0072
-        assert self.round_start_circle(c0, r0, c1, r1, inside=True) == ((386, 71), 0)
-
-    @pytest.mark.parametrize(
-        "c0, r0, c1, r1, inside, expected",
-        [
-            # inside before round, outside after round
-            ((1.4, 0), 0, (2.6, 0), 1.3, True, ((2, 0), 0)),
-            ((1, 0), 0.6, (2.8, 0), 2.45, True, ((2, 0), 1)),
-            ((6.49, 6.49), 0, (0.49, 0.49), 8.49, True, ((5, 5), 0)),
-            # outside before round, inside after round
-            ((0, 0), 0, (2, 0), 1.5, False, ((-1, 0), 0)),
-            ((0, -0.5), 0, (0, -2.5), 1.5, False, ((0, 1), 0)),
-            # the following ones require two nudges to round correctly
-            ((0.5, 0), 0, (9.4, 0), 8.8, False, ((-1, 0), 0)),
-            ((1.5, 1.5), 0, (0.49, 0.49), 1.49, True, ((0, 0), 0)),
-            # limit case when circle almost exactly overlap
-            ((0.5000001, 0), 0.5000001, (0.499999, 0), 0.4999999, True, ((0, 0), 0)),
-            # concentrical circles, r0 > r1
-            ((0, 0), 1.49, (0, 0), 1, False, ((0, 0), 2)),
-        ],
-    )
-    def test_nudge_start_circle_position(self, c0, r0, c1, r1, inside, expected):
-        assert self.round_start_circle(c0, r0, c1, r1, inside) == expected
-
-
-@pytest.mark.parametrize(
-    "lst, n, expected",
-    [
-        ([0], 2, [0]),
-        ([0, 1], 2, [0, 1]),
-        ([0, 1, 2], 2, [[0, 1], 2]),
-        ([0, 1, 2], 3, [0, 1, 2]),
-        ([0, 1, 2, 3], 2, [[0, 1], [2, 3]]),
-        ([0, 1, 2, 3], 3, [[0, 1, 2], 3]),
-        ([0, 1, 2, 3, 4], 3, [[0, 1, 2], 3, 4]),
-        ([0, 1, 2, 3, 4, 5], 3, [[0, 1, 2], [3, 4, 5]]),
-        (list(range(7)), 3, [[0, 1, 2], [3, 4, 5], 6]),
-        (list(range(8)), 3, [[0, 1, 2], [3, 4, 5], [6, 7]]),
-        (list(range(9)), 3, [[0, 1, 2], [3, 4, 5], [6, 7, 8]]),
-        (list(range(10)), 3, [[[0, 1, 2], [3, 4, 5], [6, 7, 8]], 9]),
-        (list(range(11)), 3, [[[0, 1, 2], [3, 4, 5], [6, 7, 8]], 9, 10]),
-        (list(range(12)), 3, [[[0, 1, 2], [3, 4, 5], [6, 7, 8]], [9, 10, 11]]),
-        (list(range(13)), 3, [[[0, 1, 2], [3, 4, 5], [6, 7, 8]], [9, 10, 11], 12]),
-        (
-            list(range(14)),
-            3,
-            [[[0, 1, 2], [3, 4, 5], [6, 7, 8]], [[9, 10, 11], 12, 13]],
-        ),
-        (
-            list(range(15)),
-            3,
-            [[[0, 1, 2], [3, 4, 5], [6, 7, 8]], [9, 10, 11], [12, 13, 14]],
-        ),
-        (
-            list(range(16)),
-            3,
-            [[[0, 1, 2], [3, 4, 5], [6, 7, 8]], [[9, 10, 11], [12, 13, 14], 15]],
-        ),
-        (
-            list(range(23)),
-            3,
-            [
-                [[0, 1, 2], [3, 4, 5], [6, 7, 8]],
-                [[9, 10, 11], [12, 13, 14], [15, 16, 17]],
-                [[18, 19, 20], 21, 22],
-            ],
-        ),
-        (
-            list(range(27)),
-            3,
-            [
-                [[0, 1, 2], [3, 4, 5], [6, 7, 8]],
-                [[9, 10, 11], [12, 13, 14], [15, 16, 17]],
-                [[18, 19, 20], [21, 22, 23], [24, 25, 26]],
-            ],
-        ),
-        (
-            list(range(28)),
-            3,
-            [
-                [
-                    [[0, 1, 2], [3, 4, 5], [6, 7, 8]],
-                    [[9, 10, 11], [12, 13, 14], [15, 16, 17]],
-                    [[18, 19, 20], [21, 22, 23], [24, 25, 26]],
-                ],
-                27,
-            ],
-        ),
-        (list(range(257)), 256, [list(range(256)), 256]),
-        (list(range(258)), 256, [list(range(256)), 256, 257]),
-        (list(range(512)), 256, [list(range(256)), list(range(256, 512))]),
-        (list(range(512 + 1)), 256, [list(range(256)), list(range(256, 512)), 512]),
-        (
-            list(range(256 ** 2)),
-            256,
-            [list(range(k * 256, k * 256 + 256)) for k in range(256)],
-        ),
-    ],
-)
-def test_build_n_ary_tree(lst, n, expected):
-    assert _build_n_ary_tree(lst, n) == expected
diff --git a/Tests/colorLib/table_builder_test.py b/Tests/colorLib/table_builder_test.py
deleted file mode 100644
index d0a76f5..0000000
--- a/Tests/colorLib/table_builder_test.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from fontTools.ttLib.tables import otTables  # trigger setup to occur
-from fontTools.ttLib.tables.otConverters import UShort
-from fontTools.colorLib.table_builder import TableBuilder
-import pytest
-
-
-class WriteMe:
-    value = None
-
-
-def test_intValue_otRound():
-    dest = WriteMe()
-    converter = UShort("value", None, None)
-    TableBuilder()._convert(dest, "value", converter, 85.6)
-    assert dest.value == 86, "Should have used otRound"
diff --git a/Tests/colorLib/unbuilder_test.py b/Tests/colorLib/unbuilder_test.py
deleted file mode 100644
index 81169e0..0000000
--- a/Tests/colorLib/unbuilder_test.py
+++ /dev/null
@@ -1,210 +0,0 @@
-from fontTools.ttLib.tables import otTables as ot
-from fontTools.colorLib.builder import buildColrV1
-from fontTools.colorLib.unbuilder import unbuildColrV1
-import pytest
-
-
-TEST_COLOR_GLYPHS = {
-    "glyph00010": {
-        "Format": int(ot.PaintFormat.PaintColrLayers),
-        "Layers": [
-            {
-                "Format": int(ot.PaintFormat.PaintGlyph),
-                "Paint": {
-                    "Format": int(ot.PaintFormat.PaintSolid),
-                    "Color": {"PaletteIndex": 2, "Alpha": 0.5},
-                },
-                "Glyph": "glyph00011",
-            },
-            {
-                "Format": int(ot.PaintFormat.PaintGlyph),
-                "Paint": {
-                    "Format": int(ot.PaintFormat.PaintVarLinearGradient),
-                    "ColorLine": {
-                        "Extend": "repeat",
-                        "ColorStop": [
-                            {
-                                "StopOffset": (0.0, 0),
-                                "Color": {"PaletteIndex": 3, "Alpha": (1.0, 0)},
-                            },
-                            {
-                                "StopOffset": (0.5, 0),
-                                "Color": {"PaletteIndex": 4, "Alpha": (1.0, 0)},
-                            },
-                            {
-                                "StopOffset": (1.0, 0),
-                                "Color": {"PaletteIndex": 5, "Alpha": (1.0, 0)},
-                            },
-                        ],
-                    },
-                    "x0": (1, 0),
-                    "y0": (2, 0),
-                    "x1": (-3, 0),
-                    "y1": (-4, 0),
-                    "x2": (5, 0),
-                    "y2": (6, 0),
-                },
-                "Glyph": "glyph00012",
-            },
-            {
-                "Format": int(ot.PaintFormat.PaintGlyph),
-                "Paint": {
-                    "Format": int(ot.PaintFormat.PaintVarTransform),
-                    "Paint": {
-                        "Format": int(ot.PaintFormat.PaintRadialGradient),
-                        "ColorLine": {
-                            "Extend": "pad",
-                            "ColorStop": [
-                                {
-                                    "StopOffset": 0,
-                                    "Color": {"PaletteIndex": 6, "Alpha": 1.0},
-                                },
-                                {
-                                    "StopOffset": 1.0,
-                                    "Color": {"PaletteIndex": 7, "Alpha": 0.4},
-                                },
-                            ],
-                        },
-                        "x0": 7,
-                        "y0": 8,
-                        "r0": 9,
-                        "x1": 10,
-                        "y1": 11,
-                        "r1": 12,
-                    },
-                    "Transform": {
-                        "xx": (-13.0, 0),
-                        "yx": (14.0, 0),
-                        "xy": (15.0, 0),
-                        "yy": (-17.0, 0),
-                        "dx": (18.0, 0),
-                        "dy": (19.0, 0),
-                    },
-                },
-                "Glyph": "glyph00013",
-            },
-            {
-                "Format": int(ot.PaintFormat.PaintVarTranslate),
-                "Paint": {
-                    "Format": int(ot.PaintFormat.PaintRotate),
-                    "Paint": {
-                        "Format": int(ot.PaintFormat.PaintVarSkew),
-                        "Paint": {
-                            "Format": int(ot.PaintFormat.PaintGlyph),
-                            "Paint": {
-                                "Format": int(ot.PaintFormat.PaintSolid),
-                                "Color": {"PaletteIndex": 2, "Alpha": 0.5},
-                            },
-                            "Glyph": "glyph00011",
-                        },
-                        "xSkewAngle": (-11.0, 0),
-                        "ySkewAngle": (5.0, 0),
-                        "centerX": (253.0, 0),
-                        "centerY": (254.0, 0),
-                    },
-                    "angle": 45.0,
-                    "centerX": 255.0,
-                    "centerY": 256.0,
-                },
-                "dx": (257.0, 0),
-                "dy": (258.0, 0),
-            },
-        ],
-    },
-    "glyph00014": {
-        "Format": int(ot.PaintFormat.PaintComposite),
-        "SourcePaint": {
-            "Format": int(ot.PaintFormat.PaintColrGlyph),
-            "Glyph": "glyph00010",
-        },
-        "CompositeMode": "src_over",
-        "BackdropPaint": {
-            "Format": int(ot.PaintFormat.PaintTransform),
-            "Paint": {
-                "Format": int(ot.PaintFormat.PaintColrGlyph),
-                "Glyph": "glyph00010",
-            },
-            "Transform": {
-                "xx": 1.0,
-                "yx": 0.0,
-                "xy": 0.0,
-                "yy": 1.0,
-                "dx": 300.0,
-                "dy": 0.0,
-            },
-        },
-    },
-    "glyph00015": {
-        "Format": int(ot.PaintFormat.PaintGlyph),
-        "Paint": {
-            "Format": int(ot.PaintFormat.PaintSweepGradient),
-            "ColorLine": {
-                "Extend": "pad",
-                "ColorStop": [
-                    {
-                        "StopOffset": 0.0,
-                        "Color": {"PaletteIndex": 3, "Alpha": 1.0},
-                    },
-                    {
-                        "StopOffset": 1.0,
-                        "Color": {"PaletteIndex": 5, "Alpha": 1.0},
-                    },
-                ],
-            },
-            "centerX": 259,
-            "centerY": 300,
-            "startAngle": 45.0,
-            "endAngle": 135.0,
-        },
-        "Glyph": "glyph00011",
-    },
-    "glyph00016": {
-        "Format": int(ot.PaintFormat.PaintColrLayers),
-        "Layers": [
-            {
-                "Format": int(ot.PaintFormat.PaintGlyph),
-                "Paint": {
-                    "Format": int(ot.PaintFormat.PaintVarSolid),
-                    "Color": {"PaletteIndex": 2, "Alpha": (0.5, 0)},
-                },
-                "Glyph": "glyph00011",
-            },
-            {
-                "Format": int(ot.PaintFormat.PaintGlyph),
-                "Paint": {
-                    "Format": int(ot.PaintFormat.PaintVarLinearGradient),
-                    "ColorLine": {
-                        "Extend": "repeat",
-                        "ColorStop": [
-                            {
-                                "StopOffset": (0.0, 0),
-                                "Color": {"PaletteIndex": 3, "Alpha": (1.0, 0)},
-                            },
-                            {
-                                "StopOffset": (0.5, 0),
-                                "Color": {"PaletteIndex": 4, "Alpha": (1.0, 0)},
-                            },
-                            {
-                                "StopOffset": (1.0, 0),
-                                "Color": {"PaletteIndex": 5, "Alpha": (1.0, 0)},
-                            },
-                        ],
-                    },
-                    "x0": (1, 0),
-                    "y0": (2, 0),
-                    "x1": (-3, 0),
-                    "y1": (-4, 0),
-                    "x2": (5, 0),
-                    "y2": (6, 0),
-                },
-                "Glyph": "glyph00012",
-            },
-        ],
-    },
-}
-
-
-def test_unbuildColrV1():
-    layersV1, baseGlyphsV1 = buildColrV1(TEST_COLOR_GLYPHS)
-    colorGlyphs = unbuildColrV1(layersV1, baseGlyphsV1)
-    assert colorGlyphs == TEST_COLOR_GLYPHS
diff --git a/Tests/cu2qu/cli_test.py b/Tests/cu2qu/cli_test.py
deleted file mode 100644
index f6798a6..0000000
--- a/Tests/cu2qu/cli_test.py
+++ /dev/null
@@ -1,86 +0,0 @@
-import os
-
-import pytest
-import py
-
-ufoLib2 = pytest.importorskip("ufoLib2")
-
-from fontTools.cu2qu.ufo import CURVE_TYPE_LIB_KEY
-from fontTools.cu2qu.cli import main
-
-
-DATADIR = os.path.join(os.path.dirname(__file__), 'data')
-
-TEST_UFOS = [
-    py.path.local(DATADIR).join("RobotoSubset-Regular.ufo"),
-    py.path.local(DATADIR).join("RobotoSubset-Bold.ufo"),
-]
-
-
-@pytest.fixture
-def test_paths(tmpdir):
-    result = []
-    for path in TEST_UFOS:
-        new_path = tmpdir / path.basename
-        path.copy(new_path)
-        result.append(new_path)
-    return result
-
-
-class MainTest(object):
-
-    @staticmethod
-    def run_main(*args):
-        main([str(p) for p in args if p])
-
-    def test_single_input_no_output(self, test_paths):
-        ufo_path = test_paths[0]
-
-        self.run_main(ufo_path)
-
-        font = ufoLib2.Font.open(ufo_path)
-        assert font.lib[CURVE_TYPE_LIB_KEY] == "quadratic"
-
-    def test_single_input_output_file(self, tmpdir):
-        input_path = TEST_UFOS[0]
-        output_path = tmpdir / input_path.basename
-        self.run_main('-o', output_path, input_path)
-
-        assert output_path.check(dir=1)
-
-    def test_multiple_inputs_output_dir(self, tmpdir):
-        output_dir = tmpdir / "output_dir"
-        self.run_main('-d', output_dir, *TEST_UFOS)
-
-        assert output_dir.check(dir=1)
-        outputs = set(p.basename for p in output_dir.listdir())
-        assert "RobotoSubset-Regular.ufo" in outputs
-        assert "RobotoSubset-Bold.ufo" in outputs
-
-    def test_interpolatable_inplace(self, test_paths):
-        self.run_main('-i', *test_paths)
-        self.run_main('-i', *test_paths)  # idempotent
-
-    @pytest.mark.parametrize(
-        "mode", ["", "-i"], ids=["normal", "interpolatable"])
-    def test_copytree(self, mode, tmpdir):
-        output_dir = tmpdir / "output_dir"
-        self.run_main(mode, '-d', output_dir, *TEST_UFOS)
-
-        output_dir_2 = tmpdir / "output_dir_2"
-        # no conversion when curves are already quadratic, just copy
-        self.run_main(mode, '-d', output_dir_2, *output_dir.listdir())
-        # running again overwrites existing with the copy
-        self.run_main(mode, '-d', output_dir_2, *output_dir.listdir())
-
-    def test_multiprocessing(self, tmpdir, test_paths):
-        self.run_main(*(test_paths + ["-j"]))
-
-    def test_keep_direction(self, test_paths):
-        self.run_main('--keep-direction', *test_paths)
-
-    def test_conversion_error(self, test_paths):
-        self.run_main('--conversion-error', 0.002, *test_paths)
-
-    def test_conversion_error_short(self, test_paths):
-        self.run_main('-e', 0.003, test_paths[0])
diff --git a/Tests/cu2qu/cu2qu_test.py b/Tests/cu2qu/cu2qu_test.py
deleted file mode 100644
index 456d210..0000000
--- a/Tests/cu2qu/cu2qu_test.py
+++ /dev/null
@@ -1,178 +0,0 @@
-# Copyright 2016 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import collections
-import math
-import unittest
-import os
-import json
-
-from fontTools.cu2qu import curve_to_quadratic, curves_to_quadratic
-
-
-DATADIR = os.path.join(os.path.dirname(__file__), 'data')
-
-MAX_ERR = 5
-
-
-class CurveToQuadraticTest(unittest.TestCase):
-
-    @classmethod
-    def setUpClass(cls):
-        """Do the curve conversion ahead of time, and run tests on results."""
-        with open(os.path.join(DATADIR, "curves.json"), "r") as fp:
-            curves = json.load(fp)
-
-        cls.single_splines = [
-            curve_to_quadratic(c, MAX_ERR) for c in curves]
-        cls.single_errors = [
-            cls.curve_spline_dist(c, s)
-            for c, s in zip(curves, cls.single_splines)]
-
-        curve_groups = [curves[i:i + 3] for i in range(0, 300, 3)]
-        cls.compat_splines = [
-            curves_to_quadratic(c, [MAX_ERR] * 3) for c in curve_groups]
-        cls.compat_errors = [
-            [cls.curve_spline_dist(c, s) for c, s in zip(curve_group, splines)]
-            for curve_group, splines in zip(curve_groups, cls.compat_splines)]
-
-        cls.results = []
-
-    @classmethod
-    def tearDownClass(cls):
-        """Print stats from conversion, as determined during tests."""
-
-        for tag, results in cls.results:
-            print('\n%s\n%s' % (
-                tag, '\n'.join(
-                    '%s: %s (%d)' % (k, '#' * (v // 10 + 1), v)
-                    for k, v in sorted(results.items()))))
-
-    def test_results_unchanged(self):
-        """Tests that the results of conversion haven't changed since the time
-        of this test's writing. Useful as a quick check whenever one modifies
-        the conversion algorithm.
-        """
-
-        expected = {
-            2: 6,
-            3: 26,
-            4: 82,
-            5: 232,
-            6: 360,
-            7: 266,
-            8: 28}
-
-        results = collections.defaultdict(int)
-        for spline in self.single_splines:
-            n = len(spline) - 2
-            results[n] += 1
-        self.assertEqual(results, expected)
-        self.results.append(('single spline lengths', results))
-
-    def test_results_unchanged_multiple(self):
-        """Test that conversion results are unchanged for multiple curves."""
-
-        expected = {
-            5: 11,
-            6: 35,
-            7: 49,
-            8: 5}
-
-        results = collections.defaultdict(int)
-        for splines in self.compat_splines:
-            n = len(splines[0]) - 2
-            for spline in splines[1:]:
-                self.assertEqual(len(spline) - 2, n,
-                    'Got incompatible conversion results')
-            results[n] += 1
-        self.assertEqual(results, expected)
-        self.results.append(('compatible spline lengths', results))
-
-    def test_does_not_exceed_tolerance(self):
-        """Test that conversion results do not exceed given error tolerance."""
-
-        results = collections.defaultdict(int)
-        for error in self.single_errors:
-            results[round(error, 1)] += 1
-            self.assertLessEqual(error, MAX_ERR)
-        self.results.append(('single errors', results))
-
-    def test_does_not_exceed_tolerance_multiple(self):
-        """Test that error tolerance isn't exceeded for multiple curves."""
-
-        results = collections.defaultdict(int)
-        for errors in self.compat_errors:
-            for error in errors:
-                results[round(error, 1)] += 1
-                self.assertLessEqual(error, MAX_ERR)
-        self.results.append(('compatible errors', results))
-
-    @classmethod
-    def curve_spline_dist(cls, bezier, spline, total_steps=20):
-        """Max distance between a bezier and quadratic spline at sampled points."""
-
-        error = 0
-        n = len(spline) - 2
-        steps = total_steps // n
-        for i in range(0, n - 1):
-            p1 = spline[0] if i == 0 else p3
-            p2 = spline[i + 1]
-            if i < n - 1:
-                p3 = cls.lerp(spline[i + 1], spline[i + 2], 0.5)
-            else:
-                p3 = spline[n + 2]
-            segment = p1, p2, p3
-            for j in range(steps):
-                error = max(error, cls.dist(
-                    cls.cubic_bezier_at(bezier, (j / steps + i) / n),
-                    cls.quadratic_bezier_at(segment, j / steps)))
-        return error
-
-    @classmethod
-    def lerp(cls, p1, p2, t):
-        (x1, y1), (x2, y2) = p1, p2
-        return x1 + (x2 - x1) * t, y1 + (y2 - y1) * t
-
-    @classmethod
-    def dist(cls, p1, p2):
-        (x1, y1), (x2, y2) = p1, p2
-        return math.hypot(x1 - x2, y1 - y2)
-
-    @classmethod
-    def quadratic_bezier_at(cls, b, t):
-        (x1, y1), (x2, y2), (x3, y3) = b
-        _t = 1 - t
-        t2 = t * t
-        _t2 = _t * _t
-        _2_t_t = 2 * t * _t
-        return (_t2 * x1 + _2_t_t * x2 + t2 * x3,
-                _t2 * y1 + _2_t_t * y2 + t2 * y3)
-
-    @classmethod
-    def cubic_bezier_at(cls, b, t):
-        (x1, y1), (x2, y2), (x3, y3), (x4, y4) = b
-        _t = 1 - t
-        t2 = t * t
-        _t2 = _t * _t
-        t3 = t * t2
-        _t3 = _t * _t2
-        _3_t2_t = 3 * t2 * _t
-        _3_t_t2 = 3 * t * _t2
-        return (_t3 * x1 + _3_t_t2 * x2 + _3_t2_t * x3 + t3 * x4,
-                _t3 * y1 + _3_t_t2 * y2 + _3_t2_t * y3 + t3 * y4)
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/fontinfo.plist b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/fontinfo.plist
deleted file mode 100644
index 21621a2..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/fontinfo.plist
+++ /dev/null
@@ -1,205 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>ascender</key>
-	<integer>2146</integer>
-	<key>capHeight</key>
-	<integer>1456</integer>
-	<key>copyright</key>
-	<string>Copyright 2011 Google Inc. All Rights Reserved.</string>
-	<key>descender</key>
-	<integer>-555</integer>
-	<key>familyName</key>
-	<string>RobotoSubset</string>
-	<key>italicAngle</key>
-	<integer>0</integer>
-	<key>openTypeHeadCreated</key>
-	<string>2008/09/12 12:29:34</string>
-	<key>openTypeHeadFlags</key>
-	<array>
-		<integer>0</integer>
-		<integer>1</integer>
-		<integer>3</integer>
-		<integer>4</integer>
-	</array>
-	<key>openTypeHeadLowestRecPPEM</key>
-	<integer>9</integer>
-	<key>openTypeHheaAscender</key>
-	<integer>1900</integer>
-	<key>openTypeHheaDescender</key>
-	<integer>-500</integer>
-	<key>openTypeHheaLineGap</key>
-	<integer>0</integer>
-	<key>openTypeNameDescription</key>
-	<string></string>
-	<key>openTypeNameDesigner</key>
-	<string></string>
-	<key>openTypeNameDesignerURL</key>
-	<string></string>
-	<key>openTypeNameLicense</key>
-	<string></string>
-	<key>openTypeNameLicenseURL</key>
-	<string></string>
-	<key>openTypeNameManufacturer</key>
-	<string></string>
-	<key>openTypeNameManufacturerURL</key>
-	<string></string>
-	<key>openTypeNameSampleText</key>
-	<string></string>
-	<key>openTypeOS2CodePageRanges</key>
-	<array>
-		<integer>0</integer>
-		<integer>1</integer>
-		<integer>2</integer>
-		<integer>3</integer>
-		<integer>4</integer>
-		<integer>7</integer>
-		<integer>8</integer>
-		<integer>29</integer>
-	</array>
-	<key>openTypeOS2FamilyClass</key>
-	<array>
-		<integer>0</integer>
-		<integer>0</integer>
-	</array>
-	<key>openTypeOS2Panose</key>
-	<array>
-		<integer>0</integer>
-		<integer>0</integer>
-		<integer>0</integer>
-		<integer>0</integer>
-		<integer>0</integer>
-		<integer>0</integer>
-		<integer>0</integer>
-		<integer>0</integer>
-		<integer>0</integer>
-		<integer>0</integer>
-	</array>
-	<key>openTypeOS2Selection</key>
-	<array>
-	</array>
-	<key>openTypeOS2StrikeoutPosition</key>
-	<integer>512</integer>
-	<key>openTypeOS2StrikeoutSize</key>
-	<integer>102</integer>
-	<key>openTypeOS2SubscriptXOffset</key>
-	<integer>0</integer>
-	<key>openTypeOS2SubscriptXSize</key>
-	<integer>1434</integer>
-	<key>openTypeOS2SubscriptYOffset</key>
-	<integer>287</integer>
-	<key>openTypeOS2SubscriptYSize</key>
-	<integer>1331</integer>
-	<key>openTypeOS2SuperscriptXOffset</key>
-	<integer>0</integer>
-	<key>openTypeOS2SuperscriptXSize</key>
-	<integer>1434</integer>
-	<key>openTypeOS2SuperscriptYOffset</key>
-	<integer>977</integer>
-	<key>openTypeOS2SuperscriptYSize</key>
-	<integer>1331</integer>
-	<key>openTypeOS2Type</key>
-	<array>
-	</array>
-	<key>openTypeOS2TypoAscender</key>
-	<integer>2146</integer>
-	<key>openTypeOS2TypoDescender</key>
-	<integer>-555</integer>
-	<key>openTypeOS2TypoLineGap</key>
-	<integer>0</integer>
-	<key>openTypeOS2UnicodeRanges</key>
-	<array>
-		<integer>0</integer>
-		<integer>1</integer>
-		<integer>2</integer>
-		<integer>3</integer>
-		<integer>4</integer>
-		<integer>5</integer>
-		<integer>6</integer>
-		<integer>7</integer>
-		<integer>9</integer>
-		<integer>11</integer>
-		<integer>29</integer>
-		<integer>30</integer>
-		<integer>31</integer>
-		<integer>32</integer>
-		<integer>33</integer>
-		<integer>34</integer>
-		<integer>35</integer>
-		<integer>36</integer>
-		<integer>37</integer>
-		<integer>38</integer>
-		<integer>40</integer>
-		<integer>45</integer>
-		<integer>60</integer>
-		<integer>62</integer>
-		<integer>64</integer>
-		<integer>69</integer>
-	</array>
-	<key>openTypeOS2VendorID</key>
-	<string>GOOG</string>
-	<key>openTypeOS2WeightClass</key>
-	<integer>700</integer>
-	<key>openTypeOS2WidthClass</key>
-	<integer>5</integer>
-	<key>openTypeOS2WinAscent</key>
-	<integer>2146</integer>
-	<key>openTypeOS2WinDescent</key>
-	<integer>555</integer>
-	<key>postscriptBlueFuzz</key>
-	<integer>1</integer>
-	<key>postscriptBlueScale</key>
-	<real>0.039625</real>
-	<key>postscriptBlueShift</key>
-	<integer>7</integer>
-	<key>postscriptBlueValues</key>
-	<array>
-		<integer>-20</integer>
-		<integer>0</integer>
-		<integer>1082</integer>
-		<integer>1102</integer>
-		<integer>1456</integer>
-		<integer>1476</integer>
-	</array>
-	<key>postscriptDefaultCharacter</key>
-	<string>space</string>
-	<key>postscriptForceBold</key>
-	<false/>
-	<key>postscriptIsFixedPitch</key>
-	<false/>
-	<key>postscriptOtherBlues</key>
-	<array>
-		<integer>-436</integer>
-		<integer>-416</integer>
-	</array>
-	<key>postscriptStemSnapH</key>
-	<array>
-		<integer>250</integer>
-	</array>
-	<key>postscriptStemSnapV</key>
-	<array>
-		<integer>316</integer>
-	</array>
-	<key>postscriptUnderlinePosition</key>
-	<integer>-150</integer>
-	<key>postscriptUnderlineThickness</key>
-	<integer>100</integer>
-	<key>postscriptUniqueID</key>
-	<integer>-1</integer>
-	<key>styleName</key>
-	<string>Bold</string>
-	<key>trademark</key>
-	<string></string>
-	<key>unitsPerEm</key>
-	<integer>2048</integer>
-	<key>versionMajor</key>
-	<integer>1</integer>
-	<key>versionMinor</key>
-	<integer>0</integer>
-	<key>xHeight</key>
-	<integer>1082</integer>
-	<key>year</key>
-	<integer>2017</integer>
-</dict>
-</plist>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/A_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/A_.glif
deleted file mode 100644
index 481f006..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/A_.glif
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="A" format="2">
-	<unicode hex="0041"/>
-	<advance width="1390"/>
-	<outline>
-		<contour>
-			<point x="727" y="1150" type="line"/>
-			<point x="764" y="1456" type="line"/>
-			<point x="537" y="1456" type="line"/>
-			<point x="0" y="0" type="line"/>
-			<point x="358" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="1032" y="0" type="line"/>
-			<point x="1391" y="0" type="line"/>
-			<point x="851" y="1456" type="line"/>
-			<point x="621" y="1456" type="line"/>
-			<point x="662" y="1150" type="line"/>
-		</contour>
-		<contour>
-			<point x="1018" y="543" type="line"/>
-			<point x="262" y="543" type="line"/>
-			<point x="262" y="272" type="line"/>
-			<point x="1018" y="272" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/B_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/B_.glif
deleted file mode 100644
index a4c9f25..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/B_.glif
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="B" format="2">
-	<unicode hex="0042"/>
-	<advance width="1317"/>
-	<outline>
-		<contour>
-			<point x="703" y="619" type="line"/>
-			<point x="797" y="710" type="line"/>
-			<point x="1092" y="713"/>
-			<point x="1199" y="875"/>
-			<point x="1199" y="1054" type="curve"/>
-			<point x="1199" y="1326"/>
-			<point x="988" y="1456"/>
-			<point x="636" y="1456" type="curve"/>
-			<point x="117" y="1456" type="line"/>
-			<point x="117" y="0" type="line"/>
-			<point x="452" y="0" type="line"/>
-			<point x="452" y="1185" type="line"/>
-			<point x="636" y="1185" type="line"/>
-			<point x="795" y="1185"/>
-			<point x="864" y="1135"/>
-			<point x="864" y="1012" type="curve"/>
-			<point x="864" y="904"/>
-			<point x="797" y="849"/>
-			<point x="635" y="849" type="curve"/>
-			<point x="328" y="849" type="line"/>
-			<point x="330" y="619" type="line"/>
-		</contour>
-		<contour>
-			<point x="690" y="0" type="line"/>
-			<point x="1042" y="0"/>
-			<point x="1230" y="145"/>
-			<point x="1230" y="431" type="curve" smooth="yes"/>
-			<point x="1230" y="598"/>
-			<point x="1129" y="769"/>
-			<point x="846" y="757" type="curve"/>
-			<point x="768" y="849" type="line"/>
-			<point x="412" y="849" type="line"/>
-			<point x="410" y="619" type="line"/>
-			<point x="703" y="619" type="line" smooth="yes"/>
-			<point x="842" y="619"/>
-			<point x="896" y="548"/>
-			<point x="896" y="436" type="curve" smooth="yes"/>
-			<point x="896" y="344"/>
-			<point x="836" y="270"/>
-			<point x="690" y="270" type="curve" smooth="yes"/>
-			<point x="365" y="270" type="line"/>
-			<point x="245" y="0" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/C_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/C_.glif
deleted file mode 100644
index 1d8e1e1..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/C_.glif
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="C" format="2">
-	<unicode hex="0043"/>
-	<advance width="1343"/>
-	<outline>
-		<contour>
-			<point x="950" y="493" type="line"/>
-			<point x="942" y="329"/>
-			<point x="856" y="255"/>
-			<point x="687" y="255" type="curve" smooth="yes"/>
-			<point x="489" y="255"/>
-			<point x="415" y="379"/>
-			<point x="415" y="688" type="curve" smooth="yes"/>
-			<point x="415" y="769" type="line" smooth="yes"/>
-			<point x="415" y="1079"/>
-			<point x="503" y="1202"/>
-			<point x="685" y="1202" type="curve" smooth="yes"/>
-			<point x="875" y="1202"/>
-			<point x="944" y="1117"/>
-			<point x="952" y="953" type="curve"/>
-			<point x="1286" y="953" type="line"/>
-			<point x="1259" y="1255"/>
-			<point x="1060" y="1477"/>
-			<point x="685" y="1477" type="curve" smooth="yes"/>
-			<point x="316" y="1477"/>
-			<point x="75" y="1205"/>
-			<point x="75" y="767" type="curve"/>
-			<point x="75" y="688" type="line"/>
-			<point x="75" y="250"/>
-			<point x="303" y="-20"/>
-			<point x="687" y="-20" type="curve" smooth="yes"/>
-			<point x="1046" y="-20"/>
-			<point x="1268" y="188"/>
-			<point x="1284" y="493" type="curve"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/D_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/D_.glif
deleted file mode 100644
index 1d82e15..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/D_.glif
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="D" format="2">
-	<unicode hex="0044"/>
-	<advance width="1327"/>
-	<outline>
-		<contour>
-			<point x="581" y="0" type="line"/>
-			<point x="973" y="0"/>
-			<point x="1251" y="285"/>
-			<point x="1251" y="697" type="curve"/>
-			<point x="1251" y="758" type="line"/>
-			<point x="1251" y="1170"/>
-			<point x="973" y="1456"/>
-			<point x="579" y="1456" type="curve"/>
-			<point x="255" y="1456" type="line"/>
-			<point x="255" y="1185" type="line"/>
-			<point x="579" y="1185" type="line"/>
-			<point x="794" y="1185"/>
-			<point x="910" y="1039"/>
-			<point x="910" y="760" type="curve"/>
-			<point x="910" y="697" type="line" smooth="yes"/>
-			<point x="910" y="416"/>
-			<point x="793" y="270"/>
-			<point x="581" y="270" type="curve"/>
-			<point x="263" y="270" type="line"/>
-			<point x="261" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="452" y="1456" type="line"/>
-			<point x="117" y="1456" type="line"/>
-			<point x="117" y="0" type="line"/>
-			<point x="452" y="0" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/E_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/E_.glif
deleted file mode 100644
index 4d867ee..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/E_.glif
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="E" format="2">
-	<unicode hex="0045"/>
-	<advance width="1148"/>
-	<outline>
-		<contour>
-			<point x="1111" y="270" type="line"/>
-			<point x="337" y="270" type="line"/>
-			<point x="337" y="0" type="line"/>
-			<point x="1111" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="452" y="1456" type="line"/>
-			<point x="117" y="1456" type="line"/>
-			<point x="117" y="0" type="line"/>
-			<point x="452" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="1011" y="878" type="line"/>
-			<point x="337" y="878" type="line"/>
-			<point x="337" y="617" type="line"/>
-			<point x="1011" y="617" type="line"/>
-		</contour>
-		<contour>
-			<point x="1112" y="1456" type="line"/>
-			<point x="337" y="1456" type="line"/>
-			<point x="337" y="1185" type="line"/>
-			<point x="1112" y="1185" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/F_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/F_.glif
deleted file mode 100644
index 2e0d20c..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/F_.glif
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="F" format="2">
-	<unicode hex="0046"/>
-	<advance width="1121"/>
-	<outline>
-		<contour>
-			<point x="452" y="1456" type="line"/>
-			<point x="117" y="1456" type="line"/>
-			<point x="117" y="0" type="line"/>
-			<point x="452" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="1021" y="850" type="line"/>
-			<point x="359" y="850" type="line"/>
-			<point x="359" y="580" type="line"/>
-			<point x="1021" y="580" type="line"/>
-		</contour>
-		<contour>
-			<point x="1083" y="1456" type="line"/>
-			<point x="359" y="1456" type="line"/>
-			<point x="359" y="1185" type="line"/>
-			<point x="1083" y="1185" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/G_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/G_.glif
deleted file mode 100644
index 6e65a0c..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/G_.glif
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="G" format="2">
-	<unicode hex="0047"/>
-	<advance width="1396"/>
-	<outline>
-		<contour>
-			<point x="1296" y="778" type="line"/>
-			<point x="708" y="778" type="line"/>
-			<point x="708" y="537" type="line"/>
-			<point x="961" y="537" type="line"/>
-			<point x="961" y="311" type="line"/>
-			<point x="931" y="284"/>
-			<point x="868" y="250"/>
-			<point x="746" y="250" type="curve" smooth="yes"/>
-			<point x="529" y="250"/>
-			<point x="426" y="396"/>
-			<point x="426" y="687" type="curve" smooth="yes"/>
-			<point x="426" y="770" type="line" smooth="yes"/>
-			<point x="426" y="1063"/>
-			<point x="535" y="1207"/>
-			<point x="715" y="1207" type="curve" smooth="yes"/>
-			<point x="883" y="1207"/>
-			<point x="951" y="1125"/>
-			<point x="972" y="981" type="curve"/>
-			<point x="1295" y="981" type="line"/>
-			<point x="1265" y="1272"/>
-			<point x="1098" y="1477"/>
-			<point x="704" y="1477" type="curve" smooth="yes"/>
-			<point x="340" y="1477"/>
-			<point x="86" y="1221"/>
-			<point x="86" y="768" type="curve" smooth="yes"/>
-			<point x="86" y="687" type="line" smooth="yes"/>
-			<point x="86" y="234"/>
-			<point x="340" y="-20"/>
-			<point x="724" y="-20" type="curve" smooth="yes"/>
-			<point x="1040" y="-20"/>
-			<point x="1223" y="98"/>
-			<point x="1296" y="180" type="curve"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/H_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/H_.glif
deleted file mode 100644
index 4ae896d..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/H_.glif
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="H" format="2">
-	<unicode hex="0048"/>
-	<advance width="1442"/>
-	<outline>
-		<contour>
-			<point x="1094" y="878" type="line"/>
-			<point x="345" y="878" type="line"/>
-			<point x="345" y="608" type="line"/>
-			<point x="1094" y="608" type="line"/>
-		</contour>
-		<contour>
-			<point x="452" y="1456" type="line"/>
-			<point x="117" y="1456" type="line"/>
-			<point x="117" y="0" type="line"/>
-			<point x="452" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="1324" y="1456" type="line"/>
-			<point x="990" y="1456" type="line"/>
-			<point x="990" y="0" type="line"/>
-			<point x="1324" y="0" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/I_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/I_.glif
deleted file mode 100644
index c22d48a..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/I_.glif
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="I" format="2">
-	<unicode hex="0049"/>
-	<advance width="612"/>
-	<outline>
-		<contour>
-			<point x="473" y="1456" type="line"/>
-			<point x="139" y="1456" type="line"/>
-			<point x="139" y="0" type="line"/>
-			<point x="473" y="0" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/J_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/J_.glif
deleted file mode 100644
index 599404b..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/J_.glif
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="J" format="2">
-	<unicode hex="004A"/>
-	<advance width="1149"/>
-	<outline>
-		<contour>
-			<point x="699" y="457" type="line"/>
-			<point x="699" y="327"/>
-			<point x="638" y="250"/>
-			<point x="536" y="250" type="curve" smooth="yes"/>
-			<point x="433" y="250"/>
-			<point x="374" y="292"/>
-			<point x="374" y="440" type="curve"/>
-			<point x="38" y="440" type="line"/>
-			<point x="38" y="124"/>
-			<point x="246" y="-20"/>
-			<point x="536" y="-20" type="curve" smooth="yes"/>
-			<point x="816" y="-20"/>
-			<point x="1033" y="165"/>
-			<point x="1033" y="457" type="curve"/>
-			<point x="1033" y="1456" type="line"/>
-			<point x="699" y="1456" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/K_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/K_.glif
deleted file mode 100644
index 15d08e1..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/K_.glif
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="K" format="2">
-	<unicode hex="004B"/>
-	<advance width="1307"/>
-	<outline>
-		<contour>
-			<point x="452" y="1456" type="line"/>
-			<point x="117" y="1456" type="line"/>
-			<point x="117" y="0" type="line"/>
-			<point x="452" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="1322" y="1456" type="line"/>
-			<point x="909" y="1456" type="line"/>
-			<point x="577" y="999" type="line"/>
-			<point x="361" y="679" type="line"/>
-			<point x="422" y="357" type="line"/>
-			<point x="754" y="718" type="line"/>
-		</contour>
-		<contour>
-			<point x="930" y="0" type="line"/>
-			<point x="1327" y="0" type="line"/>
-			<point x="794" y="857" type="line"/>
-			<point x="538" y="656" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/L_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/L_.glif
deleted file mode 100644
index eb22f5f..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/L_.glif
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="L" format="2">
-	<unicode hex="004C"/>
-	<advance width="1110"/>
-	<outline>
-		<contour>
-			<point x="1071" y="270" type="line"/>
-			<point x="337" y="270" type="line"/>
-			<point x="337" y="0" type="line"/>
-			<point x="1071" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="452" y="1456" type="line"/>
-			<point x="117" y="1456" type="line"/>
-			<point x="117" y="0" type="line"/>
-			<point x="452" y="0" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/M_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/M_.glif
deleted file mode 100644
index 9c1a8e5..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/M_.glif
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="M" format="2">
-	<unicode hex="004D"/>
-	<advance width="1795"/>
-	<outline>
-		<contour>
-			<point x="279" y="1456" type="line"/>
-			<point x="784" y="0" type="line"/>
-			<point x="1008" y="0" type="line"/>
-			<point x="1513" y="1456" type="line"/>
-			<point x="1236" y="1456" type="line"/>
-			<point x="896" y="443" type="line"/>
-			<point x="556" y="1456" type="line"/>
-		</contour>
-		<contour>
-			<point x="117" y="1456" type="line"/>
-			<point x="117" y="0" type="line"/>
-			<point x="452" y="0" type="line"/>
-			<point x="452" y="340" type="line"/>
-			<point x="400" y="1456" type="line"/>
-		</contour>
-		<contour>
-			<point x="1392" y="1456" type="line"/>
-			<point x="1340" y="340" type="line"/>
-			<point x="1340" y="0" type="line"/>
-			<point x="1676" y="0" type="line"/>
-			<point x="1676" y="1456" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/N_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/N_.glif
deleted file mode 100644
index 4b335f3..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/N_.glif
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="N" format="2">
-	<unicode hex="004E"/>
-	<advance width="1441"/>
-	<outline>
-		<contour>
-			<point x="1323" y="1456" type="line"/>
-			<point x="989" y="1456" type="line"/>
-			<point x="989" y="550" type="line"/>
-			<point x="452" y="1456" type="line"/>
-			<point x="117" y="1456" type="line"/>
-			<point x="117" y="0" type="line"/>
-			<point x="452" y="0" type="line"/>
-			<point x="452" y="906" type="line"/>
-			<point x="989" y="0" type="line"/>
-			<point x="1323" y="0" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/O_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/O_.glif
deleted file mode 100644
index 8e6d182..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/O_.glif
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="O" format="2">
-	<unicode hex="004F"/>
-	<advance width="1414"/>
-	<outline>
-		<contour>
-			<point x="1338" y="757" type="line"/>
-			<point x="1338" y="1202"/>
-			<point x="1076" y="1476"/>
-			<point x="706" y="1476" type="curve" smooth="yes"/>
-			<point x="334" y="1476"/>
-			<point x="75" y="1202"/>
-			<point x="75" y="757" type="curve"/>
-			<point x="75" y="698" type="line"/>
-			<point x="75" y="253"/>
-			<point x="336" y="-20"/>
-			<point x="708" y="-20" type="curve" smooth="yes"/>
-			<point x="1078" y="-20"/>
-			<point x="1338" y="253"/>
-			<point x="1338" y="698" type="curve"/>
-		</contour>
-		<contour>
-			<point x="998" y="698" type="line"/>
-			<point x="998" y="413"/>
-			<point x="894" y="254"/>
-			<point x="708" y="254" type="curve" smooth="yes"/>
-			<point x="517" y="254"/>
-			<point x="415" y="413"/>
-			<point x="415" y="698" type="curve" smooth="yes"/>
-			<point x="415" y="759" type="line" smooth="yes"/>
-			<point x="415" y="1047"/>
-			<point x="515" y="1201"/>
-			<point x="706" y="1201" type="curve" smooth="yes"/>
-			<point x="892" y="1201"/>
-			<point x="998" y="1047"/>
-			<point x="998" y="759" type="curve"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/P_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/P_.glif
deleted file mode 100644
index 5b00197..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/P_.glif
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="P" format="2">
-	<unicode hex="0050"/>
-	<advance width="1330"/>
-	<outline>
-		<contour>
-			<point x="694" y="494" type="line"/>
-			<point x="1042" y="494"/>
-			<point x="1253" y="680"/>
-			<point x="1253" y="962" type="curve"/>
-			<point x="1253" y="1247"/>
-			<point x="1042" y="1456"/>
-			<point x="694" y="1456" type="curve"/>
-			<point x="117" y="1456" type="line"/>
-			<point x="117" y="0" type="line"/>
-			<point x="452" y="0" type="line"/>
-			<point x="452" y="1185" type="line"/>
-			<point x="694" y="1185" type="line"/>
-			<point x="849" y="1185"/>
-			<point x="914" y="1079"/>
-			<point x="914" y="960" type="curve"/>
-			<point x="914" y="847"/>
-			<point x="849" y="765"/>
-			<point x="694" y="765" type="curve"/>
-			<point x="330" y="765" type="line"/>
-			<point x="330" y="494" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/Q_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/Q_.glif
deleted file mode 100644
index 28a9616..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/Q_.glif
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="Q" format="2">
-	<unicode hex="0051"/>
-	<advance width="1414"/>
-	<outline>
-		<contour>
-			<point x="922" y="240" type="line"/>
-			<point x="720" y="56" type="line"/>
-			<point x="1116" y="-266" type="line"/>
-			<point x="1325" y="-82" type="line"/>
-		</contour>
-		<contour>
-			<point x="1339" y="757" type="line"/>
-			<point x="1339" y="1202"/>
-			<point x="1077" y="1476"/>
-			<point x="707" y="1476" type="curve" smooth="yes"/>
-			<point x="335" y="1476"/>
-			<point x="76" y="1202"/>
-			<point x="76" y="757" type="curve"/>
-			<point x="76" y="698" type="line"/>
-			<point x="76" y="253"/>
-			<point x="337" y="-20"/>
-			<point x="709" y="-20" type="curve" smooth="yes"/>
-			<point x="1079" y="-20"/>
-			<point x="1339" y="253"/>
-			<point x="1339" y="698" type="curve"/>
-		</contour>
-		<contour>
-			<point x="999" y="698" type="line"/>
-			<point x="999" y="413"/>
-			<point x="895" y="254"/>
-			<point x="709" y="254" type="curve" smooth="yes"/>
-			<point x="518" y="254"/>
-			<point x="416" y="413"/>
-			<point x="416" y="698" type="curve" smooth="yes"/>
-			<point x="416" y="759" type="line" smooth="yes"/>
-			<point x="416" y="1047"/>
-			<point x="516" y="1201"/>
-			<point x="707" y="1201" type="curve" smooth="yes"/>
-			<point x="893" y="1201"/>
-			<point x="999" y="1047"/>
-			<point x="999" y="759" type="curve"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/R_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/R_.glif
deleted file mode 100644
index b76ad56..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/R_.glif
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="R" format="2">
-	<unicode hex="0052"/>
-	<advance width="1327"/>
-	<outline>
-		<contour>
-			<point name="hr00" x="117" y="1456" type="line"/>
-			<point x="117" y="0" type="line"/>
-			<point x="452" y="0" type="line"/>
-			<point x="452" y="1185" type="line"/>
-			<point x="680" y="1185" type="line" smooth="yes"/>
-			<point x="820" y="1185"/>
-			<point x="892" y="1109"/>
-			<point x="892" y="984" type="curve" smooth="yes"/>
-			<point x="892" y="860"/>
-			<point x="821" y="785"/>
-			<point x="680" y="785" type="curve" smooth="yes"/>
-			<point x="328" y="785" type="line"/>
-			<point x="330" y="514" type="line"/>
-			<point x="806" y="514" type="line"/>
-			<point x="915" y="579" type="line"/>
-			<point x="1102" y="649"/>
-			<point x="1227" y="766"/>
-			<point x="1227" y="1016" type="curve" smooth="yes"/>
-			<point x="1227" y="1303"/>
-			<point x="1016" y="1456"/>
-			<point x="680" y="1456" type="curve" smooth="yes"/>
-		</contour>
-		<contour>
-			<point x="919" y="0" type="line"/>
-			<point x="1278" y="0" type="line"/>
-			<point x="1278" y="15" type="line"/>
-			<point x="949" y="646" type="line"/>
-			<point x="594" y="644" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/S_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/S_.glif
deleted file mode 100644
index a2ab850..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/S_.glif
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="S" format="2">
-	<unicode hex="0053"/>
-	<advance width="1275"/>
-	<outline>
-		<contour>
-			<point name="hr00" x="869" y="387" type="curve" smooth="yes"/>
-			<point x="869" y="309"/>
-			<point x="809" y="244"/>
-			<point x="669" y="244" type="curve" smooth="yes"/>
-			<point x="502" y="244"/>
-			<point x="402" y="301"/>
-			<point x="402" y="472" type="curve"/>
-			<point x="66" y="472" type="line"/>
-			<point x="66" y="127"/>
-			<point x="373" y="-20"/>
-			<point x="669" y="-20" type="curve" smooth="yes"/>
-			<point x="993" y="-20"/>
-			<point x="1204" y="127"/>
-			<point x="1204" y="389" type="curve"/>
-			<point x="1204" y="634"/>
-			<point x="1030" y="772"/>
-			<point x="718" y="870" type="curve"/>
-			<point x="545" y="924"/>
-			<point x="444" y="977"/>
-			<point x="444" y="1064" type="curve"/>
-			<point x="444" y="1144"/>
-			<point x="515" y="1211"/>
-			<point x="656" y="1211" type="curve" smooth="yes"/>
-			<point x="800" y="1211"/>
-			<point x="870" y="1134"/>
-			<point x="870" y="1024" type="curve"/>
-			<point x="1204" y="1024" type="line"/>
-			<point x="1204" y="1299"/>
-			<point x="983" y="1476"/>
-			<point x="663" y="1476" type="curve" smooth="yes"/>
-			<point x="343" y="1476"/>
-			<point x="110" y="1317"/>
-			<point x="110" y="1067" type="curve"/>
-			<point x="110" y="805"/>
-			<point x="344" y="685"/>
-			<point x="603" y="600" type="curve"/>
-			<point x="827" y="527"/>
-			<point x="869" y="478"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/T_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/T_.glif
deleted file mode 100644
index 5e0a1c9..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/T_.glif
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="T" format="2">
-	<unicode hex="0054"/>
-	<advance width="1284"/>
-	<outline>
-		<contour>
-			<point x="805" y="1456" type="line"/>
-			<point x="470" y="1456" type="line"/>
-			<point x="470" y="0" type="line"/>
-			<point x="805" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="1245" y="1456" type="line"/>
-			<point x="38" y="1456" type="line"/>
-			<point x="38" y="1185" type="line"/>
-			<point x="1245" y="1185" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/U_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/U_.glif
deleted file mode 100644
index 202f92f..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/U_.glif
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="U" format="2">
-	<unicode hex="0055"/>
-	<advance width="1357"/>
-	<outline>
-		<contour>
-			<point x="911" y="1456" type="line"/>
-			<point x="911" y="505" type="line" smooth="yes"/>
-			<point x="911" y="325"/>
-			<point x="829" y="250"/>
-			<point x="679" y="250" type="curve" smooth="yes"/>
-			<point x="530" y="250"/>
-			<point x="445" y="325"/>
-			<point x="445" y="505" type="curve" smooth="yes"/>
-			<point x="445" y="1456" type="line"/>
-			<point x="109" y="1456" type="line"/>
-			<point x="109" y="505" type="line"/>
-			<point x="109" y="164"/>
-			<point x="342" y="-20"/>
-			<point x="679" y="-20" type="curve" smooth="yes"/>
-			<point x="1017" y="-20"/>
-			<point x="1246" y="164"/>
-			<point x="1246" y="505" type="curve"/>
-			<point x="1246" y="1456" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/V_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/V_.glif
deleted file mode 100644
index c242ddd..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/V_.glif
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="V" format="2">
-	<unicode hex="0056"/>
-	<advance width="1349"/>
-	<outline>
-		<contour>
-			<point x="659" y="343" type="line"/>
-			<point x="610" y="0" type="line"/>
-			<point x="854" y="0" type="line"/>
-			<point x="1350" y="1456" type="line"/>
-			<point x="976" y="1456" type="line"/>
-		</contour>
-		<contour>
-			<point x="372" y="1456" type="line"/>
-			<point x="0" y="1456" type="line"/>
-			<point x="493" y="0" type="line"/>
-			<point x="739" y="0" type="line"/>
-			<point x="688" y="343" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/W_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/W_.glif
deleted file mode 100644
index 5cf2b3a..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/W_.glif
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="W" format="2">
-	<unicode hex="0057"/>
-	<advance width="1784"/>
-	<outline>
-		<contour>
-			<point x="459" y="132" type="line"/>
-			<point x="498" y="0" type="line"/>
-			<point x="684" y="0" type="line"/>
-			<point x="993" y="1343" type="line"/>
-			<point x="918" y="1456" type="line"/>
-			<point x="748" y="1456" type="line"/>
-		</contour>
-		<contour>
-			<point x="359" y="1456" type="line"/>
-			<point x="26" y="1456" type="line"/>
-			<point x="340" y="0" type="line"/>
-			<point x="552" y="0" type="line"/>
-			<point x="601" y="122" type="line"/>
-		</contour>
-		<contour>
-			<point x="1183" y="129" type="line"/>
-			<point x="1230" y="0" type="line"/>
-			<point x="1442" y="0" type="line"/>
-			<point x="1755" y="1456" type="line"/>
-			<point x="1423" y="1456" type="line"/>
-		</contour>
-		<contour>
-			<point x="1032" y="1456" type="line"/>
-			<point x="863" y="1456" type="line"/>
-			<point x="785" y="1345" type="line"/>
-			<point x="1098" y="0" type="line"/>
-			<point x="1284" y="0" type="line"/>
-			<point x="1326" y="124" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/X_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/X_.glif
deleted file mode 100644
index 9682d90..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/X_.glif
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="X" format="2">
-	<unicode hex="0058"/>
-	<advance width="1306"/>
-	<outline>
-		<contour>
-			<point x="404" y="1456" type="line"/>
-			<point x="21" y="1456" type="line"/>
-			<point x="433" y="734" type="line"/>
-			<point x="10" y="0" type="line"/>
-			<point x="397" y="0" type="line"/>
-			<point x="653" y="493" type="line"/>
-			<point x="909" y="0" type="line"/>
-			<point x="1296" y="0" type="line"/>
-			<point x="873" y="734" type="line"/>
-			<point x="1285" y="1456" type="line"/>
-			<point x="902" y="1456" type="line"/>
-			<point x="653" y="972" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/Y_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/Y_.glif
deleted file mode 100644
index 0b738ae..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/Y_.glif
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="Y" format="2">
-	<unicode hex="0059"/>
-	<advance width="1280"/>
-	<outline>
-		<contour>
-			<point x="361" y="1456" type="line"/>
-			<point x="-2" y="1456" type="line"/>
-			<point x="470" y="523" type="line"/>
-			<point x="470" y="0" type="line"/>
-			<point x="810" y="0" type="line"/>
-			<point x="810" y="523" type="line"/>
-			<point x="1282" y="1456" type="line"/>
-			<point x="919" y="1456" type="line"/>
-			<point x="640" y="824" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/Z_.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/Z_.glif
deleted file mode 100644
index 82d6647..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/Z_.glif
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="Z" format="2">
-	<unicode hex="005A"/>
-	<advance width="1247"/>
-	<outline>
-		<contour>
-			<point x="1195" y="270" type="line"/>
-			<point x="149" y="270" type="line"/>
-			<point x="149" y="0" type="line"/>
-			<point x="1195" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="1185" y="1276" type="line"/>
-			<point x="1185" y="1456" type="line"/>
-			<point x="954" y="1456" type="line"/>
-			<point x="69" y="185" type="line"/>
-			<point x="69" y="0" type="line"/>
-			<point x="309" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="1075" y="1456" type="line"/>
-			<point x="66" y="1456" type="line"/>
-			<point x="66" y="1185" type="line"/>
-			<point x="1075" y="1185" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/a.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/a.glif
deleted file mode 100644
index 885bf08..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/a.glif
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="a" format="2">
-	<unicode hex="0061"/>
-	<advance width="1091"/>
-	<outline>
-		<contour>
-			<point name="hr00" x="670" y="272" type="line"/>
-			<point x="670" y="169"/>
-			<point x="684" y="66"/>
-			<point x="715" y="0" type="curve"/>
-			<point x="1038" y="0" type="line"/>
-			<point x="1038" y="17" type="line"/>
-			<point x="1009" y="71"/>
-			<point x="993" y="132"/>
-			<point x="993" y="273" type="curve" smooth="yes"/>
-			<point x="993" y="716" type="line"/>
-			<point x="993" y="973"/>
-			<point x="803" y="1102"/>
-			<point x="548" y="1102" type="curve" smooth="yes"/>
-			<point x="262" y="1102"/>
-			<point x="78" y="950"/>
-			<point x="78" y="749" type="curve"/>
-			<point x="400" y="749" type="line"/>
-			<point x="400" y="828"/>
-			<point x="448" y="867"/>
-			<point x="531" y="867" type="curve" smooth="yes"/>
-			<point x="629" y="867"/>
-			<point x="670" y="809"/>
-			<point x="670" y="718" type="curve"/>
-		</contour>
-		<contour>
-			<point x="710" y="661" type="line"/>
-			<point x="558" y="661" type="line"/>
-			<point x="216" y="661"/>
-			<point x="53" y="528"/>
-			<point x="53" y="305" type="curve" smooth="yes"/>
-			<point x="53" y="113"/>
-			<point x="218" y="-20"/>
-			<point x="420" y="-20" type="curve" smooth="yes"/>
-			<point x="627" y="-20"/>
-			<point x="709" y="108"/>
-			<point x="758" y="214" type="curve"/>
-			<point x="683" y="352" type="line"/>
-			<point x="683" y="297"/>
-			<point x="612" y="220"/>
-			<point x="495" y="220" type="curve" smooth="yes"/>
-			<point x="424" y="220"/>
-			<point x="375" y="262"/>
-			<point x="375" y="323" type="curve" smooth="yes"/>
-			<point x="375" y="405"/>
-			<point x="425" y="481"/>
-			<point x="560" y="481" type="curve"/>
-			<point x="712" y="481" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/b.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/b.glif
deleted file mode 100644
index 728335c..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/b.glif
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="b" format="2">
-	<unicode hex="0062"/>
-	<advance width="1153"/>
-	<outline>
-		<contour>
-			<point x="102" y="1536" type="line"/>
-			<point x="102" y="0" type="line"/>
-			<point x="391" y="0" type="line"/>
-			<point x="424" y="266" type="line"/>
-			<point x="424" y="1536" type="line"/>
-		</contour>
-		<contour>
-			<point x="1095" y="553" type="line"/>
-			<point x="1095" y="870"/>
-			<point x="961" y="1102"/>
-			<point x="673" y="1102" type="curve" smooth="yes"/>
-			<point x="412" y="1102"/>
-			<point x="306" y="856"/>
-			<point x="264" y="554" type="curve"/>
-			<point x="264" y="529" type="line"/>
-			<point x="306" y="225"/>
-			<point x="412" y="-20"/>
-			<point x="675" y="-20" type="curve" smooth="yes"/>
-			<point x="961" y="-20"/>
-			<point x="1095" y="205"/>
-			<point x="1095" y="532" type="curve" smooth="yes"/>
-		</contour>
-		<contour>
-			<point x="773" y="532" type="line"/>
-			<point x="773" y="358"/>
-			<point x="745" y="239"/>
-			<point x="594" y="239" type="curve" smooth="yes"/>
-			<point x="445" y="239"/>
-			<point x="394" y="335"/>
-			<point x="394" y="502" type="curve" smooth="yes"/>
-			<point x="394" y="581" type="line" smooth="yes"/>
-			<point x="394" y="744"/>
-			<point x="445" y="842"/>
-			<point x="592" y="842" type="curve" smooth="yes"/>
-			<point x="741" y="842"/>
-			<point x="773" y="710"/>
-			<point x="773" y="553" type="curve" smooth="yes"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/c.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/c.glif
deleted file mode 100644
index 33db728..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/c.glif
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="c" format="2">
-	<unicode hex="0063"/>
-	<advance width="1066"/>
-	<outline>
-		<contour>
-			<point x="555" y="240" type="curve" smooth="yes"/>
-			<point x="404" y="240"/>
-			<point x="379" y="369"/>
-			<point x="379" y="529" type="curve" smooth="yes"/>
-			<point x="379" y="552" type="line" smooth="yes"/>
-			<point x="379" y="708"/>
-			<point x="405" y="842"/>
-			<point x="553" y="842" type="curve"/>
-			<point x="661" y="842"/>
-			<point x="714" y="765"/>
-			<point x="714" y="668" type="curve"/>
-			<point x="1016" y="668" type="line"/>
-			<point x="1016" y="943"/>
-			<point x="829" y="1102"/>
-			<point x="560" y="1102" type="curve" smooth="yes"/>
-			<point x="225" y="1102"/>
-			<point x="57" y="865"/>
-			<point x="57" y="552" type="curve" smooth="yes"/>
-			<point x="57" y="529" type="line" smooth="yes"/>
-			<point x="57" y="216"/>
-			<point x="225" y="-20"/>
-			<point x="562" y="-20" type="curve"/>
-			<point x="819" y="-20"/>
-			<point x="1016" y="142"/>
-			<point x="1016" y="386" type="curve"/>
-			<point x="714" y="386" type="line"/>
-			<point x="714" y="294"/>
-			<point x="653" y="240"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/contents.plist b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/contents.plist
deleted file mode 100644
index 431aca7..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/contents.plist
+++ /dev/null
@@ -1,112 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-	<dict>
-		<key>A</key>
-		<string>A_.glif</string>
-		<key>B</key>
-		<string>B_.glif</string>
-		<key>C</key>
-		<string>C_.glif</string>
-		<key>D</key>
-		<string>D_.glif</string>
-		<key>E</key>
-		<string>E_.glif</string>
-		<key>F</key>
-		<string>F_.glif</string>
-		<key>G</key>
-		<string>G_.glif</string>
-		<key>H</key>
-		<string>H_.glif</string>
-		<key>I</key>
-		<string>I_.glif</string>
-		<key>J</key>
-		<string>J_.glif</string>
-		<key>K</key>
-		<string>K_.glif</string>
-		<key>L</key>
-		<string>L_.glif</string>
-		<key>M</key>
-		<string>M_.glif</string>
-		<key>N</key>
-		<string>N_.glif</string>
-		<key>O</key>
-		<string>O_.glif</string>
-		<key>P</key>
-		<string>P_.glif</string>
-		<key>Q</key>
-		<string>Q_.glif</string>
-		<key>R</key>
-		<string>R_.glif</string>
-		<key>S</key>
-		<string>S_.glif</string>
-		<key>T</key>
-		<string>T_.glif</string>
-		<key>U</key>
-		<string>U_.glif</string>
-		<key>V</key>
-		<string>V_.glif</string>
-		<key>W</key>
-		<string>W_.glif</string>
-		<key>X</key>
-		<string>X_.glif</string>
-		<key>Y</key>
-		<string>Y_.glif</string>
-		<key>Z</key>
-		<string>Z_.glif</string>
-		<key>a</key>
-		<string>a.glif</string>
-		<key>b</key>
-		<string>b.glif</string>
-		<key>c</key>
-		<string>c.glif</string>
-		<key>d</key>
-		<string>d.glif</string>
-		<key>e</key>
-		<string>e.glif</string>
-		<key>f</key>
-		<string>f.glif</string>
-		<key>g</key>
-		<string>g.glif</string>
-		<key>h</key>
-		<string>h.glif</string>
-		<key>i</key>
-		<string>i.glif</string>
-		<key>j</key>
-		<string>j.glif</string>
-		<key>k</key>
-		<string>k.glif</string>
-		<key>l</key>
-		<string>l.glif</string>
-		<key>m</key>
-		<string>m.glif</string>
-		<key>n</key>
-		<string>n.glif</string>
-		<key>o</key>
-		<string>o.glif</string>
-		<key>p</key>
-		<string>p.glif</string>
-		<key>q</key>
-		<string>q.glif</string>
-		<key>r</key>
-		<string>r.glif</string>
-		<key>s</key>
-		<string>s.glif</string>
-		<key>space</key>
-		<string>space.glif</string>
-		<key>t</key>
-		<string>t.glif</string>
-		<key>u</key>
-		<string>u.glif</string>
-		<key>v</key>
-		<string>v.glif</string>
-		<key>w</key>
-		<string>w.glif</string>
-		<key>x</key>
-		<string>x.glif</string>
-		<key>y</key>
-		<string>y.glif</string>
-		<key>z</key>
-		<string>z.glif</string>
-	</dict>
-</plist>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/d.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/d.glif
deleted file mode 100644
index 9c7ac79..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/d.glif
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="d" format="2">
-	<unicode hex="0064"/>
-	<advance width="1153"/>
-	<outline>
-		<contour>
-			<point x="728" y="248" type="line"/>
-			<point x="761" y="0" type="line"/>
-			<point x="1051" y="0" type="line"/>
-			<point x="1051" y="1536" type="line"/>
-			<point x="728" y="1536" type="line"/>
-		</contour>
-		<contour>
-			<point x="57" y="528" type="line"/>
-			<point x="57" y="213"/>
-			<point x="205" y="-20"/>
-			<point x="477" y="-20" type="curve" smooth="yes"/>
-			<point x="728" y="-20"/>
-			<point x="848" y="227"/>
-			<point x="889" y="520" type="curve"/>
-			<point x="889" y="545" type="line"/>
-			<point x="848" y="858"/>
-			<point x="728" y="1102"/>
-			<point x="479" y="1102" type="curve" smooth="yes"/>
-			<point x="205" y="1102"/>
-			<point x="57" y="878"/>
-			<point x="57" y="549" type="curve" smooth="yes"/>
-		</contour>
-		<contour>
-			<point x="379" y="549" type="line"/>
-			<point x="379" y="717"/>
-			<point x="427" y="842"/>
-			<point x="561" y="842" type="curve" smooth="yes"/>
-			<point x="695" y="842"/>
-			<point x="759" y="748"/>
-			<point x="759" y="572" type="curve" smooth="yes"/>
-			<point x="759" y="493" type="line" smooth="yes"/>
-			<point x="759" y="339"/>
-			<point x="694" y="240"/>
-			<point x="559" y="240" type="curve" smooth="yes"/>
-			<point x="423" y="240"/>
-			<point x="379" y="366"/>
-			<point x="379" y="528" type="curve" smooth="yes"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/e.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/e.glif
deleted file mode 100644
index 71ee028..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/e.glif
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="e" format="2">
-	<unicode hex="0065"/>
-	<advance width="1113"/>
-	<outline>
-		<contour>
-			<point x="616" y="-20" type="curve" smooth="yes"/>
-			<point x="825" y="-20"/>
-			<point x="973" y="75"/>
-			<point x="1041" y="170" type="curve"/>
-			<point x="891" y="352" type="line"/>
-			<point x="827" y="272"/>
-			<point x="733" y="240"/>
-			<point x="637" y="240" type="curve" smooth="yes"/>
-			<point x="481" y="240"/>
-			<point x="387" y="345"/>
-			<point x="387" y="505" type="curve" smooth="yes"/>
-			<point x="387" y="543" type="line" smooth="yes"/>
-			<point x="387" y="704"/>
-			<point x="430" y="842"/>
-			<point x="579" y="842" type="curve" smooth="yes"/>
-			<point x="694" y="842"/>
-			<point x="753" y="779"/>
-			<point x="753" y="672" type="curve" smooth="yes"/>
-			<point x="753" y="646" type="line"/>
-			<point name="hr01" x="192" y="646" type="line"/>
-			<point x="192" y="435" type="line"/>
-			<point x="1068" y="435" type="line"/>
-			<point x="1068" y="572" type="line" smooth="yes"/>
-			<point x="1068" y="897"/>
-			<point x="890" y="1102"/>
-			<point x="581" y="1102" type="curve" smooth="yes"/>
-			<point x="246" y="1102"/>
-			<point x="65" y="859"/>
-			<point name="hr02" x="65" y="543" type="curve" smooth="yes"/>
-			<point x="65" y="505" type="line" smooth="yes"/>
-			<point x="65" y="221"/>
-			<point x="268" y="-20"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/f.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/f.glif
deleted file mode 100644
index deeb2d6..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/f.glif
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="f" format="2">
-	<unicode hex="0066"/>
-	<advance width="740"/>
-	<outline>
-		<contour>
-			<point name="hr00" x="499" y="0" type="line"/>
-			<point x="499" y="1170" type="line"/>
-			<point x="499" y="1252"/>
-			<point x="555" y="1297"/>
-			<point x="655" y="1297" type="curve" smooth="yes"/>
-			<point x="691" y="1297"/>
-			<point x="716" y="1294"/>
-			<point x="740" y="1288" type="curve"/>
-			<point x="740" y="1536" type="line"/>
-			<point x="692" y="1548"/>
-			<point x="641" y="1557"/>
-			<point x="585" y="1557" type="curve" smooth="yes"/>
-			<point x="334" y="1557"/>
-			<point x="176" y="1421"/>
-			<point x="176" y="1170" type="curve"/>
-			<point x="176" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="711" y="1082" type="line"/>
-			<point x="18" y="1082" type="line"/>
-			<point x="18" y="848" type="line"/>
-			<point x="711" y="848" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/g.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/g.glif
deleted file mode 100644
index 7618721..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/g.glif
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="g" format="2">
-	<unicode hex="0067"/>
-	<advance width="1176"/>
-	<outline>
-		<contour>
-			<point x="782" y="1082" type="line"/>
-			<point x="751" y="826" type="line"/>
-			<point x="751" y="44" type="line" smooth="yes"/>
-			<point x="751" y="-96"/>
-			<point x="669" y="-177"/>
-			<point x="521" y="-177" type="curve" smooth="yes"/>
-			<point x="411" y="-177"/>
-			<point x="326" y="-128"/>
-			<point x="268" y="-66" type="curve"/>
-			<point x="131" y="-264" type="line"/>
-			<point x="221" y="-370"/>
-			<point x="392" y="-426"/>
-			<point x="533" y="-426" type="curve" smooth="yes"/>
-			<point x="856" y="-426"/>
-			<point x="1074" y="-258"/>
-			<point x="1074" y="42" type="curve" smooth="yes"/>
-			<point x="1074" y="1082" type="line"/>
-		</contour>
-		<contour>
-			<point x="60" y="528" type="line"/>
-			<point x="60" y="213"/>
-			<point x="228" y="-20"/>
-			<point x="500" y="-20" type="curve" smooth="yes"/>
-			<point x="763" y="-20"/>
-			<point x="869" y="227"/>
-			<point x="912" y="520" type="curve"/>
-			<point x="912" y="545" type="line"/>
-			<point x="869" y="858"/>
-			<point x="795" y="1102"/>
-			<point x="502" y="1102" type="curve" smooth="yes"/>
-			<point x="228" y="1102"/>
-			<point x="60" y="878"/>
-			<point x="60" y="549" type="curve" smooth="yes"/>
-		</contour>
-		<contour>
-			<point x="382" y="549" type="line"/>
-			<point x="382" y="717"/>
-			<point x="450" y="842"/>
-			<point x="584" y="842" type="curve" smooth="yes"/>
-			<point x="731" y="842"/>
-			<point x="792" y="748"/>
-			<point x="792" y="572" type="curve" smooth="yes"/>
-			<point x="792" y="493" type="line" smooth="yes"/>
-			<point x="792" y="339"/>
-			<point x="731" y="240"/>
-			<point x="582" y="240" type="curve" smooth="yes"/>
-			<point x="446" y="240"/>
-			<point x="382" y="366"/>
-			<point x="382" y="528" type="curve" smooth="yes"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/h.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/h.glif
deleted file mode 100644
index 58e9754..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/h.glif
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="h" format="2">
-	<unicode hex="0068"/>
-	<advance width="1153"/>
-	<outline>
-		<contour>
-			<point x="415" y="1536" type="line"/>
-			<point x="93" y="1536" type="line"/>
-			<point x="93" y="0" type="line"/>
-			<point x="415" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="374" y="578" type="line"/>
-			<point x="374" y="729"/>
-			<point x="413" y="842"/>
-			<point x="573" y="842" type="curve" smooth="yes"/>
-			<point x="674" y="842"/>
-			<point x="733" y="806"/>
-			<point x="733" y="674" type="curve" smooth="yes"/>
-			<point x="733" y="0" type="line"/>
-			<point x="1056" y="0" type="line"/>
-			<point x="1056" y="672" type="line" smooth="yes"/>
-			<point x="1056" y="986"/>
-			<point x="909" y="1102"/>
-			<point x="695" y="1102" type="curve" smooth="yes"/>
-			<point x="454" y="1102"/>
-			<point x="295" y="880"/>
-			<point x="295" y="576" type="curve"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/i.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/i.glif
deleted file mode 100644
index be7bc25..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/i.glif
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="i" format="2">
-	<unicode hex="0069"/>
-	<advance width="557"/>
-	<outline>
-		<contour>
-			<point x="440" y="1082" type="line"/>
-			<point x="117" y="1082" type="line"/>
-			<point x="117" y="0" type="line"/>
-			<point x="440" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="98" y="1361" type="curve" smooth="yes"/>
-			<point x="98" y="1265"/>
-			<point x="170" y="1197"/>
-			<point x="277" y="1197" type="curve" smooth="yes"/>
-			<point x="384" y="1197"/>
-			<point x="456" y="1265"/>
-			<point x="456" y="1361" type="curve" smooth="yes"/>
-			<point x="456" y="1457"/>
-			<point x="384" y="1525"/>
-			<point x="277" y="1525" type="curve" smooth="yes"/>
-			<point x="170" y="1525"/>
-			<point x="98" y="1457"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/j.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/j.glif
deleted file mode 100644
index 1ac2ef3..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/j.glif
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="j" format="2">
-	<unicode hex="006A"/>
-	<advance width="547"/>
-	<outline>
-		<contour>
-			<point x="122" y="1082" type="line"/>
-			<point x="122" y="-35" type="line"/>
-			<point x="122" y="-129"/>
-			<point x="73" y="-174"/>
-			<point x="-16" y="-174" type="curve" smooth="yes"/>
-			<point x="-49" y="-174"/>
-			<point x="-77" y="-170"/>
-			<point x="-110" y="-165" type="curve"/>
-			<point x="-110" y="-420" type="line"/>
-			<point x="-55" y="-433"/>
-			<point x="-10" y="-437"/>
-			<point x="45" y="-437" type="curve" smooth="yes"/>
-			<point x="294" y="-437"/>
-			<point x="445" y="-295"/>
-			<point x="445" y="-35" type="curve"/>
-			<point x="445" y="1082" type="line"/>
-		</contour>
-		<contour>
-			<point x="98" y="1361" type="curve" smooth="yes"/>
-			<point x="98" y="1265"/>
-			<point x="170" y="1197"/>
-			<point x="277" y="1197" type="curve" smooth="yes"/>
-			<point x="384" y="1197"/>
-			<point x="456" y="1265"/>
-			<point x="456" y="1361" type="curve" smooth="yes"/>
-			<point x="456" y="1457"/>
-			<point x="384" y="1525"/>
-			<point x="277" y="1525" type="curve" smooth="yes"/>
-			<point x="170" y="1525"/>
-			<point x="98" y="1457"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/k.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/k.glif
deleted file mode 100644
index 9f329d4..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/k.glif
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="k" format="2">
-	<unicode hex="006B"/>
-	<advance width="1112"/>
-	<outline>
-		<contour>
-			<point x="424" y="1537" type="line"/>
-			<point x="102" y="1537" type="line"/>
-			<point x="102" y="0" type="line"/>
-			<point x="424" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="1112" y="1082" type="line"/>
-			<point x="726" y="1082" type="line"/>
-			<point x="465" y="766" type="line"/>
-			<point x="261" y="499" type="line"/>
-			<point x="394" y="285" type="line"/>
-			<point x="643" y="531" type="line"/>
-		</contour>
-		<contour>
-			<point x="771" y="0" type="line"/>
-			<point x="1140" y="0" type="line"/>
-			<point x="706" y="670" type="line"/>
-			<point x="473" y="493" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/l.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/l.glif
deleted file mode 100644
index 3156475..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/l.glif
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="l" format="2">
-	<unicode hex="006C"/>
-	<advance width="557"/>
-	<outline>
-		<contour>
-			<point x="440" y="1536" type="line"/>
-			<point x="117" y="1536" type="line"/>
-			<point x="117" y="0" type="line"/>
-			<point x="440" y="0" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/m.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/m.glif
deleted file mode 100644
index 93ed63a..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/m.glif
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="m" format="2">
-	<unicode hex="006D"/>
-	<advance width="1767"/>
-	<outline>
-		<contour>
-			<point x="424" y="853" type="line"/>
-			<point x="404" y="1082" type="line"/>
-			<point x="102" y="1082" type="line"/>
-			<point x="102" y="0" type="line"/>
-			<point x="424" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="383" y="578" type="line"/>
-			<point x="383" y="729"/>
-			<point x="452" y="842"/>
-			<point x="581" y="842" type="curve" smooth="yes"/>
-			<point x="670" y="842"/>
-			<point x="722" y="816"/>
-			<point x="722" y="679" type="curve"/>
-			<point x="722" y="0" type="line"/>
-			<point x="1044" y="0" type="line"/>
-			<point x="1044" y="722" type="line"/>
-			<point x="1044" y="992"/>
-			<point x="914" y="1102"/>
-			<point x="724" y="1102" type="curve" smooth="yes"/>
-			<point x="450" y="1102"/>
-			<point x="304" y="880"/>
-			<point x="304" y="576" type="curve"/>
-		</contour>
-		<contour>
-			<point x="1010" y="578" type="line"/>
-			<point x="1010" y="729"/>
-			<point x="1072" y="842"/>
-			<point x="1202" y="842" type="curve" smooth="yes"/>
-			<point x="1289" y="842"/>
-			<point x="1342" y="815"/>
-			<point x="1342" y="681" type="curve" smooth="yes"/>
-			<point x="1342" y="0" type="line"/>
-			<point x="1665" y="0" type="line"/>
-			<point x="1665" y="681" type="line" smooth="yes"/>
-			<point x="1665" y="995"/>
-			<point x="1526" y="1102"/>
-			<point x="1324" y="1102" type="curve" smooth="yes"/>
-			<point x="1050" y="1102"/>
-			<point x="911" y="880"/>
-			<point x="911" y="576" type="curve"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/n.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/n.glif
deleted file mode 100644
index 092570b..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/n.glif
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="n" format="2">
-	<unicode hex="006E"/>
-	<advance width="1153"/>
-	<outline>
-		<contour>
-			<point x="416" y="851" type="line"/>
-			<point x="396" y="1082" type="line"/>
-			<point x="94" y="1082" type="line"/>
-			<point x="94" y="0" type="line"/>
-			<point x="416" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="375" y="578" type="line"/>
-			<point x="375" y="729"/>
-			<point x="431" y="842"/>
-			<point x="574" y="842" type="curve" smooth="yes"/>
-			<point x="675" y="842"/>
-			<point x="733" y="812"/>
-			<point x="733" y="682" type="curve"/>
-			<point x="733" y="0" type="line"/>
-			<point x="1056" y="0" type="line"/>
-			<point x="1056" y="681" type="line"/>
-			<point x="1056" y="995"/>
-			<point x="918" y="1102"/>
-			<point x="716" y="1102" type="curve" smooth="yes"/>
-			<point x="464" y="1102"/>
-			<point x="296" y="907"/>
-			<point x="296" y="576" type="curve"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/o.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/o.glif
deleted file mode 100644
index b5836f7..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/o.glif
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="o" format="2">
-	<unicode hex="006F"/>
-	<advance width="1153"/>
-	<outline>
-		<contour>
-			<point x="57" y="530" type="line"/>
-			<point x="57" y="214"/>
-			<point x="241" y="-20"/>
-			<point x="577" y="-20" type="curve" smooth="yes"/>
-			<point x="912" y="-20"/>
-			<point x="1095" y="214"/>
-			<point x="1095" y="530" type="curve"/>
-			<point x="1095" y="551" type="line"/>
-			<point x="1095" y="867"/>
-			<point x="912" y="1102"/>
-			<point x="575" y="1102" type="curve" smooth="yes"/>
-			<point x="241" y="1102"/>
-			<point x="57" y="867"/>
-			<point x="57" y="551" type="curve"/>
-		</contour>
-		<contour>
-			<point x="379" y="551" type="line"/>
-			<point x="379" y="709"/>
-			<point x="427" y="842"/>
-			<point x="575" y="842" type="curve" smooth="yes"/>
-			<point x="726" y="842"/>
-			<point x="773" y="709"/>
-			<point x="773" y="551" type="curve"/>
-			<point x="773" y="530" type="line"/>
-			<point x="773" y="367"/>
-			<point x="725" y="240"/>
-			<point x="577" y="240" type="curve" smooth="yes"/>
-			<point x="426" y="240"/>
-			<point x="379" y="367"/>
-			<point x="379" y="530" type="curve"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/p.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/p.glif
deleted file mode 100644
index 4989434..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/p.glif
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="p" format="2">
-	<unicode hex="0070"/>
-	<advance width="1153"/>
-	<outline>
-		<contour>
-			<point x="424" y="874" type="line"/>
-			<point x="402" y="1082" type="line"/>
-			<point x="102" y="1082" type="line"/>
-			<point x="102" y="-416" type="line"/>
-			<point x="424" y="-416" type="line"/>
-		</contour>
-		<contour>
-			<point x="1095" y="554" type="line"/>
-			<point x="1095" y="883"/>
-			<point x="948" y="1102"/>
-			<point x="673" y="1102" type="curve" smooth="yes"/>
-			<point x="412" y="1102"/>
-			<point x="306" y="863"/>
-			<point x="264" y="550" type="curve"/>
-			<point x="264" y="523" type="line"/>
-			<point x="306" y="231"/>
-			<point x="412" y="-20"/>
-			<point x="675" y="-20" type="curve" smooth="yes"/>
-			<point x="948" y="-20"/>
-			<point x="1095" y="218"/>
-			<point x="1095" y="533" type="curve" smooth="yes"/>
-		</contour>
-		<contour>
-			<point x="773" y="533" type="line"/>
-			<point x="773" y="371"/>
-			<point x="729" y="240"/>
-			<point x="594" y="240" type="curve" smooth="yes"/>
-			<point x="445" y="240"/>
-			<point x="394" y="343"/>
-			<point x="394" y="495" type="curve" smooth="yes"/>
-			<point x="394" y="577" type="line" smooth="yes"/>
-			<point x="394" y="753"/>
-			<point x="445" y="842"/>
-			<point x="592" y="842" type="curve" smooth="yes"/>
-			<point x="725" y="842"/>
-			<point x="773" y="722"/>
-			<point x="773" y="554" type="curve" smooth="yes"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/q.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/q.glif
deleted file mode 100644
index 78a3914..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/q.glif
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="q" format="2">
-	<unicode hex="0071"/>
-	<advance width="1153"/>
-	<outline>
-		<contour>
-			<point x="728" y="-416" type="line"/>
-			<point x="1051" y="-416" type="line"/>
-			<point x="1051" y="1082" type="line"/>
-			<point x="771" y="1082" type="line"/>
-			<point x="728" y="855" type="line"/>
-		</contour>
-		<contour>
-			<point x="57" y="531" type="line"/>
-			<point x="57" y="216"/>
-			<point x="205" y="-20"/>
-			<point x="477" y="-20" type="curve" smooth="yes"/>
-			<point x="740" y="-20"/>
-			<point x="846" y="230"/>
-			<point x="889" y="523" type="curve"/>
-			<point x="889" y="548" type="line"/>
-			<point x="846" y="861"/>
-			<point x="740" y="1102"/>
-			<point x="479" y="1102" type="curve" smooth="yes"/>
-			<point x="205" y="1102"/>
-			<point x="57" y="881"/>
-			<point x="57" y="552" type="curve" smooth="yes"/>
-		</contour>
-		<contour>
-			<point x="379" y="552" type="line"/>
-			<point x="379" y="720"/>
-			<point x="427" y="842"/>
-			<point x="561" y="842" type="curve" smooth="yes"/>
-			<point x="708" y="842"/>
-			<point x="759" y="751"/>
-			<point x="759" y="575" type="curve" smooth="yes"/>
-			<point x="759" y="496" type="line" smooth="yes"/>
-			<point x="759" y="342"/>
-			<point x="708" y="240"/>
-			<point x="559" y="240" type="curve" smooth="yes"/>
-			<point x="423" y="240"/>
-			<point x="379" y="369"/>
-			<point x="379" y="531" type="curve" smooth="yes"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/r.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/r.glif
deleted file mode 100644
index e4e388a..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/r.glif
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="r" format="2">
-	<unicode hex="0072"/>
-	<advance width="767"/>
-	<outline>
-		<contour>
-			<point x="424" y="814" type="line"/>
-			<point x="404" y="1082" type="line"/>
-			<point x="102" y="1082" type="line"/>
-			<point x="102" y="0" type="line"/>
-			<point x="424" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="745" y="1090" type="line"/>
-			<point x="721" y="1098"/>
-			<point x="685" y="1102"/>
-			<point x="653" y="1102" type="curve"/>
-			<point x="459" y="1102"/>
-			<point x="343" y="902"/>
-			<point x="343" y="612" type="curve"/>
-			<point x="403" y="572" type="line"/>
-			<point x="403" y="714"/>
-			<point x="472" y="785"/>
-			<point x="631" y="785" type="curve"/>
-			<point x="661" y="785"/>
-			<point x="712" y="780"/>
-			<point x="740" y="777" type="curve"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/s.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/s.glif
deleted file mode 100644
index c46d75c..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/s.glif
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="s" format="2">
-	<unicode hex="0073"/>
-	<advance width="1051"/>
-	<outline>
-		<contour>
-			<point x="673" y="304" type="curve" smooth="yes"/>
-			<point x="673" y="244"/>
-			<point x="622" y="203"/>
-			<point x="525" y="203" type="curve" smooth="yes"/>
-			<point x="424" y="203"/>
-			<point x="348" y="247"/>
-			<point x="344" y="347" type="curve"/>
-			<point x="42" y="347" type="line"/>
-			<point x="42" y="173"/>
-			<point x="208" y="-20"/>
-			<point x="517" y="-20" type="curve" smooth="yes"/>
-			<point x="803" y="-20"/>
-			<point x="984" y="123"/>
-			<point x="984" y="314" type="curve"/>
-			<point x="984" y="543"/>
-			<point x="792" y="619"/>
-			<point x="569" y="659" type="curve" smooth="yes"/>
-			<point x="435" y="683"/>
-			<point x="382" y="719"/>
-			<point x="382" y="777" type="curve"/>
-			<point x="382" y="839"/>
-			<point x="438" y="880"/>
-			<point x="516" y="880" type="curve" smooth="yes"/>
-			<point x="620" y="880"/>
-			<point x="662" y="832"/>
-			<point x="662" y="750" type="curve"/>
-			<point x="984" y="750" type="line"/>
-			<point x="984" y="958"/>
-			<point x="805" y="1102"/>
-			<point x="517" y="1102" type="curve" smooth="yes"/>
-			<point x="238" y="1102"/>
-			<point x="76" y="943"/>
-			<point x="76" y="760" type="curve"/>
-			<point x="76" y="570"/>
-			<point x="243" y="472"/>
-			<point x="458" y="426" type="curve" smooth="yes"/>
-			<point x="629" y="389"/>
-			<point x="673" y="359"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/space.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/space.glif
deleted file mode 100644
index 52850f2..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/space.glif
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="space" format="1">
-  <advance width="510"/>
-  <unicode hex="0020"/>
-  <outline>
-  </outline>
-  <lib>
-  <dict>
-  <key>com.typemytype.robofont.guides</key>
-  <array>
-    <dict>
-      <key>angle</key>
-      <real>0</real>
-      <key>isGlobal</key>
-      <false/>
-      <key>magnetic</key>
-      <integer>5</integer>
-      <key>x</key>
-      <real>0</real>
-      <key>y</key>
-      <real>901</real>
-    </dict>
-    <dict>
-      <key>angle</key>
-      <real>0</real>
-      <key>isGlobal</key>
-      <false/>
-      <key>magnetic</key>
-      <integer>5</integer>
-      <key>x</key>
-      <real>0</real>
-      <key>y</key>
-      <real>555</real>
-    </dict>
-  </array>
-  </dict>
-  </lib>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/t.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/t.glif
deleted file mode 100644
index 2639d1d..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/t.glif
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="t" format="2">
-	<unicode hex="0074"/>
-	<advance width="700"/>
-	<outline>
-		<contour>
-			<point x="658" y="1082" type="line"/>
-			<point x="12" y="1082" type="line"/>
-			<point x="12" y="848" type="line"/>
-			<point x="658" y="848" type="line"/>
-		</contour>
-		<contour>
-			<point x="156" y="1351" type="line"/>
-			<point x="156" y="311" type="line"/>
-			<point x="156" y="76"/>
-			<point x="279" y="-20"/>
-			<point x="487" y="-20" type="curve" smooth="yes"/>
-			<point x="558" y="-20"/>
-			<point x="617" y="-10"/>
-			<point x="672" y="9" type="curve"/>
-			<point x="672" y="250" type="line"/>
-			<point x="650" y="246"/>
-			<point x="625" y="244"/>
-			<point x="588" y="244" type="curve" smooth="yes"/>
-			<point x="508" y="244"/>
-			<point x="478" y="267"/>
-			<point x="478" y="353" type="curve"/>
-			<point x="478" y="1351" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/u.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/u.glif
deleted file mode 100644
index 4ee3072..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/u.glif
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="u" format="2">
-	<unicode hex="0075"/>
-	<advance width="1153"/>
-	<outline>
-		<contour>
-			<point x="734" y="263" type="line"/>
-			<point x="755" y="0" type="line"/>
-			<point x="1057" y="0" type="line"/>
-			<point x="1057" y="1082" type="line"/>
-			<point x="734" y="1082" type="line"/>
-		</contour>
-		<contour>
-			<point x="767" y="483" type="line"/>
-			<point x="767" y="344"/>
-			<point x="718" y="240"/>
-			<point x="557" y="240" type="curve" smooth="yes"/>
-			<point x="469" y="240"/>
-			<point x="416" y="285"/>
-			<point x="416" y="380" type="curve"/>
-			<point x="416" y="1082" type="line"/>
-			<point x="94" y="1082" type="line"/>
-			<point x="94" y="382" type="line"/>
-			<point x="94" y="96"/>
-			<point x="241" y="-20"/>
-			<point x="455" y="-20" type="curve" smooth="yes"/>
-			<point x="716" y="-20"/>
-			<point x="854" y="194"/>
-			<point x="854" y="485" type="curve"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/v.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/v.glif
deleted file mode 100644
index 2c06870..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/v.glif
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="v" format="2">
-	<unicode hex="0076"/>
-	<advance width="1051"/>
-	<outline>
-		<contour>
-			<point x="483" y="231" type="line"/>
-			<point x="483" y="0" type="line"/>
-			<point x="685" y="0" type="line"/>
-			<point x="1042" y="1082" type="line"/>
-			<point x="704" y="1082" type="line"/>
-		</contour>
-		<contour>
-			<point x="345" y="1082" type="line"/>
-			<point x="6" y="1082" type="line"/>
-			<point x="363" y="0" type="line"/>
-			<point x="565" y="0" type="line"/>
-			<point x="565" y="231" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/w.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/w.glif
deleted file mode 100644
index 08b32ac..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/w.glif
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="w" format="2">
-	<unicode hex="0077"/>
-	<advance width="1493"/>
-	<outline>
-		<contour>
-			<point x="422" y="322" type="line"/>
-			<point x="392" y="0" type="line"/>
-			<point x="557" y="0" type="line"/>
-			<point x="764" y="701" type="line"/>
-			<point x="833" y="1082" type="line"/>
-			<point x="631" y="1082" type="line"/>
-		</contour>
-		<contour>
-			<point x="333" y="1082" type="line"/>
-			<point x="24" y="1082" type="line"/>
-			<point x="286" y="0" type="line"/>
-			<point x="483" y="0" type="line"/>
-			<point x="470" y="328" type="line"/>
-		</contour>
-		<contour>
-			<point x="1019" y="344" type="line"/>
-			<point x="1007" y="0" type="line"/>
-			<point x="1204" y="0" type="line"/>
-			<point x="1465" y="1082" type="line"/>
-			<point x="1156" y="1082" type="line"/>
-		</contour>
-		<contour>
-			<point x="858" y="1082" type="line"/>
-			<point x="661" y="1082" type="line"/>
-			<point x="727" y="699" type="line"/>
-			<point x="932" y="0" type="line"/>
-			<point x="1098" y="0" type="line"/>
-			<point x="1068" y="324" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/x.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/x.glif
deleted file mode 100644
index 0a5d8b6..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/x.glif
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="x" format="2">
-	<unicode hex="0078"/>
-	<advance width="1051"/>
-	<outline>
-		<contour>
-			<point x="370" y="1082" type="line"/>
-			<point x="30" y="1082" type="line"/>
-			<point x="321" y="555" type="line"/>
-			<point x="15" y="0" type="line"/>
-			<point x="355" y="0" type="line"/>
-			<point x="530" y="320" type="line"/>
-			<point x="707" y="0" type="line"/>
-			<point x="1046" y="0" type="line"/>
-			<point x="740" y="555" type="line"/>
-			<point x="1032" y="1082" type="line"/>
-			<point x="695" y="1082" type="line"/>
-			<point x="530" y="784" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/y.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/y.glif
deleted file mode 100644
index 01015df..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/y.glif
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="y" format="2">
-	<unicode hex="0079"/>
-	<advance width="1051"/>
-	<outline>
-		<contour>
-			<point x="428" y="127" type="line"/>
-			<point x="347" y="-82" type="line"/>
-			<point x="324" y="-143"/>
-			<point x="285" y="-176"/>
-			<point x="175" y="-176" type="curve" smooth="yes"/>
-			<point x="160" y="-176"/>
-			<point x="147" y="-176"/>
-			<point x="131" y="-176" type="curve"/>
-			<point x="131" y="-417" type="line"/>
-			<point x="187" y="-432"/>
-			<point x="205" y="-437"/>
-			<point x="267" y="-437" type="curve" smooth="yes"/>
-			<point x="508" y="-437"/>
-			<point x="583" y="-270"/>
-			<point x="621" y="-161" type="curve" smooth="yes"/>
-			<point x="1055" y="1082" type="line"/>
-			<point x="710" y="1082" type="line"/>
-		</contour>
-		<contour>
-			<point x="343" y="1082" type="line"/>
-			<point x="-2" y="1082" type="line"/>
-			<point x="384" y="-32" type="line"/>
-			<point x="600" y="-32" type="line"/>
-			<point x="562" y="325" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/z.glif b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/z.glif
deleted file mode 100644
index ab555dc..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/glyphs/z.glif
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="z" format="2">
-	<unicode hex="007A"/>
-	<advance width="1051"/>
-	<outline>
-		<contour>
-			<point x="981" y="260" type="line"/>
-			<point x="149" y="260" type="line"/>
-			<point x="149" y="0" type="line"/>
-			<point x="981" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="969" y="900" type="line"/>
-			<point x="969" y="1082" type="line"/>
-			<point x="749" y="1082" type="line"/>
-			<point x="69" y="188" type="line"/>
-			<point x="69" y="0" type="line"/>
-			<point x="288" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="861" y="1082" type="line"/>
-			<point x="88" y="1082" type="line"/>
-			<point x="88" y="822" type="line"/>
-			<point x="861" y="822" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/layercontents.plist b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/layercontents.plist
deleted file mode 100644
index 03e5dde..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/layercontents.plist
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-	<array>
-		<array>
-			<string>public.default</string>
-			<string>glyphs</string>
-		</array>
-	</array>
-</plist>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/lib.plist b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/lib.plist
deleted file mode 100644
index 5623ed1..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/lib.plist
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-	<dict>
-		<key>public.glyphOrder</key>
-		<array>
-			<string>space</string>
-			<string>A</string>
-			<string>B</string>
-			<string>C</string>
-			<string>D</string>
-			<string>E</string>
-			<string>F</string>
-			<string>G</string>
-			<string>H</string>
-			<string>I</string>
-			<string>J</string>
-			<string>K</string>
-			<string>L</string>
-			<string>M</string>
-			<string>N</string>
-			<string>O</string>
-			<string>P</string>
-			<string>Q</string>
-			<string>R</string>
-			<string>S</string>
-			<string>T</string>
-			<string>U</string>
-			<string>V</string>
-			<string>W</string>
-			<string>X</string>
-			<string>Y</string>
-			<string>Z</string>
-			<string>a</string>
-			<string>b</string>
-			<string>c</string>
-			<string>d</string>
-			<string>e</string>
-			<string>f</string>
-			<string>g</string>
-			<string>h</string>
-			<string>i</string>
-			<string>j</string>
-			<string>k</string>
-			<string>l</string>
-			<string>m</string>
-			<string>n</string>
-			<string>o</string>
-			<string>p</string>
-			<string>q</string>
-			<string>r</string>
-			<string>s</string>
-			<string>t</string>
-			<string>u</string>
-			<string>v</string>
-			<string>w</string>
-			<string>x</string>
-			<string>y</string>
-			<string>z</string>
-		</array>
-	</dict>
-</plist>
diff --git a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/metainfo.plist b/Tests/cu2qu/data/RobotoSubset-Bold.ufo/metainfo.plist
deleted file mode 100644
index edfd637..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Bold.ufo/metainfo.plist
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-	<dict>
-		<key>creator</key>
-		<string>org.robofab.ufoLib</string>
-		<key>formatVersion</key>
-		<integer>3</integer>
-	</dict>
-</plist>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/fontinfo.plist b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/fontinfo.plist
deleted file mode 100644
index 28e318e..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/fontinfo.plist
+++ /dev/null
@@ -1,214 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-	<dict>
-		<key>ascender</key>
-		<integer>2146</integer>
-		<key>capHeight</key>
-		<integer>1456</integer>
-		<key>copyright</key>
-		<string>Copyright 2011 Google Inc. All Rights Reserved.</string>
-		<key>descender</key>
-		<integer>-555</integer>
-		<key>familyName</key>
-		<string>RobotoSubset</string>
-		<key>guidelines</key>
-		<array>
-		</array>
-		<key>italicAngle</key>
-		<integer>0</integer>
-		<key>openTypeHeadCreated</key>
-		<string>2008/09/12 12:29:34</string>
-		<key>openTypeHeadFlags</key>
-		<array>
-			<integer>0</integer>
-			<integer>1</integer>
-			<integer>3</integer>
-			<integer>4</integer>
-		</array>
-		<key>openTypeHeadLowestRecPPEM</key>
-		<integer>9</integer>
-		<key>openTypeHheaAscender</key>
-		<integer>1900</integer>
-		<key>openTypeHheaDescender</key>
-		<integer>-500</integer>
-		<key>openTypeHheaLineGap</key>
-		<integer>0</integer>
-		<key>openTypeNameDescription</key>
-		<string></string>
-		<key>openTypeNameDesigner</key>
-		<string></string>
-		<key>openTypeNameDesignerURL</key>
-		<string></string>
-		<key>openTypeNameLicense</key>
-		<string></string>
-		<key>openTypeNameLicenseURL</key>
-		<string></string>
-		<key>openTypeNameManufacturer</key>
-		<string></string>
-		<key>openTypeNameManufacturerURL</key>
-		<string></string>
-		<key>openTypeNameSampleText</key>
-		<string></string>
-		<key>openTypeOS2CodePageRanges</key>
-		<array>
-			<integer>0</integer>
-			<integer>1</integer>
-			<integer>2</integer>
-			<integer>3</integer>
-			<integer>4</integer>
-			<integer>7</integer>
-			<integer>8</integer>
-			<integer>29</integer>
-		</array>
-		<key>openTypeOS2FamilyClass</key>
-		<array>
-			<integer>0</integer>
-			<integer>0</integer>
-		</array>
-		<key>openTypeOS2Panose</key>
-		<array>
-			<integer>2</integer>
-			<integer>0</integer>
-			<integer>0</integer>
-			<integer>0</integer>
-			<integer>0</integer>
-			<integer>0</integer>
-			<integer>0</integer>
-			<integer>0</integer>
-			<integer>0</integer>
-			<integer>0</integer>
-		</array>
-		<key>openTypeOS2Selection</key>
-		<array>
-		</array>
-		<key>openTypeOS2StrikeoutPosition</key>
-		<integer>512</integer>
-		<key>openTypeOS2StrikeoutSize</key>
-		<integer>102</integer>
-		<key>openTypeOS2SubscriptXOffset</key>
-		<integer>0</integer>
-		<key>openTypeOS2SubscriptXSize</key>
-		<integer>1434</integer>
-		<key>openTypeOS2SubscriptYOffset</key>
-		<integer>287</integer>
-		<key>openTypeOS2SubscriptYSize</key>
-		<integer>1331</integer>
-		<key>openTypeOS2SuperscriptXOffset</key>
-		<integer>0</integer>
-		<key>openTypeOS2SuperscriptXSize</key>
-		<integer>1434</integer>
-		<key>openTypeOS2SuperscriptYOffset</key>
-		<integer>977</integer>
-		<key>openTypeOS2SuperscriptYSize</key>
-		<integer>1331</integer>
-		<key>openTypeOS2Type</key>
-		<array>
-		</array>
-		<key>openTypeOS2TypoAscender</key>
-		<integer>2146</integer>
-		<key>openTypeOS2TypoDescender</key>
-		<integer>-555</integer>
-		<key>openTypeOS2TypoLineGap</key>
-		<integer>0</integer>
-		<key>openTypeOS2UnicodeRanges</key>
-		<array>
-			<integer>0</integer>
-			<integer>1</integer>
-			<integer>2</integer>
-			<integer>3</integer>
-			<integer>4</integer>
-			<integer>5</integer>
-			<integer>6</integer>
-			<integer>7</integer>
-			<integer>9</integer>
-			<integer>11</integer>
-			<integer>29</integer>
-			<integer>30</integer>
-			<integer>31</integer>
-			<integer>32</integer>
-			<integer>33</integer>
-			<integer>34</integer>
-			<integer>35</integer>
-			<integer>36</integer>
-			<integer>37</integer>
-			<integer>38</integer>
-			<integer>40</integer>
-			<integer>45</integer>
-			<integer>60</integer>
-			<integer>62</integer>
-			<integer>64</integer>
-			<integer>69</integer>
-		</array>
-		<key>openTypeOS2VendorID</key>
-		<string>GOOG</string>
-		<key>openTypeOS2WeightClass</key>
-		<integer>400</integer>
-		<key>openTypeOS2WidthClass</key>
-		<integer>5</integer>
-		<key>openTypeOS2WinAscent</key>
-		<integer>2146</integer>
-		<key>openTypeOS2WinDescent</key>
-		<integer>555</integer>
-		<key>postscriptBlueFuzz</key>
-		<integer>1</integer>
-		<key>postscriptBlueScale</key>
-		<real>0.039625</real>
-		<key>postscriptBlueShift</key>
-		<integer>7</integer>
-		<key>postscriptBlueValues</key>
-		<array>
-			<integer>-20</integer>
-			<integer>0</integer>
-			<integer>1082</integer>
-			<integer>1102</integer>
-			<integer>1456</integer>
-			<integer>1476</integer>
-		</array>
-		<key>postscriptDefaultCharacter</key>
-		<string>space</string>
-		<key>postscriptFamilyBlues</key>
-		<array>
-		</array>
-		<key>postscriptFamilyOtherBlues</key>
-		<array>
-		</array>
-		<key>postscriptForceBold</key>
-		<false/>
-		<key>postscriptIsFixedPitch</key>
-		<false/>
-		<key>postscriptOtherBlues</key>
-		<array>
-			<integer>-436</integer>
-			<integer>-416</integer>
-		</array>
-		<key>postscriptStemSnapH</key>
-		<array>
-			<integer>154</integer>
-		</array>
-		<key>postscriptStemSnapV</key>
-		<array>
-			<integer>196</integer>
-		</array>
-		<key>postscriptUnderlinePosition</key>
-		<integer>-150</integer>
-		<key>postscriptUnderlineThickness</key>
-		<integer>100</integer>
-		<key>postscriptUniqueID</key>
-		<integer>-1</integer>
-		<key>styleName</key>
-		<string>Regular</string>
-		<key>trademark</key>
-		<string></string>
-		<key>unitsPerEm</key>
-		<integer>2048</integer>
-		<key>versionMajor</key>
-		<integer>1</integer>
-		<key>versionMinor</key>
-		<integer>0</integer>
-		<key>xHeight</key>
-		<integer>1082</integer>
-		<key>year</key>
-		<integer>2017</integer>
-	</dict>
-</plist>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/A_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/A_.glif
deleted file mode 100644
index 8f070f2..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/A_.glif
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="A" format="2">
-	<unicode hex="0041"/>
-	<advance width="1349"/>
-	<outline>
-		<contour>
-			<point x="718" y="1320" type="line"/>
-			<point x="720" y="1456" type="line"/>
-			<point x="585" y="1456" type="line"/>
-			<point x="28" y="0" type="line"/>
-			<point x="241" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="1110" y="0" type="line"/>
-			<point x="1323" y="0" type="line"/>
-			<point x="765" y="1456" type="line"/>
-			<point x="630" y="1456" type="line"/>
-			<point x="632" y="1320" type="line"/>
-		</contour>
-		<contour>
-			<point x="1099" y="543" type="line"/>
-			<point x="271" y="543" type="line"/>
-			<point x="271" y="376" type="line"/>
-			<point x="1099" y="376" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/B_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/B_.glif
deleted file mode 100644
index 2a5194a..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/B_.glif
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="B" format="2">
-	<unicode hex="0042"/>
-	<advance width="1280"/>
-	<outline>
-		<contour>
-			<point x="688" y="678" type="line"/>
-			<point x="755" y="726" type="line"/>
-			<point x="976" y="752"/>
-			<point x="1128" y="887"/>
-			<point x="1128" y="1067" type="curve"/>
-			<point x="1128" y="1339"/>
-			<point x="951" y="1456"/>
-			<point x="653" y="1456" type="curve"/>
-			<point x="166" y="1456" type="line"/>
-			<point x="166" y="0" type="line"/>
-			<point x="374" y="0" type="line"/>
-			<point x="374" y="1289" type="line"/>
-			<point x="653" y="1289" type="line"/>
-			<point x="834" y="1289"/>
-			<point x="920" y="1224"/>
-			<point x="920" y="1068" type="curve"/>
-			<point x="920" y="927"/>
-			<point x="812" y="841"/>
-			<point x="657" y="841" type="curve"/>
-			<point x="327" y="841" type="line"/>
-			<point x="329" y="678" type="line"/>
-		</contour>
-		<contour>
-			<point x="679" y="0" type="line"/>
-			<point x="973" y="0"/>
-			<point x="1164" y="148"/>
-			<point x="1164" y="422" type="curve" smooth="yes"/>
-			<point x="1164" y="610"/>
-			<point x="1048" y="764"/>
-			<point x="835" y="782" type="curve"/>
-			<point x="790" y="841" type="line"/>
-			<point x="411" y="841" type="line"/>
-			<point x="409" y="678" type="line"/>
-			<point x="688" y="678" type="line" smooth="yes"/>
-			<point x="877" y="678"/>
-			<point x="956" y="581"/>
-			<point x="956" y="420" type="curve" smooth="yes"/>
-			<point x="956" y="265"/>
-			<point x="855" y="166"/>
-			<point x="679" y="166" type="curve" smooth="yes"/>
-			<point x="364" y="166" type="line"/>
-			<point x="244" y="0" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/C_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/C_.glif
deleted file mode 100644
index eaabcee..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/C_.glif
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="C" format="2">
-	<unicode hex="0043"/>
-	<advance width="1334"/>
-	<outline>
-		<contour>
-			<point x="1038" y="464" type="line"/>
-			<point x="1005" y="266"/>
-			<point x="933" y="146"/>
-			<point x="690" y="146" type="curve" smooth="yes"/>
-			<point x="434" y="146"/>
-			<point x="325" y="378"/>
-			<point x="325" y="658" type="curve" smooth="yes"/>
-			<point x="325" y="799" type="line" smooth="yes"/>
-			<point x="325" y="1104"/>
-			<point x="454" y="1309"/>
-			<point x="709" y="1309" type="curve" smooth="yes"/>
-			<point x="928" y="1309"/>
-			<point x="1009" y="1184"/>
-			<point x="1038" y="987" type="curve"/>
-			<point x="1246" y="987" type="line"/>
-			<point x="1216" y="1272"/>
-			<point x="1043" y="1476"/>
-			<point x="709" y="1476" type="curve" smooth="yes"/>
-			<point x="344" y="1476"/>
-			<point x="117" y="1207"/>
-			<point x="117" y="797" type="curve"/>
-			<point x="117" y="658" type="line"/>
-			<point x="117" y="248"/>
-			<point x="345" y="-20"/>
-			<point x="690" y="-20" type="curve" smooth="yes"/>
-			<point x="1046" y="-20"/>
-			<point x="1215" y="192"/>
-			<point x="1246" y="464" type="curve"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/D_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/D_.glif
deleted file mode 100644
index b89cff9..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/D_.glif
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="D" format="2">
-	<unicode hex="0044"/>
-	<advance width="1344"/>
-	<outline>
-		<contour>
-			<point x="559" y="0" type="line"/>
-			<point x="969" y="0"/>
-			<point x="1225" y="263"/>
-			<point x="1225" y="688" type="curve"/>
-			<point x="1225" y="767" type="line"/>
-			<point x="1225" y="1192"/>
-			<point x="965" y="1456"/>
-			<point x="578" y="1456" type="curve"/>
-			<point x="254" y="1456" type="line"/>
-			<point x="254" y="1289" type="line"/>
-			<point x="578" y="1289" type="line"/>
-			<point x="863" y="1289"/>
-			<point x="1019" y="1102"/>
-			<point x="1019" y="769" type="curve"/>
-			<point x="1019" y="688" type="line" smooth="yes"/>
-			<point x="1019" y="371"/>
-			<point x="869" y="166"/>
-			<point x="559" y="166" type="curve"/>
-			<point x="262" y="166" type="line"/>
-			<point x="260" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="374" y="1456" type="line"/>
-			<point x="166" y="1456" type="line"/>
-			<point x="166" y="0" type="line"/>
-			<point x="374" y="0" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/E_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/E_.glif
deleted file mode 100644
index 14f1ad9..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/E_.glif
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="E" format="2">
-	<unicode hex="0045"/>
-	<advance width="1164"/>
-	<outline>
-		<contour>
-			<point x="1095" y="166" type="line"/>
-			<point x="335" y="166" type="line"/>
-			<point x="335" y="0" type="line"/>
-			<point x="1095" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="374" y="1456" type="line"/>
-			<point x="166" y="1456" type="line"/>
-			<point x="166" y="0" type="line"/>
-			<point x="374" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="993" y="835" type="line"/>
-			<point x="335" y="835" type="line"/>
-			<point x="335" y="669" type="line"/>
-			<point x="993" y="669" type="line"/>
-		</contour>
-		<contour>
-			<point x="1084" y="1456" type="line"/>
-			<point x="335" y="1456" type="line"/>
-			<point x="335" y="1289" type="line"/>
-			<point x="1084" y="1289" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/F_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/F_.glif
deleted file mode 100644
index 77ffdb8..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/F_.glif
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="F" format="2">
-	<unicode hex="0046"/>
-	<advance width="1128"/>
-	<outline>
-		<contour>
-			<point x="374" y="1456" type="line"/>
-			<point x="166" y="1456" type="line"/>
-			<point x="166" y="0" type="line"/>
-			<point x="374" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="969" y="803" type="line"/>
-			<point x="332" y="803" type="line"/>
-			<point x="332" y="637" type="line"/>
-			<point x="969" y="637" type="line"/>
-		</contour>
-		<contour>
-			<point x="1068" y="1456" type="line"/>
-			<point x="332" y="1456" type="line"/>
-			<point x="332" y="1289" type="line"/>
-			<point x="1068" y="1289" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/G_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/G_.glif
deleted file mode 100644
index dd03d17..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/G_.glif
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="G" format="2">
-	<unicode hex="0047"/>
-	<advance width="1394"/>
-	<outline>
-		<contour>
-			<point x="1247" y="731" type="line"/>
-			<point x="715" y="731" type="line"/>
-			<point x="715" y="566" type="line"/>
-			<point x="1040" y="566" type="line"/>
-			<point x="1040" y="248" type="line"/>
-			<point x="1002" y="206"/>
-			<point x="934" y="146"/>
-			<point x="731" y="146" type="curve" smooth="yes"/>
-			<point x="489" y="146"/>
-			<point x="326" y="341"/>
-			<point x="326" y="676" type="curve" smooth="yes"/>
-			<point x="326" y="781" type="line" smooth="yes"/>
-			<point x="326" y="1108"/>
-			<point x="440" y="1309"/>
-			<point x="708" y="1309" type="curve" smooth="yes"/>
-			<point x="922" y="1309"/>
-			<point x="1012" y="1181"/>
-			<point x="1039" y="1027" type="curve"/>
-			<point x="1247" y="1027" type="line"/>
-			<point x="1209" y="1287"/>
-			<point x="1042" y="1476"/>
-			<point x="707" y="1476" type="curve" smooth="yes"/>
-			<point x="325" y="1476"/>
-			<point x="117" y="1219"/>
-			<point x="117" y="779" type="curve" smooth="yes"/>
-			<point x="117" y="676" type="line" smooth="yes"/>
-			<point x="117" y="236"/>
-			<point x="373" y="-20"/>
-			<point x="730" y="-20" type="curve" smooth="yes"/>
-			<point x="1061" y="-20"/>
-			<point x="1191" y="114"/>
-			<point x="1247" y="195" type="curve"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/H_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/H_.glif
deleted file mode 100644
index fa6876c..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/H_.glif
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="H" format="2">
-	<unicode hex="0048"/>
-	<advance width="1463"/>
-	<outline>
-		<contour>
-			<point x="1110" y="835" type="line"/>
-			<point x="344" y="835" type="line"/>
-			<point x="344" y="669" type="line"/>
-			<point x="1110" y="669" type="line"/>
-		</contour>
-		<contour>
-			<point x="374" y="1456" type="line"/>
-			<point x="166" y="1456" type="line"/>
-			<point x="166" y="0" type="line"/>
-			<point x="374" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="1294" y="1456" type="line"/>
-			<point x="1086" y="1456" type="line"/>
-			<point x="1086" y="0" type="line"/>
-			<point x="1294" y="0" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/I_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/I_.glif
deleted file mode 100644
index cdf1ebf..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/I_.glif
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="I" format="2">
-	<unicode hex="0049"/>
-	<advance width="560"/>
-	<outline>
-		<contour>
-			<point x="385" y="1456" type="line"/>
-			<point x="177" y="1456" type="line"/>
-			<point x="177" y="0" type="line"/>
-			<point x="385" y="0" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/J_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/J_.glif
deleted file mode 100644
index 34346b7..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/J_.glif
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="J" format="2">
-	<unicode hex="004A"/>
-	<advance width="1131"/>
-	<outline>
-		<contour>
-			<point x="769" y="424" type="line"/>
-			<point x="769" y="242"/>
-			<point x="660" y="146"/>
-			<point x="513" y="146" type="curve" smooth="yes"/>
-			<point x="366" y="146"/>
-			<point x="257" y="224"/>
-			<point x="257" y="403" type="curve"/>
-			<point x="49" y="403" type="line"/>
-			<point x="49" y="116"/>
-			<point x="244" y="-20"/>
-			<point x="513" y="-20" type="curve" smooth="yes"/>
-			<point x="784" y="-20"/>
-			<point x="977" y="136"/>
-			<point x="977" y="424" type="curve"/>
-			<point x="977" y="1456" type="line"/>
-			<point x="769" y="1456" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/K_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/K_.glif
deleted file mode 100644
index 2c27124..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/K_.glif
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="K" format="2">
-	<unicode hex="004B"/>
-	<advance width="1283"/>
-	<outline>
-		<contour>
-			<point x="374" y="1456" type="line"/>
-			<point x="166" y="1456" type="line"/>
-			<point x="166" y="0" type="line"/>
-			<point x="374" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="1248" y="1456" type="line"/>
-			<point x="999" y="1456" type="line"/>
-			<point x="523" y="918" type="line"/>
-			<point x="267" y="632" type="line"/>
-			<point x="303" y="415" type="line"/>
-			<point x="648" y="775" type="line"/>
-		</contour>
-		<contour>
-			<point x="1044" y="0" type="line"/>
-			<point x="1292" y="0" type="line"/>
-			<point x="645" y="866" type="line"/>
-			<point x="521" y="703" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/L_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/L_.glif
deleted file mode 100644
index 85d578d..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/L_.glif
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="L" format="2">
-	<unicode hex="004C"/>
-	<advance width="1108"/>
-	<outline>
-		<contour>
-			<point x="1058" y="166" type="line"/>
-			<point x="335" y="166" type="line"/>
-			<point x="335" y="0" type="line"/>
-			<point x="1058" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="374" y="1456" type="line"/>
-			<point x="166" y="1456" type="line"/>
-			<point x="166" y="0" type="line"/>
-			<point x="374" y="0" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/M_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/M_.glif
deleted file mode 100644
index f67a855..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/M_.glif
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="M" format="2">
-	<unicode hex="004D"/>
-	<advance width="1792"/>
-	<outline>
-		<contour>
-			<point x="231" y="1456" type="line"/>
-			<point x="816" y="0" type="line"/>
-			<point x="974" y="0" type="line"/>
-			<point x="1560" y="1456" type="line"/>
-			<point x="1358" y="1456" type="line"/>
-			<point x="896" y="285" type="line"/>
-			<point x="433" y="1456" type="line"/>
-		</contour>
-		<contour>
-			<point x="166" y="1456" type="line"/>
-			<point x="166" y="0" type="line"/>
-			<point x="373" y="0" type="line"/>
-			<point x="373" y="556" type="line"/>
-			<point x="343" y="1456" type="line"/>
-		</contour>
-		<contour>
-			<point x="1448" y="1456" type="line"/>
-			<point x="1418" y="556" type="line"/>
-			<point x="1418" y="0" type="line"/>
-			<point x="1625" y="0" type="line"/>
-			<point x="1625" y="1456" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/N_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/N_.glif
deleted file mode 100644
index 70b3869..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/N_.glif
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="N" format="2">
-	<unicode hex="004E"/>
-	<advance width="1462"/>
-	<outline>
-		<contour>
-			<point x="1293" y="1456" type="line"/>
-			<point x="1087" y="1456" type="line"/>
-			<point x="1087" y="350" type="line"/>
-			<point x="374" y="1456" type="line"/>
-			<point x="166" y="1456" type="line"/>
-			<point x="166" y="0" type="line"/>
-			<point x="374" y="0" type="line"/>
-			<point x="374" y="1102" type="line"/>
-			<point x="1084" y="0" type="line"/>
-			<point x="1293" y="0" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/O_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/O_.glif
deleted file mode 100644
index 6d87c26..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/O_.glif
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="O" format="2">
-	<unicode hex="004F"/>
-	<advance width="1414"/>
-	<outline>
-		<contour>
-			<point x="1296" y="768" type="line"/>
-			<point x="1296" y="1209"/>
-			<point x="1063" y="1476"/>
-			<point x="706" y="1476" type="curve" smooth="yes"/>
-			<point x="360" y="1476"/>
-			<point x="117" y="1209"/>
-			<point x="117" y="768" type="curve"/>
-			<point x="117" y="687" type="line"/>
-			<point x="117" y="246"/>
-			<point x="362" y="-20"/>
-			<point x="708" y="-20" type="curve" smooth="yes"/>
-			<point x="1065" y="-20"/>
-			<point x="1296" y="246"/>
-			<point x="1296" y="687" type="curve"/>
-		</contour>
-		<contour>
-			<point x="1090" y="687" type="line"/>
-			<point x="1090" y="338"/>
-			<point x="952" y="153"/>
-			<point x="708" y="153" type="curve" smooth="yes"/>
-			<point x="478" y="153"/>
-			<point x="323" y="338"/>
-			<point x="323" y="687" type="curve" smooth="yes"/>
-			<point x="323" y="770" type="line" smooth="yes"/>
-			<point x="323" y="1117"/>
-			<point x="476" y="1302"/>
-			<point x="706" y="1302" type="curve" smooth="yes"/>
-			<point x="948" y="1302"/>
-			<point x="1090" y="1117"/>
-			<point x="1090" y="770" type="curve"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/P_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/P_.glif
deleted file mode 100644
index 81622d1..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/P_.glif
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="P" format="2">
-	<unicode hex="0050"/>
-	<advance width="1299"/>
-	<outline>
-		<contour>
-			<point x="712" y="567" type="line"/>
-			<point x="1044" y="567"/>
-			<point x="1227" y="727"/>
-			<point x="1227" y="1010" type="curve"/>
-			<point x="1227" y="1269"/>
-			<point x="1044" y="1456"/>
-			<point x="712" y="1456" type="curve"/>
-			<point x="166" y="1456" type="line"/>
-			<point x="166" y="0" type="line"/>
-			<point x="374" y="0" type="line"/>
-			<point x="374" y="1289" type="line"/>
-			<point x="712" y="1289" type="line"/>
-			<point x="930" y="1289"/>
-			<point x="1019" y="1153"/>
-			<point x="1019" y="1008" type="curve"/>
-			<point x="1019" y="846"/>
-			<point x="930" y="733"/>
-			<point x="712" y="733" type="curve"/>
-			<point x="329" y="733" type="line"/>
-			<point x="329" y="567" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/Q_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/Q_.glif
deleted file mode 100644
index 9dfc7f6..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/Q_.glif
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="Q" format="2">
-	<unicode hex="0051"/>
-	<advance width="1414"/>
-	<outline>
-		<contour>
-			<point x="918" y="176" type="line"/>
-			<point x="785" y="45" type="line"/>
-			<point x="1156" y="-245" type="line"/>
-			<point x="1297" y="-117" type="line"/>
-		</contour>
-		<contour>
-			<point x="1287" y="768" type="line"/>
-			<point x="1287" y="1209"/>
-			<point x="1054" y="1476"/>
-			<point x="696" y="1476" type="curve" smooth="yes"/>
-			<point x="350" y="1476"/>
-			<point x="107" y="1209"/>
-			<point x="107" y="768" type="curve"/>
-			<point x="107" y="687" type="line"/>
-			<point x="107" y="246"/>
-			<point x="352" y="-20"/>
-			<point x="698" y="-20" type="curve" smooth="yes"/>
-			<point x="1056" y="-20"/>
-			<point x="1287" y="246"/>
-			<point x="1287" y="687" type="curve"/>
-		</contour>
-		<contour>
-			<point x="1080" y="687" type="line"/>
-			<point x="1080" y="338"/>
-			<point x="942" y="153"/>
-			<point x="698" y="153" type="curve" smooth="yes"/>
-			<point x="469" y="153"/>
-			<point x="314" y="338"/>
-			<point x="314" y="687" type="curve" smooth="yes"/>
-			<point x="314" y="770" type="line" smooth="yes"/>
-			<point x="314" y="1117"/>
-			<point x="467" y="1302"/>
-			<point x="696" y="1302" type="curve" smooth="yes"/>
-			<point x="939" y="1302"/>
-			<point x="1080" y="1117"/>
-			<point x="1080" y="770" type="curve"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/R_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/R_.glif
deleted file mode 100644
index 8d35190..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/R_.glif
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="R" format="2">
-	<unicode hex="0052"/>
-	<advance width="1253"/>
-	<outline>
-		<contour>
-			<point x="166" y="1456" type="line"/>
-			<point x="166" y="0" type="line"/>
-			<point x="374" y="0" type="line"/>
-			<point x="374" y="1289" type="line"/>
-			<point x="650" y="1289" type="line" smooth="yes"/>
-			<point x="868" y="1289"/>
-			<point x="956" y="1180"/>
-			<point x="956" y="1017" type="curve" smooth="yes"/>
-			<point x="956" y="869"/>
-			<point x="854" y="753"/>
-			<point x="651" y="753" type="curve" smooth="yes"/>
-			<point x="327" y="753" type="line"/>
-			<point x="329" y="587" type="line"/>
-			<point x="770" y="587" type="line"/>
-			<point x="827" y="609" type="line"/>
-			<point x="1039" y="666"/>
-			<point x="1164" y="818"/>
-			<point x="1164" y="1017" type="curve" smooth="yes"/>
-			<point x="1164" y="1303"/>
-			<point x="983" y="1456"/>
-			<point x="650" y="1456" type="curve" smooth="yes"/>
-		</contour>
-		<contour>
-			<point x="1006" y="0" type="line"/>
-			<point x="1229" y="0" type="line"/>
-			<point x="1229" y="12" type="line"/>
-			<point x="874" y="662" type="line"/>
-			<point x="657" y="662" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/S_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/S_.glif
deleted file mode 100644
index 8bc81ce..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/S_.glif
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="S" format="2">
-	<unicode hex="0053"/>
-	<advance width="1216"/>
-	<outline>
-		<contour>
-			<point x="931" y="370" type="curve" smooth="yes"/>
-			<point x="931" y="232"/>
-			<point x="826" y="146"/>
-			<point x="631" y="146" type="curve" smooth="yes"/>
-			<point x="446" y="146"/>
-			<point x="287" y="232"/>
-			<point x="287" y="423" type="curve"/>
-			<point x="79" y="423" type="line"/>
-			<point x="79" y="136"/>
-			<point x="360" y="-20"/>
-			<point x="631" y="-20" type="curve" smooth="yes"/>
-			<point x="942" y="-20"/>
-			<point x="1140" y="135"/>
-			<point x="1140" y="372" type="curve"/>
-			<point x="1140" y="596"/>
-			<point x="998" y="727"/>
-			<point x="663" y="822" type="curve"/>
-			<point x="435" y="886"/>
-			<point x="334" y="959"/>
-			<point x="334" y="1079" type="curve"/>
-			<point x="334" y="1212"/>
-			<point x="423" y="1309"/>
-			<point x="621" y="1309" type="curve" smooth="yes"/>
-			<point x="834" y="1309"/>
-			<point x="930" y="1194"/>
-			<point x="930" y="1035" type="curve"/>
-			<point x="1138" y="1035" type="line"/>
-			<point x="1138" y="1260"/>
-			<point x="955" y="1476"/>
-			<point x="621" y="1476" type="curve" smooth="yes"/>
-			<point x="320" y="1476"/>
-			<point x="125" y="1303"/>
-			<point x="125" y="1076" type="curve"/>
-			<point x="125" y="851"/>
-			<point x="309" y="728"/>
-			<point x="596" y="644" type="curve"/>
-			<point x="865" y="565"/>
-			<point x="931" y="502"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/T_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/T_.glif
deleted file mode 100644
index dff2656..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/T_.glif
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="T" format="2">
-	<unicode hex="0054"/>
-	<advance width="1222"/>
-	<outline>
-		<contour>
-			<point x="715" y="1456" type="line"/>
-			<point x="509" y="1456" type="line"/>
-			<point x="509" y="0" type="line"/>
-			<point x="715" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="1176" y="1456" type="line"/>
-			<point x="49" y="1456" type="line"/>
-			<point x="49" y="1289" type="line"/>
-			<point x="1176" y="1289" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/U_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/U_.glif
deleted file mode 100644
index ee592bc..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/U_.glif
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="U" format="2">
-	<unicode hex="0055"/>
-	<advance width="1324"/>
-	<outline>
-		<contour>
-			<point x="988" y="1456" type="line"/>
-			<point x="988" y="471" type="line" smooth="yes"/>
-			<point x="988" y="248"/>
-			<point x="860" y="146"/>
-			<point x="664" y="146" type="curve" smooth="yes"/>
-			<point x="470" y="146"/>
-			<point x="341" y="248"/>
-			<point x="341" y="471" type="curve" smooth="yes"/>
-			<point x="341" y="1456" type="line"/>
-			<point x="135" y="1456" type="line"/>
-			<point x="135" y="471" type="line"/>
-			<point x="135" y="143"/>
-			<point x="366" y="-20"/>
-			<point x="664" y="-20" type="curve" smooth="yes"/>
-			<point x="946" y="-20"/>
-			<point x="1196" y="143"/>
-			<point x="1196" y="471" type="curve"/>
-			<point x="1196" y="1456" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/V_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/V_.glif
deleted file mode 100644
index 232cc55..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/V_.glif
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="V" format="2">
-	<unicode hex="0056"/>
-	<advance width="1313"/>
-	<outline>
-		<contour>
-			<point x="639" y="228" type="line"/>
-			<point x="588" y="0" type="line"/>
-			<point x="748" y="0" type="line"/>
-			<point x="1287" y="1456" type="line"/>
-			<point x="1061" y="1456" type="line"/>
-		</contour>
-		<contour>
-			<point x="254" y="1456" type="line"/>
-			<point x="28" y="1456" type="line"/>
-			<point x="566" y="0" type="line"/>
-			<point x="726" y="0" type="line"/>
-			<point x="672" y="228" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/W_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/W_.glif
deleted file mode 100644
index 4c1b017..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/W_.glif
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="W" format="2">
-	<unicode hex="0057"/>
-	<advance width="1813"/>
-	<outline>
-		<contour>
-			<point x="552" y="450" type="line"/>
-			<point x="448" y="0" type="line"/>
-			<point x="597" y="0" type="line"/>
-			<point x="902" y="1048" type="line"/>
-			<point x="984" y="1456" type="line"/>
-			<point x="834" y="1456" type="line"/>
-		</contour>
-		<contour>
-			<point x="268" y="1456" type="line"/>
-			<point x="61" y="1456" type="line"/>
-			<point x="409" y="0" type="line"/>
-			<point x="556" y="0" type="line"/>
-			<point x="490" y="471" type="line"/>
-		</contour>
-		<contour>
-			<point x="1346" y="472" type="line"/>
-			<point x="1276" y="0" type="line"/>
-			<point x="1423" y="0" type="line"/>
-			<point x="1771" y="1456" type="line"/>
-			<point x="1563" y="1456" type="line"/>
-		</contour>
-		<contour>
-			<point x="1007" y="1456" type="line"/>
-			<point x="860" y="1456" type="line"/>
-			<point x="942" y="1048" type="line"/>
-			<point x="1235" y="0" type="line"/>
-			<point x="1384" y="0" type="line"/>
-			<point x="1281" y="450" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/X_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/X_.glif
deleted file mode 100644
index a8547b3..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/X_.glif
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="X" format="2">
-	<unicode hex="0058"/>
-	<advance width="1291"/>
-	<outline>
-		<contour>
-			<point x="311" y="1456" type="line"/>
-			<point x="68" y="1456" type="line"/>
-			<point x="524" y="734" type="line"/>
-			<point x="58" y="0" type="line"/>
-			<point x="303" y="0" type="line"/>
-			<point x="648" y="557" type="line"/>
-			<point x="992" y="0" type="line"/>
-			<point x="1237" y="0" type="line"/>
-			<point x="772" y="734" type="line"/>
-			<point x="1227" y="1456" type="line"/>
-			<point x="984" y="1456" type="line"/>
-			<point x="648" y="908" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/Y_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/Y_.glif
deleted file mode 100644
index 6d48150..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/Y_.glif
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="Y" format="2">
-	<unicode hex="0059"/>
-	<advance width="1231"/>
-	<outline>
-		<contour>
-			<point x="250" y="1456" type="line"/>
-			<point x="13" y="1456" type="line"/>
-			<point x="510" y="543" type="line"/>
-			<point x="510" y="0" type="line"/>
-			<point x="718" y="0" type="line"/>
-			<point x="718" y="543" type="line"/>
-			<point x="1215" y="1456" type="line"/>
-			<point x="979" y="1456" type="line"/>
-			<point x="614" y="736" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/Z_.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/Z_.glif
deleted file mode 100644
index 6b5dfc4..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/Z_.glif
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="Z" format="2">
-	<unicode hex="005A"/>
-	<advance width="1227"/>
-	<outline>
-		<contour>
-			<point x="1148" y="166" type="line"/>
-			<point x="165" y="166" type="line"/>
-			<point x="165" y="0" type="line"/>
-			<point x="1148" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="1116" y="1307" type="line"/>
-			<point x="1116" y="1456" type="line"/>
-			<point x="987" y="1456" type="line"/>
-			<point x="86" y="153" type="line"/>
-			<point x="86" y="0" type="line"/>
-			<point x="214" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="1028" y="1456" type="line"/>
-			<point x="96" y="1456" type="line"/>
-			<point x="96" y="1289" type="line"/>
-			<point x="1028" y="1289" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/a.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/a.glif
deleted file mode 100644
index 7d8a2cd..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/a.glif
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="a" format="2">
-	<unicode hex="0061"/>
-	<advance width="1118"/>
-	<outline>
-		<contour>
-			<point x="771" y="183" type="line"/>
-			<point x="771" y="123"/>
-			<point x="782" y="41"/>
-			<point x="802" y="0" type="curve"/>
-			<point x="1010" y="0" type="line"/>
-			<point x="1010" y="17" type="line"/>
-			<point x="984" y="76"/>
-			<point x="971" y="166"/>
-			<point x="971" y="238" type="curve" smooth="yes"/>
-			<point x="971" y="738" type="line"/>
-			<point x="971" y="981"/>
-			<point x="803" y="1102"/>
-			<point x="566" y="1102" type="curve" smooth="yes"/>
-			<point x="301" y="1102"/>
-			<point x="133" y="935"/>
-			<point x="133" y="782" type="curve"/>
-			<point x="333" y="782" type="line"/>
-			<point x="333" y="867"/>
-			<point x="421" y="945"/>
-			<point x="554" y="945" type="curve" smooth="yes"/>
-			<point x="697" y="945"/>
-			<point x="771" y="864"/>
-			<point x="771" y="740" type="curve"/>
-		</contour>
-		<contour>
-			<point x="804" y="661" type="line"/>
-			<point x="596" y="661" type="line"/>
-			<point x="301" y="661"/>
-			<point x="111" y="539"/>
-			<point x="111" y="303" type="curve" smooth="yes"/>
-			<point x="111" y="123"/>
-			<point x="257" y="-20"/>
-			<point x="480" y="-20" type="curve" smooth="yes"/>
-			<point x="711" y="-20"/>
-			<point x="857" y="170"/>
-			<point x="874" y="277" type="curve"/>
-			<point x="789" y="370" type="line"/>
-			<point x="789" y="279"/>
-			<point x="673" y="151"/>
-			<point x="510" y="151" type="curve" smooth="yes"/>
-			<point x="377" y="151"/>
-			<point x="311" y="230"/>
-			<point x="311" y="331" type="curve" smooth="yes"/>
-			<point x="311" y="462"/>
-			<point x="425" y="524"/>
-			<point x="629" y="524" type="curve"/>
-			<point x="806" y="524" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/b.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/b.glif
deleted file mode 100644
index f009d99..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/b.glif
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="b" format="2">
-	<unicode hex="0062"/>
-	<advance width="1153"/>
-	<outline>
-		<contour>
-			<point x="137" y="1536" type="line"/>
-			<point x="137" y="0" type="line"/>
-			<point x="320" y="0" type="line"/>
-			<point x="337" y="210" type="line"/>
-			<point x="337" y="1536" type="line"/>
-		</contour>
-		<contour>
-			<point x="1063" y="550" type="line"/>
-			<point x="1063" y="879"/>
-			<point x="912" y="1102"/>
-			<point x="639" y="1102" type="curve" smooth="yes"/>
-			<point x="362" y="1102"/>
-			<point x="230" y="901"/>
-			<point x="200" y="572" type="curve"/>
-			<point x="200" y="510" type="line"/>
-			<point x="230" y="181"/>
-			<point x="362" y="-20"/>
-			<point x="641" y="-20" type="curve" smooth="yes"/>
-			<point x="910" y="-20"/>
-			<point x="1063" y="214"/>
-			<point x="1063" y="529" type="curve" smooth="yes"/>
-		</contour>
-		<contour>
-			<point x="863" y="529" type="line"/>
-			<point x="863" y="320"/>
-			<point x="785" y="146"/>
-			<point x="590" y="146" type="curve" smooth="yes"/>
-			<point x="411" y="146"/>
-			<point x="327" y="287"/>
-			<point x="296" y="426" type="curve"/>
-			<point x="296" y="655" type="line"/>
-			<point x="326" y="803"/>
-			<point x="411" y="937"/>
-			<point x="588" y="937" type="curve" smooth="yes"/>
-			<point x="794" y="937"/>
-			<point x="863" y="759"/>
-			<point x="863" y="550" type="curve" smooth="yes"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/c.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/c.glif
deleted file mode 100644
index 727fef4..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/c.glif
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="c" format="2">
-	<unicode hex="0063"/>
-	<advance width="1076"/>
-	<outline>
-		<contour>
-			<point x="578" y="140" type="curve" smooth="yes"/>
-			<point x="352" y="140"/>
-			<point x="292" y="337"/>
-			<point x="292" y="520" type="curve" smooth="yes"/>
-			<point x="292" y="562" type="line" smooth="yes"/>
-			<point x="292" y="743"/>
-			<point x="354" y="942"/>
-			<point x="578" y="942" type="curve"/>
-			<point x="723" y="942"/>
-			<point x="813" y="835"/>
-			<point x="823" y="709" type="curve"/>
-			<point x="1012" y="709" type="line"/>
-			<point x="1002" y="929"/>
-			<point x="836" y="1102"/>
-			<point x="578" y="1102" type="curve" smooth="yes"/>
-			<point x="248" y="1102"/>
-			<point x="92" y="850"/>
-			<point x="92" y="562" type="curve" smooth="yes"/>
-			<point x="92" y="520" type="line" smooth="yes"/>
-			<point x="92" y="232"/>
-			<point x="247" y="-20"/>
-			<point x="578" y="-20" type="curve"/>
-			<point x="809" y="-20"/>
-			<point x="1002" y="153"/>
-			<point x="1012" y="343" type="curve"/>
-			<point x="823" y="343" type="line"/>
-			<point x="813" y="229"/>
-			<point x="706" y="140"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/contents.plist b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/contents.plist
deleted file mode 100644
index 431aca7..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/contents.plist
+++ /dev/null
@@ -1,112 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-	<dict>
-		<key>A</key>
-		<string>A_.glif</string>
-		<key>B</key>
-		<string>B_.glif</string>
-		<key>C</key>
-		<string>C_.glif</string>
-		<key>D</key>
-		<string>D_.glif</string>
-		<key>E</key>
-		<string>E_.glif</string>
-		<key>F</key>
-		<string>F_.glif</string>
-		<key>G</key>
-		<string>G_.glif</string>
-		<key>H</key>
-		<string>H_.glif</string>
-		<key>I</key>
-		<string>I_.glif</string>
-		<key>J</key>
-		<string>J_.glif</string>
-		<key>K</key>
-		<string>K_.glif</string>
-		<key>L</key>
-		<string>L_.glif</string>
-		<key>M</key>
-		<string>M_.glif</string>
-		<key>N</key>
-		<string>N_.glif</string>
-		<key>O</key>
-		<string>O_.glif</string>
-		<key>P</key>
-		<string>P_.glif</string>
-		<key>Q</key>
-		<string>Q_.glif</string>
-		<key>R</key>
-		<string>R_.glif</string>
-		<key>S</key>
-		<string>S_.glif</string>
-		<key>T</key>
-		<string>T_.glif</string>
-		<key>U</key>
-		<string>U_.glif</string>
-		<key>V</key>
-		<string>V_.glif</string>
-		<key>W</key>
-		<string>W_.glif</string>
-		<key>X</key>
-		<string>X_.glif</string>
-		<key>Y</key>
-		<string>Y_.glif</string>
-		<key>Z</key>
-		<string>Z_.glif</string>
-		<key>a</key>
-		<string>a.glif</string>
-		<key>b</key>
-		<string>b.glif</string>
-		<key>c</key>
-		<string>c.glif</string>
-		<key>d</key>
-		<string>d.glif</string>
-		<key>e</key>
-		<string>e.glif</string>
-		<key>f</key>
-		<string>f.glif</string>
-		<key>g</key>
-		<string>g.glif</string>
-		<key>h</key>
-		<string>h.glif</string>
-		<key>i</key>
-		<string>i.glif</string>
-		<key>j</key>
-		<string>j.glif</string>
-		<key>k</key>
-		<string>k.glif</string>
-		<key>l</key>
-		<string>l.glif</string>
-		<key>m</key>
-		<string>m.glif</string>
-		<key>n</key>
-		<string>n.glif</string>
-		<key>o</key>
-		<string>o.glif</string>
-		<key>p</key>
-		<string>p.glif</string>
-		<key>q</key>
-		<string>q.glif</string>
-		<key>r</key>
-		<string>r.glif</string>
-		<key>s</key>
-		<string>s.glif</string>
-		<key>space</key>
-		<string>space.glif</string>
-		<key>t</key>
-		<string>t.glif</string>
-		<key>u</key>
-		<string>u.glif</string>
-		<key>v</key>
-		<string>v.glif</string>
-		<key>w</key>
-		<string>w.glif</string>
-		<key>x</key>
-		<string>x.glif</string>
-		<key>y</key>
-		<string>y.glif</string>
-		<key>z</key>
-		<string>z.glif</string>
-	</dict>
-</plist>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/d.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/d.glif
deleted file mode 100644
index c585788..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/d.glif
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="d" format="2">
-	<unicode hex="0064"/>
-	<advance width="1159"/>
-	<outline>
-		<contour>
-			<point x="815" y="210" type="line"/>
-			<point x="832" y="0" type="line"/>
-			<point x="1015" y="0" type="line"/>
-			<point x="1015" y="1536" type="line"/>
-			<point x="815" y="1536" type="line"/>
-		</contour>
-		<contour>
-			<point x="92" y="529" type="line"/>
-			<point x="92" y="214"/>
-			<point x="266" y="-20"/>
-			<point x="520" y="-20" type="curve" smooth="yes"/>
-			<point x="798" y="-20"/>
-			<point x="931" y="181"/>
-			<point x="960" y="510" type="curve"/>
-			<point x="960" y="572" type="line"/>
-			<point x="931" y="901"/>
-			<point x="798" y="1102"/>
-			<point x="522" y="1102" type="curve" smooth="yes"/>
-			<point x="264" y="1102"/>
-			<point x="92" y="879"/>
-			<point x="92" y="550" type="curve" smooth="yes"/>
-		</contour>
-		<contour>
-			<point x="292" y="550" type="line"/>
-			<point x="292" y="759"/>
-			<point x="375" y="937"/>
-			<point x="573" y="937" type="curve" smooth="yes"/>
-			<point x="750" y="937"/>
-			<point x="834" y="803"/>
-			<point x="865" y="655" type="curve"/>
-			<point x="865" y="426" type="line"/>
-			<point x="824" y="277"/>
-			<point x="750" y="146"/>
-			<point x="571" y="146" type="curve" smooth="yes"/>
-			<point x="375" y="146"/>
-			<point x="292" y="320"/>
-			<point x="292" y="529" type="curve" smooth="yes"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/e.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/e.glif
deleted file mode 100644
index 29d3ecd..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/e.glif
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="e" format="2">
-	<unicode hex="0065"/>
-	<advance width="1092"/>
-	<outline>
-		<contour>
-			<point x="593" y="-20" type="curve"/>
-			<point x="812" y="-20"/>
-			<point x="936" y="85"/>
-			<point x="1006" y="192" type="curve"/>
-			<point x="885" y="286" type="line"/>
-			<point x="820" y="200"/>
-			<point x="735" y="140"/>
-			<point x="604" y="140" type="curve" smooth="yes"/>
-			<point x="406" y="140"/>
-			<point x="294" y="302"/>
-			<point x="294" y="502" type="curve" smooth="yes"/>
-			<point x="294" y="544" type="line" smooth="yes"/>
-			<point x="294" y="803"/>
-			<point x="407" y="942"/>
-			<point x="569" y="942" type="curve"/>
-			<point x="755" y="942"/>
-			<point x="808" y="792"/>
-			<point x="818" y="655" type="curve"/>
-			<point x="818" y="641" type="line"/>
-			<point x="212" y="641" type="line"/>
-			<point x="212" y="481" type="line"/>
-			<point x="1018" y="481" type="line"/>
-			<point x="1018" y="566" type="line" smooth="yes"/>
-			<point x="1018" y="871"/>
-			<point x="887" y="1102"/>
-			<point x="569" y="1102" type="curve" smooth="yes"/>
-			<point x="326" y="1102"/>
-			<point x="94" y="900"/>
-			<point x="94" y="544" type="curve" smooth="yes"/>
-			<point x="94" y="502" type="line" smooth="yes"/>
-			<point x="94" y="198"/>
-			<point x="287" y="-20"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/f.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/f.glif
deleted file mode 100644
index 56e63f7..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/f.glif
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="f" format="2">
-	<unicode hex="0066"/>
-	<advance width="719"/>
-	<outline>
-		<contour>
-			<point x="429" y="0" type="line"/>
-			<point x="429" y="1193" type="line"/>
-			<point x="429" y="1320"/>
-			<point x="496" y="1390"/>
-			<point x="612" y="1390" type="curve" smooth="yes"/>
-			<point x="645" y="1390"/>
-			<point x="683" y="1387"/>
-			<point x="710" y="1382" type="curve"/>
-			<point x="720" y="1541" type="line"/>
-			<point x="679" y="1551"/>
-			<point x="635" y="1557"/>
-			<point x="593" y="1557" type="curve" smooth="yes"/>
-			<point x="367" y="1557"/>
-			<point x="229" y="1428"/>
-			<point x="229" y="1193" type="curve"/>
-			<point x="229" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="653" y="1082" type="line"/>
-			<point x="60" y="1082" type="line"/>
-			<point x="60" y="932" type="line"/>
-			<point x="653" y="932" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/g.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/g.glif
deleted file mode 100644
index 130a3ed..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/g.glif
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="g" format="2">
-	<unicode hex="0067"/>
-	<advance width="1153"/>
-	<outline>
-		<contour>
-			<point x="836" y="1082" type="line"/>
-			<point x="817" y="844" type="line"/>
-			<point x="817" y="14" type="line" smooth="yes"/>
-			<point x="817" y="-170"/>
-			<point x="706" y="-266"/>
-			<point x="538" y="-266" type="curve" smooth="yes"/>
-			<point x="444" y="-266"/>
-			<point x="341" y="-232"/>
-			<point x="250" y="-121" type="curve"/>
-			<point x="147" y="-238" type="line"/>
-			<point x="246" y="-382"/>
-			<point x="446" y="-426"/>
-			<point x="553" y="-426" type="curve" smooth="yes"/>
-			<point x="825" y="-426"/>
-			<point x="1017" y="-264"/>
-			<point x="1017" y="24" type="curve" smooth="yes"/>
-			<point x="1017" y="1082" type="line"/>
-		</contour>
-		<contour>
-			<point x="94" y="529" type="line"/>
-			<point x="94" y="214"/>
-			<point x="261" y="-20"/>
-			<point x="521" y="-20" type="curve" smooth="yes"/>
-			<point x="799" y="-20"/>
-			<point x="932" y="181"/>
-			<point x="962" y="510" type="curve"/>
-			<point x="962" y="572" type="line"/>
-			<point x="932" y="901"/>
-			<point x="799" y="1102"/>
-			<point x="523" y="1102" type="curve" smooth="yes"/>
-			<point x="259" y="1102"/>
-			<point x="94" y="879"/>
-			<point x="94" y="550" type="curve" smooth="yes"/>
-		</contour>
-		<contour>
-			<point x="294" y="550" type="line"/>
-			<point x="294" y="759"/>
-			<point x="376" y="937"/>
-			<point x="574" y="937" type="curve" smooth="yes"/>
-			<point x="751" y="937"/>
-			<point x="835" y="803"/>
-			<point x="866" y="655" type="curve"/>
-			<point x="866" y="426" type="line"/>
-			<point x="825" y="277"/>
-			<point x="751" y="146"/>
-			<point x="572" y="146" type="curve" smooth="yes"/>
-			<point x="376" y="146"/>
-			<point x="294" y="320"/>
-			<point x="294" y="529" type="curve" smooth="yes"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/h.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/h.glif
deleted file mode 100644
index 85defe3..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/h.glif
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="h" format="2">
-	<unicode hex="0068"/>
-	<advance width="1129"/>
-	<outline>
-		<contour>
-			<point x="337" y="1536" type="line"/>
-			<point x="137" y="1536" type="line"/>
-			<point x="137" y="0" type="line"/>
-			<point x="337" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="289" y="578" type="line"/>
-			<point x="289" y="778"/>
-			<point x="414" y="937"/>
-			<point x="588" y="937" type="curve" smooth="yes"/>
-			<point x="725" y="937"/>
-			<point x="796" y="872"/>
-			<point x="796" y="712" type="curve" smooth="yes"/>
-			<point x="796" y="0" type="line"/>
-			<point x="996" y="0" type="line"/>
-			<point x="996" y="710" type="line" smooth="yes"/>
-			<point x="996" y="993"/>
-			<point x="861" y="1102"/>
-			<point x="649" y="1102" type="curve" smooth="yes"/>
-			<point x="384" y="1102"/>
-			<point x="207" y="880"/>
-			<point x="207" y="576" type="curve"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/i.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/i.glif
deleted file mode 100644
index 2535d41..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/i.glif
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="i" format="2">
-	<unicode hex="0069"/>
-	<advance width="506"/>
-	<outline>
-		<contour>
-			<point x="353" y="1082" type="line"/>
-			<point x="153" y="1082" type="line"/>
-			<point x="153" y="0" type="line"/>
-			<point x="353" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="140" y="1365" type="curve" smooth="yes"/>
-			<point x="140" y="1304"/>
-			<point x="179" y="1256"/>
-			<point x="255" y="1256" type="curve"/>
-			<point x="331" y="1256"/>
-			<point x="371" y="1304"/>
-			<point x="371" y="1365" type="curve"/>
-			<point x="371" y="1427"/>
-			<point x="331" y="1476"/>
-			<point x="255" y="1476" type="curve"/>
-			<point x="179" y="1476"/>
-			<point x="140" y="1427"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/j.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/j.glif
deleted file mode 100644
index 64961d3..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/j.glif
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="j" format="2">
-	<unicode hex="006A"/>
-	<advance width="495"/>
-	<outline>
-		<contour>
-			<point x="142" y="1082" type="line"/>
-			<point x="142" y="-129" type="line"/>
-			<point x="142" y="-235"/>
-			<point x="101" y="-271"/>
-			<point x="27" y="-271" type="curve" smooth="yes"/>
-			<point x="5" y="-271"/>
-			<point x="-31" y="-269"/>
-			<point x="-57" y="-263" type="curve"/>
-			<point x="-57" y="-420" type="line"/>
-			<point x="-26" y="-430"/>
-			<point x="25" y="-437"/>
-			<point x="59" y="-437" type="curve" smooth="yes"/>
-			<point x="250" y="-437"/>
-			<point x="342" y="-328"/>
-			<point x="342" y="-129" type="curve"/>
-			<point x="342" y="1082" type="line"/>
-		</contour>
-		<contour>
-			<point x="123" y="1365" type="curve" smooth="yes"/>
-			<point x="123" y="1304"/>
-			<point x="162" y="1256"/>
-			<point x="238" y="1256" type="curve" smooth="yes"/>
-			<point x="314" y="1256"/>
-			<point x="354" y="1304"/>
-			<point x="354" y="1365" type="curve" smooth="yes"/>
-			<point x="354" y="1427"/>
-			<point x="314" y="1476"/>
-			<point x="238" y="1476" type="curve" smooth="yes"/>
-			<point x="162" y="1476"/>
-			<point x="123" y="1427"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/k.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/k.glif
deleted file mode 100644
index 708bdec..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/k.glif
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="k" format="2">
-	<unicode hex="006B"/>
-	<advance width="1046"/>
-	<outline>
-		<contour>
-			<point x="338" y="1536" type="line"/>
-			<point x="138" y="1536" type="line"/>
-			<point x="138" y="0" type="line"/>
-			<point x="338" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="995" y="1082" type="line"/>
-			<point x="753" y="1082" type="line"/>
-			<point x="434" y="735" type="line"/>
-			<point x="241" y="502" type="line"/>
-			<point x="256" y="291" type="line"/>
-			<point x="531" y="577" type="line"/>
-		</contour>
-		<contour>
-			<point x="812" y="0" type="line"/>
-			<point x="1046" y="0" type="line"/>
-			<point x="543" y="684" type="line"/>
-			<point x="440" y="508" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/l.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/l.glif
deleted file mode 100644
index 26d4ac3..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/l.glif
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="l" format="2">
-	<unicode hex="006C"/>
-	<advance width="506"/>
-	<outline>
-		<contour>
-			<point x="353" y="1536" type="line"/>
-			<point x="153" y="1536" type="line"/>
-			<point x="153" y="0" type="line"/>
-			<point x="353" y="0" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/m.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/m.glif
deleted file mode 100644
index 22f0363..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/m.glif
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="m" format="2">
-	<unicode hex="006D"/>
-	<advance width="1791"/>
-	<outline>
-		<contour>
-			<point x="337" y="869" type="line"/>
-			<point x="326" y="1082" type="line"/>
-			<point x="137" y="1082" type="line"/>
-			<point x="137" y="0" type="line"/>
-			<point x="337" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="296" y="578" type="line"/>
-			<point x="296" y="778"/>
-			<point x="360" y="937"/>
-			<point x="571" y="937" type="curve" smooth="yes"/>
-			<point x="708" y="937"/>
-			<point x="795" y="872"/>
-			<point x="795" y="711" type="curve"/>
-			<point x="795" y="0" type="line"/>
-			<point x="995" y="0" type="line"/>
-			<point x="995" y="721" type="line"/>
-			<point x="995" y="992"/>
-			<point x="845" y="1102"/>
-			<point x="645" y="1102" type="curve" smooth="yes"/>
-			<point x="350" y="1102"/>
-			<point x="203" y="880"/>
-			<point x="203" y="576" type="curve"/>
-		</contour>
-		<contour>
-			<point x="993" y="681" type="line"/>
-			<point x="993" y="824"/>
-			<point x="1077" y="937"/>
-			<point x="1230" y="937" type="curve" smooth="yes"/>
-			<point x="1367" y="937"/>
-			<point x="1454" y="887"/>
-			<point x="1454" y="714" type="curve" smooth="yes"/>
-			<point x="1454" y="0" type="line"/>
-			<point x="1654" y="0" type="line"/>
-			<point x="1654" y="712" type="line" smooth="yes"/>
-			<point x="1654" y="984"/>
-			<point x="1523" y="1102"/>
-			<point x="1290" y="1102" type="curve" smooth="yes"/>
-			<point x="1009" y="1102"/>
-			<point x="859" y="878"/>
-			<point x="859" y="637" type="curve"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/n.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/n.glif
deleted file mode 100644
index c85d49b..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/n.glif
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="n" format="2">
-	<unicode hex="006E"/>
-	<advance width="1132"/>
-	<outline>
-		<contour>
-			<point x="337" y="851" type="line"/>
-			<point x="326" y="1082" type="line"/>
-			<point x="137" y="1082" type="line"/>
-			<point x="137" y="0" type="line"/>
-			<point x="337" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="289" y="578" type="line"/>
-			<point x="289" y="778"/>
-			<point x="414" y="937"/>
-			<point x="588" y="937" type="curve" smooth="yes"/>
-			<point x="725" y="937"/>
-			<point x="796" y="872"/>
-			<point x="796" y="712" type="curve" smooth="yes"/>
-			<point x="796" y="0" type="line"/>
-			<point x="996" y="0" type="line"/>
-			<point x="996" y="710" type="line" smooth="yes"/>
-			<point x="996" y="993"/>
-			<point x="861" y="1102"/>
-			<point x="649" y="1102" type="curve" smooth="yes"/>
-			<point x="384" y="1102"/>
-			<point x="207" y="880"/>
-			<point x="207" y="576" type="curve"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/o.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/o.glif
deleted file mode 100644
index a95b37a..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/o.glif
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="o" format="2">
-	<unicode hex="006F"/>
-	<advance width="1173"/>
-	<outline>
-		<contour>
-			<point x="92" y="530" type="line"/>
-			<point x="92" y="217"/>
-			<point x="281" y="-20"/>
-			<point x="587" y="-20" type="curve" smooth="yes"/>
-			<point x="893" y="-20"/>
-			<point x="1081" y="217"/>
-			<point x="1081" y="530" type="curve"/>
-			<point x="1081" y="551" type="line"/>
-			<point x="1081" y="864"/>
-			<point x="893" y="1102"/>
-			<point x="585" y="1102" type="curve" smooth="yes"/>
-			<point x="281" y="1102"/>
-			<point x="92" y="864"/>
-			<point x="92" y="551" type="curve"/>
-		</contour>
-		<contour>
-			<point x="292" y="551" type="line"/>
-			<point x="292" y="760"/>
-			<point x="388" y="942"/>
-			<point x="585" y="942" type="curve" smooth="yes"/>
-			<point x="784" y="942"/>
-			<point x="881" y="760"/>
-			<point x="881" y="551" type="curve"/>
-			<point x="881" y="530" type="line"/>
-			<point x="881" y="319"/>
-			<point x="784" y="140"/>
-			<point x="587" y="140" type="curve" smooth="yes"/>
-			<point x="388" y="140"/>
-			<point x="292" y="319"/>
-			<point x="292" y="530" type="curve"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/p.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/p.glif
deleted file mode 100644
index c003eba..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/p.glif
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="p" format="2">
-	<unicode hex="0070"/>
-	<advance width="1153"/>
-	<outline>
-		<contour>
-			<point x="337" y="874" type="line"/>
-			<point x="319" y="1082" type="line"/>
-			<point x="137" y="1082" type="line"/>
-			<point x="137" y="-416" type="line"/>
-			<point x="337" y="-416" type="line"/>
-		</contour>
-		<contour>
-			<point x="1061" y="550" type="line"/>
-			<point x="1061" y="879"/>
-			<point x="911" y="1102"/>
-			<point x="637" y="1102" type="curve" smooth="yes"/>
-			<point x="360" y="1102"/>
-			<point x="219" y="901"/>
-			<point x="189" y="572" type="curve"/>
-			<point x="189" y="489" type="line"/>
-			<point x="219" y="173"/>
-			<point x="360" y="-20"/>
-			<point x="640" y="-20" type="curve" smooth="yes"/>
-			<point x="909" y="-20"/>
-			<point x="1061" y="214"/>
-			<point x="1061" y="529" type="curve" smooth="yes"/>
-		</contour>
-		<contour>
-			<point x="861" y="529" type="line"/>
-			<point x="861" y="320"/>
-			<point x="774" y="140"/>
-			<point x="578" y="140" type="curve" smooth="yes"/>
-			<point x="400" y="140"/>
-			<point x="325" y="267"/>
-			<point x="285" y="406" type="curve"/>
-			<point x="285" y="655" type="line"/>
-			<point x="315" y="803"/>
-			<point x="400" y="937"/>
-			<point x="576" y="937" type="curve" smooth="yes"/>
-			<point x="774" y="937"/>
-			<point x="861" y="759"/>
-			<point x="861" y="550" type="curve" smooth="yes"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/q.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/q.glif
deleted file mode 100644
index 04d7b00..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/q.glif
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="q" format="2">
-	<unicode hex="0071"/>
-	<advance width="1169"/>
-	<outline>
-		<contour>
-			<point x="814" y="-416" type="line"/>
-			<point x="1014" y="-416" type="line"/>
-			<point x="1014" y="1082" type="line"/>
-			<point x="831" y="1082" type="line"/>
-			<point x="814" y="874" type="line"/>
-		</contour>
-		<contour>
-			<point x="92" y="529" type="line"/>
-			<point x="92" y="214"/>
-			<point x="255" y="-20"/>
-			<point x="524" y="-20" type="curve" smooth="yes"/>
-			<point x="802" y="-20"/>
-			<point x="941" y="181"/>
-			<point x="970" y="510" type="curve"/>
-			<point x="970" y="572" type="line"/>
-			<point x="941" y="901"/>
-			<point x="802" y="1102"/>
-			<point x="526" y="1102" type="curve" smooth="yes"/>
-			<point x="253" y="1102"/>
-			<point x="92" y="879"/>
-			<point x="92" y="550" type="curve" smooth="yes"/>
-		</contour>
-		<contour>
-			<point x="292" y="550" type="line"/>
-			<point x="292" y="759"/>
-			<point x="379" y="942"/>
-			<point x="577" y="942" type="curve" smooth="yes"/>
-			<point x="754" y="942"/>
-			<point x="844" y="803"/>
-			<point x="875" y="655" type="curve"/>
-			<point x="875" y="426" type="line"/>
-			<point x="834" y="277"/>
-			<point x="754" y="140"/>
-			<point x="575" y="140" type="curve" smooth="yes"/>
-			<point x="379" y="140"/>
-			<point x="292" y="320"/>
-			<point x="292" y="529" type="curve" smooth="yes"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/r.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/r.glif
deleted file mode 100644
index 5e222cc..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/r.glif
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="r" format="2">
-	<unicode hex="0072"/>
-	<advance width="695"/>
-	<outline>
-		<contour>
-			<point x="337" y="914" type="line"/>
-			<point x="331" y="1082" type="line"/>
-			<point x="137" y="1082" type="line"/>
-			<point x="137" y="0" type="line"/>
-			<point x="337" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="665" y="1088" type="line"/>
-			<point x="652" y="1094"/>
-			<point x="607" y="1102"/>
-			<point x="582" y="1102" type="curve"/>
-			<point x="352" y="1102"/>
-			<point x="253" y="884"/>
-			<point x="253" y="628" type="curve"/>
-			<point x="307" y="660" type="line"/>
-			<point x="325" y="809"/>
-			<point x="408" y="913"/>
-			<point x="572" y="913" type="curve"/>
-			<point x="608" y="913"/>
-			<point x="632" y="911"/>
-			<point x="665" y="905" type="curve"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/s.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/s.glif
deleted file mode 100644
index 9544403..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/s.glif
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="s" format="2">
-	<unicode hex="0073"/>
-	<advance width="1061"/>
-	<outline>
-		<contour>
-			<point x="763" y="289" type="curve" smooth="yes"/>
-			<point x="763" y="202"/>
-			<point x="685" y="140"/>
-			<point x="541" y="140" type="curve" smooth="yes"/>
-			<point x="430" y="140"/>
-			<point x="302" y="189"/>
-			<point x="294" y="339" type="curve"/>
-			<point x="94" y="339" type="line"/>
-			<point x="94" y="158"/>
-			<point x="251" y="-20"/>
-			<point x="541" y="-20" type="curve" smooth="yes"/>
-			<point x="795" y="-20"/>
-			<point x="963" y="112"/>
-			<point x="963" y="304" type="curve"/>
-			<point x="963" y="479"/>
-			<point x="838" y="567"/>
-			<point x="572" y="628" type="curve" smooth="yes"/>
-			<point x="376" y="672"/>
-			<point x="331" y="710"/>
-			<point x="331" y="788" type="curve"/>
-			<point x="331" y="865"/>
-			<point x="389" y="942"/>
-			<point x="536" y="942" type="curve" smooth="yes"/>
-			<point x="674" y="942"/>
-			<point x="751" y="847"/>
-			<point x="751" y="762" type="curve"/>
-			<point x="951" y="762" type="line"/>
-			<point x="951" y="948"/>
-			<point x="797" y="1102"/>
-			<point x="536" y="1102" type="curve" smooth="yes"/>
-			<point x="291" y="1102"/>
-			<point x="131" y="955"/>
-			<point x="131" y="782" type="curve"/>
-			<point x="131" y="604"/>
-			<point x="283" y="519"/>
-			<point x="523" y="469" type="curve" smooth="yes"/>
-			<point x="731" y="427"/>
-			<point x="763" y="367"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/space.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/space.glif
deleted file mode 100644
index b92e22c..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/space.glif
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="space" format="2">
-	<unicode hex="0020"/>
-	<advance width="510"/>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/t.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/t.glif
deleted file mode 100644
index 261e70a..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/t.glif
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="t" format="2">
-	<unicode hex="0074"/>
-	<advance width="672"/>
-	<outline>
-		<contour>
-			<point x="600" y="1082" type="line"/>
-			<point x="6" y="1082" type="line"/>
-			<point x="6" y="932" type="line"/>
-			<point x="600" y="932" type="line"/>
-		</contour>
-		<contour>
-			<point x="203" y="1342" type="line"/>
-			<point x="203" y="270" type="line"/>
-			<point x="203" y="53"/>
-			<point x="319" y="-20"/>
-			<point x="456" y="-20" type="curve" smooth="yes"/>
-			<point x="526" y="-20"/>
-			<point x="573" y="-8"/>
-			<point x="602" y="1" type="curve"/>
-			<point x="602" y="160" type="line"/>
-			<point x="587" y="156"/>
-			<point x="547" y="148"/>
-			<point x="517" y="148" type="curve" smooth="yes"/>
-			<point x="458" y="148"/>
-			<point x="403" y="165"/>
-			<point x="403" y="269" type="curve"/>
-			<point x="403" y="1342" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/u.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/u.glif
deleted file mode 100644
index c17bfd9..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/u.glif
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="u" format="2">
-	<unicode hex="0075"/>
-	<advance width="1130"/>
-	<outline>
-		<contour>
-			<point x="793" y="250" type="line"/>
-			<point x="803" y="0" type="line"/>
-			<point x="993" y="0" type="line"/>
-			<point x="993" y="1082" type="line"/>
-			<point x="793" y="1082" type="line"/>
-		</contour>
-		<contour>
-			<point x="830" y="483" type="line"/>
-			<point x="830" y="293"/>
-			<point x="750" y="146"/>
-			<point x="521" y="146" type="curve" smooth="yes"/>
-			<point x="428" y="146"/>
-			<point x="333" y="192"/>
-			<point x="333" y="381" type="curve"/>
-			<point x="333" y="1082" type="line"/>
-			<point x="133" y="1082" type="line"/>
-			<point x="133" y="383" type="line"/>
-			<point x="133" y="96"/>
-			<point x="276" y="-20"/>
-			<point x="488" y="-20" type="curve" smooth="yes"/>
-			<point x="800" y="-20"/>
-			<point x="911" y="194"/>
-			<point x="911" y="485" type="curve"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/v.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/v.glif
deleted file mode 100644
index bd5b120..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/v.glif
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="v" format="2">
-	<unicode hex="0076"/>
-	<advance width="994"/>
-	<outline>
-		<contour>
-			<point x="469" y="176" type="line"/>
-			<point x="439" y="0" type="line"/>
-			<point x="572" y="0" type="line"/>
-			<point x="957" y="1082" type="line"/>
-			<point x="753" y="1082" type="line"/>
-		</contour>
-		<contour>
-			<point x="236" y="1082" type="line"/>
-			<point x="32" y="1082" type="line"/>
-			<point x="421" y="0" type="line"/>
-			<point x="553" y="0" type="line"/>
-			<point x="531" y="171" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/w.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/w.glif
deleted file mode 100644
index e6b648e..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/w.glif
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="w" format="2">
-	<unicode hex="0077"/>
-	<advance width="1538"/>
-	<outline>
-		<contour>
-			<point x="406" y="182" type="line"/>
-			<point x="388" y="0" type="line"/>
-			<point x="514" y="0" type="line"/>
-			<point x="799" y="913" type="line"/>
-			<point x="818" y="1082" type="line"/>
-			<point x="687" y="1082" type="line"/>
-		</contour>
-		<contour>
-			<point x="237" y="1082" type="line"/>
-			<point x="39" y="1082" type="line"/>
-			<point x="353" y="0" type="line"/>
-			<point x="486" y="0" type="line"/>
-			<point x="476" y="171" type="line"/>
-		</contour>
-		<contour>
-			<point x="1071" y="178" type="line"/>
-			<point x="1049" y="0" type="line"/>
-			<point x="1181" y="0" type="line"/>
-			<point x="1495" y="1082" type="line"/>
-			<point x="1297" y="1082" type="line"/>
-		</contour>
-		<contour>
-			<point x="847" y="1082" type="line"/>
-			<point x="708" y="1082" type="line"/>
-			<point x="727" y="915" type="line"/>
-			<point x="1020" y="0" type="line"/>
-			<point x="1146" y="0" type="line"/>
-			<point x="1122" y="198" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/x.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/x.glif
deleted file mode 100644
index 8a60313..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/x.glif
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="x" format="2">
-	<unicode hex="0078"/>
-	<advance width="1020"/>
-	<outline>
-		<contour>
-			<point x="280" y="1082" type="line"/>
-			<point x="50" y="1082" type="line"/>
-			<point x="401" y="547" type="line"/>
-			<point x="40" y="0" type="line"/>
-			<point x="272" y="0" type="line"/>
-			<point x="509" y="397" type="line"/>
-			<point x="746" y="0" type="line"/>
-			<point x="976" y="0" type="line"/>
-			<point x="615" y="547" type="line"/>
-			<point x="966" y="1082" type="line"/>
-			<point x="733" y="1082" type="line"/>
-			<point x="505" y="695" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/y.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/y.glif
deleted file mode 100644
index 793d4f2..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/y.glif
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="y" format="2">
-	<unicode hex="0079"/>
-	<advance width="968"/>
-	<outline>
-		<contour>
-			<point x="438" y="113" type="line"/>
-			<point x="363" y="-92" type="line" smooth="yes"/>
-			<point x="319" y="-226"/>
-			<point x="255" y="-266"/>
-			<point x="130" y="-266" type="curve" smooth="yes"/>
-			<point x="121" y="-266"/>
-			<point x="93" y="-264"/>
-			<point x="83" y="-262" type="curve"/>
-			<point x="83" y="-421" type="line"/>
-			<point x="103" y="-426"/>
-			<point x="159" y="-437"/>
-			<point x="190" y="-437" type="curve" smooth="yes"/>
-			<point x="386" y="-437"/>
-			<point x="475" y="-274"/>
-			<point x="515" y="-166" type="curve" smooth="yes"/>
-			<point x="944" y="1082" type="line"/>
-			<point x="731" y="1082" type="line"/>
-		</contour>
-		<contour>
-			<point x="238" y="1082" type="line"/>
-			<point x="20" y="1082" type="line"/>
-			<point x="413" y="-21" type="line"/>
-			<point x="556" y="50" type="line"/>
-			<point x="504" y="258" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/z.glif b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/z.glif
deleted file mode 100644
index e21d52a..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/glyphs/z.glif
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="z" format="2">
-	<unicode hex="007A"/>
-	<advance width="1020"/>
-	<outline>
-		<contour>
-			<point x="949" y="160" type="line"/>
-			<point x="166" y="160" type="line"/>
-			<point x="166" y="0" type="line"/>
-			<point x="949" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="923" y="944" type="line"/>
-			<point x="923" y="1082" type="line"/>
-			<point x="796" y="1082" type="line"/>
-			<point x="89" y="144" type="line"/>
-			<point x="89" y="0" type="line"/>
-			<point x="211" y="0" type="line"/>
-		</contour>
-		<contour>
-			<point x="835" y="1082" type="line"/>
-			<point x="95" y="1082" type="line"/>
-			<point x="95" y="921" type="line"/>
-			<point x="835" y="921" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/layercontents.plist b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/layercontents.plist
deleted file mode 100644
index 03e5dde..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/layercontents.plist
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-	<array>
-		<array>
-			<string>public.default</string>
-			<string>glyphs</string>
-		</array>
-	</array>
-</plist>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/lib.plist b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/lib.plist
deleted file mode 100644
index 5623ed1..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/lib.plist
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-	<dict>
-		<key>public.glyphOrder</key>
-		<array>
-			<string>space</string>
-			<string>A</string>
-			<string>B</string>
-			<string>C</string>
-			<string>D</string>
-			<string>E</string>
-			<string>F</string>
-			<string>G</string>
-			<string>H</string>
-			<string>I</string>
-			<string>J</string>
-			<string>K</string>
-			<string>L</string>
-			<string>M</string>
-			<string>N</string>
-			<string>O</string>
-			<string>P</string>
-			<string>Q</string>
-			<string>R</string>
-			<string>S</string>
-			<string>T</string>
-			<string>U</string>
-			<string>V</string>
-			<string>W</string>
-			<string>X</string>
-			<string>Y</string>
-			<string>Z</string>
-			<string>a</string>
-			<string>b</string>
-			<string>c</string>
-			<string>d</string>
-			<string>e</string>
-			<string>f</string>
-			<string>g</string>
-			<string>h</string>
-			<string>i</string>
-			<string>j</string>
-			<string>k</string>
-			<string>l</string>
-			<string>m</string>
-			<string>n</string>
-			<string>o</string>
-			<string>p</string>
-			<string>q</string>
-			<string>r</string>
-			<string>s</string>
-			<string>t</string>
-			<string>u</string>
-			<string>v</string>
-			<string>w</string>
-			<string>x</string>
-			<string>y</string>
-			<string>z</string>
-		</array>
-	</dict>
-</plist>
diff --git a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/metainfo.plist b/Tests/cu2qu/data/RobotoSubset-Regular.ufo/metainfo.plist
deleted file mode 100644
index edfd637..0000000
--- a/Tests/cu2qu/data/RobotoSubset-Regular.ufo/metainfo.plist
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-	<dict>
-		<key>creator</key>
-		<string>org.robofab.ufoLib</string>
-		<key>formatVersion</key>
-		<integer>3</integer>
-	</dict>
-</plist>
diff --git a/Tests/cu2qu/data/curves.json b/Tests/cu2qu/data/curves.json
deleted file mode 100644
index 23af575..0000000
--- a/Tests/cu2qu/data/curves.json
+++ /dev/null
@@ -1 +0,0 @@
-[[[550.0,258.0],[1044.0,482.0],[2029.0,1841.0],[1934.0,1554.0]],[[859.0,384.0],[1998.0,116.0],[1596.0,1772.0],[8.0,1824.0]],[[1090.0,937.0],[418.0,1300.0],[125.0,91.0],[104.0,37.0]],[[1561.0,887.0],[1728.0,118.0],[908.0,1793.0],[2030.0,954.0]],[[1415.0,945.0],[896.0,1882.0],[1186.0,88.0],[1704.0,409.0]],[[761.0,1214.0],[495.0,1362.0],[1728.0,777.0],[1242.0,1163.0]],[[2045.0,1611.0],[141.0,1967.0],[994.0,1655.0],[1697.0,708.0]],[[1503.0,1534.0],[354.0,1797.0],[442.0,670.0],[1610.0,1517.0]],[[2005.0,121.0],[1922.0,178.0],[1263.0,1612.0],[697.0,690.0]],[[929.0,50.0],[817.0,950.0],[1656.0,1408.0],[1447.0,1880.0]],[[1102.0,23.0],[1571.0,529.0],[841.0,1745.0],[229.0,1970.0]],[[1493.0,818.0],[1693.0,1986.0],[1461.0,1697.0],[1417.0,6.0]],[[1356.0,1876.0],[114.0,940.0],[725.0,740.0],[375.0,1045.0]],[[132.0,288.0],[340.0,68.0],[1855.0,59.0],[1151.0,1022.0]],[[1100.0,448.0],[756.0,1410.0],[1189.0,284.0],[685.0,653.0]],[[1045.0,688.0],[1117.0,1206.0],[1862.0,1318.0],[2033.0,1940.0]],[[467.0,96.0],[1277.0,1583.0],[1406.0,1724.0],[770.0,1058.0]],[[445.0,1038.0],[856.0,1768.0],[85.0,923.0],[73.0,1627.0]],[[599.0,144.0],[656.0,1825.0],[1747.0,903.0],[1846.0,914.0]],[[125.0,1617.0],[1315.0,1746.0],[240.0,1223.0],[514.0,868.0]],[[194.0,1254.0],[289.0,313.0],[1271.0,1220.0],[648.0,1704.0]],[[1033.0,534.0],[34.0,155.0],[891.0,1887.0],[702.0,153.0]],[[1548.0,820.0],[1421.0,405.0],[842.0,1773.0],[795.0,2016.0]],[[427.0,1597.0],[1212.0,2047.0],[70.0,1332.0],[1647.0,1152.0]],[[74.0,642.0],[822.0,1342.0],[553.0,1388.0],[1758.0,872.0]],[[1091.0,394.0],[1553.0,1408.0],[1984.0,961.0],[267.0,165.0]],[[346.0,544.0],[695.0,682.0],[872.0,1097.0],[1360.0,1045.0]],[[1507.0,1387.0],[1393.0,466.0],[1192.0,963.0],[2002.0,554.0]],[[427.0,1313.0],[160.0,1665.0],[299.0,1557.0],[603.0,512.0]],[[1396.0,469.0],[1548.0,313.0],[916.0,334.0],[1092.0,1494.0]],[[1210.0,468.0],[1875.0,1135.0],[441.0,187.0],[1211.0,50.0]],[[59.0,375.0],[1693.0,471.0],[163.0,769.0],[981.0,1724.0]],[[663.0,473.0],[1846.0,685.0],[988.0,651.0],[421.0,1782.0]],[[1549.0,1204.0],[1037.0,1953.0],[1288.0,410.0],[850.0,1300.0]],[[162.0,111.0],[43.0,1210.0],[1311.0,1842.0],[1602.0,1283.0]],[[1632.0,257.0],[262.0,1299.0],[1867.0,456.0],[1024.0,881.0]],[[1920.0,1457.0],[1061.0,750.0],[851.0,1258.0],[815.0,1009.0]],[[1476.0,333.0],[1150.0,366.0],[1834.0,370.0],[1388.0,931.0]],[[1599.0,1256.0],[168.0,1340.0],[765.0,1297.0],[1240.0,1006.0]],[[1369.0,413.0],[377.0,1003.0],[901.0,83.0],[998.0,1645.0]],[[296.0,1097.0],[290.0,307.0],[88.0,40.0],[1191.0,1471.0]],[[2020.0,1920.0],[631.0,413.0],[1343.0,315.0],[709.0,735.0]],[[612.0,579.0],[1309.0,1251.0],[437.0,1202.0],[517.0,846.0]],[[580.0,130.0],[1294.0,841.0],[729.0,1224.0],[1772.0,646.0]],[[198.0,1012.0],[1034.0,263.0],[1829.0,1761.0],[1024.0,1799.0]],[[1856.0,44.0],[1620.0,1387.0],[702.0,1056.0],[1989.0,99.0]],[[1706.0,77.0],[255.0,1453.0],[566.0,512.0],[567.0,1061.0]],[[1134.0,1629.0],[1642.0,705.0],[365.0,956.0],[1990.0,30.0]],[[727.0,1299.0],[1795.0,924.0],[976.0,1281.0],[2027.0,1961.0]],[[921.0,1688.0],[1380.0,1127.0],[898.0,197.0],[293.0,1510.0]],[[653.0,834.0],[1277.0,1223.0],[1227.0,1522.0],[676.0,1903.0]],[[348.0,504.0],[1545.0,722.0],[638.0,1026.0],[1747.0,891.0]],[[213.0,2027.0],[1612.0,1425.0],[1572.0,675.0],[166.0,370.0]],[[1045.0,413.0],[1095.0,342.0],[569.0,335.0],[1822.0,987.0]],[[1566.0,1773.0],[1627.0,674.0],[1333.0,1794.0],[517.0,1998.0]],[[868.0,488.0],[1766.0,1672.0],[483.0,1210.0],[1137.0,1016.0]],[[1551.0,16.0],[777.0,1797.0],[86.0,126.0],[992.0,1066.0]],[[846.0,708.0],[1166.0,607.0],[821.0,1119.0],[1274.0,1027.0]],[[1828.0,688.0],[1462.0,2010.0],[1720.0,498.0],[855.0,1569.0]],[[838.0,1163.0],[442.0,98.0],[483.0,54.0],[1214.0,559.0]],[[307.0,1530.0],[1274.0,1790.0],[1461.0,1325.0],[3.0,507.0]],[[1811.0,1841.0],[1434.0,1248.0],[1635.0,1390.0],[2016.0,463.0]],[[1546.0,1566.0],[835.0,15.0],[1137.0,814.0],[1890.0,1675.0]],[[1250.0,697.0],[1840.0,808.0],[1472.0,14.0],[1594.0,1744.0]],[[1659.0,1376.0],[277.0,2018.0],[1014.0,1191.0],[85.0,1667.0]],[[639.0,1627.0],[1106.0,729.0],[300.0,41.0],[1431.0,1083.0]],[[1684.0,1243.0],[622.0,1892.0],[1062.0,1984.0],[694.0,1913.0]],[[185.0,1109.0],[403.0,1730.0],[285.0,1454.0],[274.0,1812.0]],[[80.0,672.0],[662.0,381.0],[1646.0,1129.0],[1246.0,855.0]],[[850.0,971.0],[1367.0,1102.0],[280.0,306.0],[1508.0,1916.0]],[[203.0,690.0],[1216.0,1104.0],[1457.0,950.0],[1607.0,1637.0]],[[705.0,1980.0],[1063.0,1350.0],[910.0,1059.0],[1000.0,125.0]],[[1649.0,1296.0],[1768.0,1017.0],[1102.0,777.0],[297.0,678.0]],[[1816.0,606.0],[1073.0,1881.0],[665.0,567.0],[565.0,1805.0]],[[1479.0,1268.0],[1641.0,985.0],[474.0,844.0],[1251.0,279.0]],[[435.0,932.0],[1626.0,1316.0],[2016.0,409.0],[764.0,184.0]],[[226.0,95.0],[887.0,142.0],[2025.0,1811.0],[1402.0,1124.0]],[[483.0,707.0],[390.0,909.0],[1637.0,955.0],[2027.0,1842.0]],[[1547.0,690.0],[949.0,965.0],[1161.0,1894.0],[1595.0,867.0]],[[1850.0,1056.0],[1352.0,2032.0],[454.0,875.0],[322.0,189.0]],[[63.0,21.0],[1967.0,1308.0],[1569.0,1176.0],[802.0,1638.0]],[[655.0,623.0],[124.0,62.0],[1586.0,594.0],[233.0,1554.0]],[[1041.0,532.0],[325.0,1895.0],[1242.0,59.0],[145.0,249.0]],[[528.0,175.0],[1120.0,481.0],[1771.0,372.0],[778.0,113.0]],[[2046.0,533.0],[1143.0,786.0],[1833.0,1596.0],[1350.0,1097.0]],[[1064.0,995.0],[1005.0,246.0],[717.0,1432.0],[1755.0,249.0]],[[1446.0,1690.0],[816.0,1737.0],[287.0,1094.0],[296.0,1030.0]],[[727.0,395.0],[618.0,240.0],[832.0,1753.0],[183.0,216.0]],[[373.0,1921.0],[1516.0,406.0],[1280.0,164.0],[518.0,135.0]],[[1815.0,525.0],[1618.0,1827.0],[100.0,1105.0],[370.0,1024.0]],[[1332.0,351.0],[1236.0,140.0],[1573.0,238.0],[1069.0,1282.0]],[[532.0,1066.0],[1557.0,479.0],[1244.0,385.0],[1740.0,1005.0]],[[841.0,1352.0],[1387.0,1601.0],[1970.0,428.0],[531.0,1837.0]],[[123.0,1193.0],[643.0,819.0],[1516.0,1594.0],[1328.0,398.0]],[[1677.0,1414.0],[517.0,265.0],[178.0,1230.0],[1284.0,1710.0]],[[1221.0,1305.0],[1444.0,1116.0],[1332.0,35.0],[499.0,609.0]],[[1298.0,1333.0],[1341.0,281.0],[1850.0,1145.0],[1964.0,1860.0]],[[1491.0,1558.0],[320.0,229.0],[551.0,199.0],[2015.0,1031.0]],[[1005.0,1387.0],[1481.0,1516.0],[1648.0,1259.0],[1902.0,1394.0]],[[687.0,119.0],[607.0,1024.0],[905.0,546.0],[461.0,756.0]],[[1683.0,205.0],[406.0,1088.0],[438.0,836.0],[1071.0,273.0]],[[321.0,298.0],[890.0,710.0],[1769.0,89.0],[1507.0,1993.0]],[[1162.0,900.0],[820.0,2021.0],[963.0,1742.0],[1852.0,1503.0]],[[773.0,1974.0],[297.0,1050.0],[1668.0,824.0],[33.0,1559.0]],[[1995.0,312.0],[1653.0,1743.0],[164.0,1441.0],[1877.0,26.0]],[[777.0,1226.0],[22.0,491.0],[1239.0,1292.0],[1157.0,1685.0]],[[1672.0,1260.0],[1853.0,1236.0],[536.0,1819.0],[574.0,667.0]],[[1035.0,39.0],[1737.0,148.0],[1508.0,1723.0],[1647.0,1153.0]],[[75.0,370.0],[368.0,19.0],[1570.0,1101.0],[1902.0,1113.0]],[[1526.0,1971.0],[1378.0,1591.0],[1868.0,477.0],[1981.0,1452.0]],[[592.0,1700.0],[607.0,74.0],[704.0,1065.0],[1506.0,520.0]],[[1176.0,1691.0],[1056.0,1176.0],[1723.0,1120.0],[1775.0,1375.0]],[[1989.0,882.0],[2012.0,1646.0],[1741.0,374.0],[263.0,530.0]],[[844.0,612.0],[938.0,107.0],[422.0,1037.0],[637.0,1965.0]],[[405.0,1634.0],[767.0,12.0],[365.0,1751.0],[208.0,894.0]],[[1728.0,1420.0],[192.0,422.0],[1718.0,485.0],[1086.0,1141.0]],[[733.0,1964.0],[195.0,877.0],[357.0,1596.0],[507.0,1832.0]],[[1205.0,2039.0],[1610.0,475.0],[1962.0,433.0],[610.0,1582.0]],[[824.0,684.0],[1055.0,1706.0],[1182.0,2017.0],[879.0,1380.0]],[[1990.0,421.0],[35.0,1420.0],[1095.0,231.0],[1803.0,1228.0]],[[412.0,936.0],[1124.0,1107.0],[1009.0,1686.0],[607.0,533.0]],[[1049.0,799.0],[1670.0,239.0],[609.0,1694.0],[1106.0,1146.0]],[[1966.0,1252.0],[1093.0,2012.0],[878.0,2042.0],[1506.0,1927.0]],[[989.0,1386.0],[721.0,742.0],[1847.0,612.0],[238.0,1335.0]],[[553.0,873.0],[1291.0,2022.0],[1967.0,1351.0],[484.0,523.0]],[[573.0,1050.0],[921.0,360.0],[204.0,704.0],[475.0,926.0]],[[816.0,1261.0],[1729.0,1342.0],[17.0,82.0],[1250.0,902.0]],[[346.0,919.0],[1147.0,1397.0],[1102.0,1553.0],[94.0,498.0]],[[1351.0,1421.0],[571.0,464.0],[1027.0,586.0],[168.0,1421.0]],[[316.0,376.0],[422.0,1228.0],[1298.0,1019.0],[1103.0,203.0]],[[1481.0,127.0],[320.0,569.0],[1635.0,1523.0],[991.0,384.0]],[[1346.0,1120.0],[32.0,1318.0],[459.0,1443.0],[515.0,1110.0]],[[1659.0,373.0],[1947.0,1715.0],[1612.0,1233.0],[898.0,1239.0]],[[545.0,220.0],[450.0,717.0],[985.0,880.0],[1780.0,1124.0]],[[81.0,1025.0],[1109.0,1072.0],[1938.0,516.0],[1651.0,424.0]],[[1529.0,282.0],[1487.0,124.0],[1262.0,1824.0],[541.0,638.0]],[[304.0,581.0],[885.0,1982.0],[1374.0,1495.0],[1197.0,654.0]],[[637.0,1563.0],[1801.0,1661.0],[482.0,594.0],[1104.0,1209.0]],[[33.0,39.0],[543.0,1554.0],[414.0,1882.0],[124.0,1769.0]],[[1729.0,1130.0],[1516.0,1672.0],[1663.0,1892.0],[218.0,406.0]],[[1928.0,153.0],[2.0,172.0],[455.0,571.0],[1459.0,1109.0]],[[1459.0,1941.0],[1004.0,982.0],[432.0,1465.0],[649.0,476.0]],[[166.0,1284.0],[1730.0,1418.0],[1038.0,228.0],[1781.0,1699.0]],[[1541.0,1469.0],[1203.0,1397.0],[1806.0,975.0],[591.0,229.0]],[[1398.0,464.0],[705.0,1996.0],[1396.0,497.0],[88.0,1967.0]],[[856.0,1569.0],[715.0,1627.0],[933.0,408.0],[1017.0,1374.0]],[[1347.0,1004.0],[1889.0,1929.0],[1513.0,2017.0],[793.0,1769.0]],[[1804.0,1633.0],[493.0,1999.0],[1091.0,512.0],[613.0,48.0]],[[1540.0,1698.0],[446.0,107.0],[305.0,749.0],[1879.0,1544.0]],[[1181.0,636.0],[631.0,433.0],[1042.0,76.0],[1902.0,1624.0]],[[935.0,1600.0],[21.0,1021.0],[1732.0,650.0],[733.0,1402.0]],[[979.0,311.0],[659.0,719.0],[1538.0,88.0],[888.0,1750.0]],[[965.0,165.0],[779.0,316.0],[1015.0,1630.0],[1904.0,487.0]],[[198.0,1585.0],[367.0,387.0],[1961.0,184.0],[979.0,49.0]],[[85.0,1277.0],[1910.0,1138.0],[1702.0,682.0],[545.0,1303.0]],[[1837.0,1710.0],[686.0,1619.0],[1593.0,822.0],[2029.0,1140.0]],[[1474.0,620.0],[1062.0,1144.0],[717.0,342.0],[1476.0,1376.0]],[[584.0,1058.0],[1044.0,1033.0],[1430.0,1573.0],[1143.0,1915.0]],[[55.0,610.0],[533.0,1035.0],[925.0,804.0],[288.0,812.0]],[[1758.0,982.0],[570.0,1886.0],[1602.0,802.0],[338.0,316.0]],[[627.0,235.0],[123.0,1660.0],[1567.0,1709.0],[563.0,529.0]],[[303.0,988.0],[1563.0,571.0],[1170.0,829.0],[1626.0,1461.0]],[[730.0,922.0],[1219.0,589.0],[1424.0,2015.0],[1195.0,362.0]],[[1224.0,855.0],[1898.0,89.0],[1189.0,422.0],[1526.0,1816.0]],[[1044.0,238.0],[213.0,1292.0],[654.0,542.0],[423.0,460.0]],[[1782.0,1007.0],[851.0,1625.0],[497.0,869.0],[1572.0,548.0]],[[1042.0,14.0],[495.0,825.0],[1548.0,1974.0],[944.0,1096.0]],[[154.0,687.0],[954.0,1681.0],[1121.0,1725.0],[1632.0,1114.0]],[[2023.0,400.0],[530.0,764.0],[65.0,1859.0],[183.0,2000.0]],[[877.0,1613.0],[1377.0,997.0],[385.0,315.0],[174.0,1731.0]],[[1809.0,773.0],[709.0,778.0],[1576.0,1476.0],[807.0,953.0]],[[1473.0,264.0],[1396.0,212.0],[1877.0,181.0],[724.0,604.0]],[[1169.0,1921.0],[176.0,265.0],[1623.0,376.0],[1638.0,1234.0]],[[1615.0,1097.0],[1442.0,1927.0],[201.0,1954.0],[71.0,1748.0]],[[1247.0,1299.0],[611.0,1137.0],[269.0,1478.0],[1700.0,1601.0]],[[96.0,464.0],[151.0,58.0],[413.0,1360.0],[1379.0,1508.0]],[[141.0,1516.0],[303.0,1986.0],[343.0,1827.0],[1370.0,2048.0]],[[13.0,658.0],[1331.0,1478.0],[876.0,598.0],[607.0,441.0]],[[1654.0,1299.0],[1723.0,1474.0],[1398.0,1064.0],[1509.0,154.0]],[[259.0,1010.0],[1087.0,1626.0],[1162.0,341.0],[306.0,697.0]],[[1094.0,1694.0],[341.0,517.0],[1156.0,1076.0],[961.0,862.0]],[[404.0,1135.0],[1967.0,192.0],[1234.0,835.0],[307.0,1292.0]],[[1391.0,1212.0],[545.0,144.0],[1811.0,1490.0],[152.0,117.0]],[[1292.0,1710.0],[670.0,166.0],[1739.0,755.0],[808.0,953.0]],[[470.0,532.0],[501.0,1091.0],[1877.0,804.0],[226.0,1479.0]],[[1868.0,1371.0],[1452.0,900.0],[38.0,57.0],[2001.0,132.0]],[[673.0,1037.0],[163.0,37.0],[942.0,346.0],[709.0,143.0]],[[820.0,857.0],[1814.0,1182.0],[995.0,2009.0],[1521.0,1330.0]],[[1605.0,300.0],[799.0,743.0],[768.0,1216.0],[1745.0,1941.0]],[[1488.0,94.0],[1996.0,84.0],[429.0,1771.0],[1407.0,1388.0]],[[303.0,1721.0],[799.0,2024.0],[1956.0,1843.0],[1929.0,677.0]],[[1098.0,1235.0],[1623.0,1061.0],[1046.0,1270.0],[60.0,187.0]],[[1874.0,1874.0],[1456.0,950.0],[1819.0,856.0],[1949.0,1374.0]],[[593.0,1572.0],[1791.0,222.0],[455.0,1459.0],[33.0,1047.0]],[[221.0,1255.0],[1551.0,61.0],[1329.0,1385.0],[1264.0,203.0]],[[854.0,334.0],[1346.0,491.0],[271.0,525.0],[1205.0,1677.0]],[[1395.0,952.0],[111.0,749.0],[1498.0,1239.0],[1203.0,1548.0]],[[1722.0,1890.0],[303.0,815.0],[1669.0,948.0],[172.0,986.0]],[[919.0,997.0],[1616.0,1553.0],[860.0,622.0],[1225.0,1474.0]],[[5.0,1258.0],[1819.0,2039.0],[699.0,599.0],[127.0,1518.0]],[[1789.0,1400.0],[2005.0,1300.0],[456.0,1197.0],[1130.0,1759.0]],[[46.0,1272.0],[354.0,2014.0],[470.0,903.0],[1084.0,1789.0]],[[1526.0,944.0],[222.0,419.0],[667.0,531.0],[1196.0,197.0]],[[279.0,893.0],[12.0,253.0],[1732.0,86.0],[271.0,225.0]],[[36.0,142.0],[1389.0,1362.0],[76.0,36.0],[865.0,1920.0]],[[819.0,1090.0],[1209.0,1029.0],[956.0,748.0],[863.0,1603.0]],[[244.0,977.0],[1853.0,144.0],[1357.0,1338.0],[1666.0,490.0]],[[65.0,757.0],[383.0,757.0],[894.0,921.0],[723.0,1245.0]],[[400.0,240.0],[1285.0,599.0],[257.0,1815.0],[614.0,945.0]],[[176.0,1172.0],[1410.0,238.0],[365.0,1812.0],[820.0,933.0]],[[758.0,488.0],[235.0,828.0],[221.0,474.0],[358.0,900.0]],[[1171.0,1032.0],[1731.0,1018.0],[132.0,1031.0],[797.0,1334.0]],[[1433.0,1463.0],[1860.0,1566.0],[1583.0,366.0],[1745.0,1001.0]],[[2004.0,1407.0],[731.0,466.0],[981.0,296.0],[1788.0,1134.0]],[[1244.0,1372.0],[1517.0,1676.0],[1869.0,1492.0],[1441.0,1293.0]],[[1622.0,1930.0],[70.0,1516.0],[521.0,1238.0],[688.0,1237.0]],[[519.0,612.0],[683.0,1874.0],[623.0,553.0],[659.0,326.0]],[[1039.0,964.0],[1457.0,1291.0],[702.0,1135.0],[1937.0,1268.0]],[[316.0,1754.0],[630.0,1446.0],[1841.0,440.0],[638.0,1293.0]],[[283.0,765.0],[1964.0,143.0],[191.0,785.0],[1458.0,1499.0]],[[1455.0,1534.0],[1401.0,493.0],[756.0,1537.0],[133.0,1109.0]],[[860.0,255.0],[1011.0,1246.0],[1339.0,1650.0],[1000.0,1473.0]],[[202.0,949.0],[1190.0,27.0],[800.0,397.0],[554.0,912.0]],[[1510.0,1091.0],[576.0,665.0],[934.0,308.0],[1275.0,1769.0]],[[1799.0,1945.0],[749.0,1456.0],[800.0,1773.0],[303.0,1134.0]],[[840.0,937.0],[582.0,547.0],[852.0,86.0],[670.0,1989.0]],[[1486.0,753.0],[201.0,1475.0],[337.0,972.0],[865.0,356.0]],[[1807.0,804.0],[1402.0,675.0],[73.0,891.0],[1294.0,1967.0]],[[148.0,214.0],[1502.0,2047.0],[1431.0,555.0],[1999.0,279.0]],[[1305.0,1276.0],[1301.0,366.0],[1969.0,1384.0],[1702.0,292.0]],[[1073.0,257.0],[1322.0,78.0],[738.0,1341.0],[924.0,1282.0]],[[1075.0,1033.0],[1254.0,1997.0],[1703.0,49.0],[1206.0,665.0]],[[1191.0,199.0],[474.0,1767.0],[1763.0,890.0],[1139.0,1460.0]],[[2024.0,1152.0],[1048.0,706.0],[1321.0,584.0],[1440.0,387.0]],[[1626.0,1461.0],[787.0,1621.0],[1840.0,614.0],[1970.0,994.0]],[[154.0,1014.0],[323.0,288.0],[157.0,1931.0],[1983.0,1340.0]],[[698.0,2036.0],[1628.0,54.0],[1581.0,1845.0],[677.0,1528.0]],[[211.0,1508.0],[1445.0,1793.0],[972.0,1243.0],[361.0,1809.0]],[[1462.0,799.0],[660.0,551.0],[1811.0,184.0],[1491.0,1381.0]],[[710.0,2008.0],[1959.0,34.0],[958.0,243.0],[1819.0,669.0]],[[853.0,1639.0],[1908.0,505.0],[1289.0,1073.0],[566.0,693.0]],[[1351.0,539.0],[739.0,1262.0],[959.0,1750.0],[1917.0,1875.0]],[[1274.0,695.0],[1264.0,846.0],[1157.0,633.0],[26.0,1394.0]],[[487.0,1742.0],[1556.0,732.0],[1800.0,1840.0],[1811.0,1489.0]],[[845.0,221.0],[348.0,439.0],[398.0,1587.0],[562.0,1816.0]],[[1626.0,745.0],[1945.0,1838.0],[149.0,794.0],[1843.0,2000.0]],[[1596.0,1190.0],[1428.0,710.0],[1119.0,738.0],[112.0,248.0]],[[265.0,941.0],[1825.0,1306.0],[1808.0,1373.0],[416.0,1590.0]],[[220.0,1918.0],[1139.0,1676.0],[1905.0,1356.0],[393.0,672.0]],[[1643.0,1749.0],[1956.0,610.0],[1308.0,597.0],[1433.0,562.0]],[[792.0,921.0],[885.0,1859.0],[637.0,423.0],[421.0,1741.0]],[[215.0,1857.0],[621.0,1534.0],[1317.0,1147.0],[1630.0,58.0]],[[1587.0,1995.0],[1824.0,1235.0],[1241.0,1585.0],[1282.0,1186.0]],[[713.0,410.0],[2004.0,736.0],[1825.0,628.0],[1878.0,432.0]],[[505.0,1304.0],[1295.0,2024.0],[1396.0,1309.0],[1894.0,1324.0]],[[1984.0,1614.0],[893.0,680.0],[987.0,819.0],[1004.0,211.0]],[[1314.0,252.0],[1344.0,1719.0],[121.0,1410.0],[1472.0,1480.0]],[[1674.0,856.0],[1182.0,919.0],[1284.0,1627.0],[1575.0,719.0]],[[34.0,1592.0],[1434.0,910.0],[958.0,269.0],[1311.0,1575.0]],[[834.0,1202.0],[392.0,1777.0],[16.0,1437.0],[381.0,1670.0]],[[627.0,456.0],[734.0,1394.0],[590.0,1538.0],[1789.0,1333.0]],[[1135.0,854.0],[794.0,648.0],[674.0,657.0],[600.0,490.0]],[[1810.0,532.0],[1766.0,548.0],[1367.0,1299.0],[561.0,84.0]],[[1468.0,713.0],[926.0,962.0],[2035.0,2001.0],[140.0,367.0]],[[547.0,1920.0],[584.0,856.0],[1476.0,564.0],[1147.0,1427.0]],[[265.0,1571.0],[1946.0,122.0],[1891.0,806.0],[986.0,844.0]],[[20.0,1245.0],[172.0,1093.0],[775.0,294.0],[433.0,451.0]],[[1639.0,1359.0],[429.0,1824.0],[1977.0,1149.0],[584.0,1766.0]],[[1521.0,1429.0],[1571.0,1685.0],[1786.0,1507.0],[843.0,801.0]],[[267.0,593.0],[974.0,982.0],[85.0,987.0],[1612.0,1870.0]],[[1805.0,390.0],[221.0,705.0],[31.0,181.0],[1762.0,1140.0]],[[1701.0,543.0],[965.0,1533.0],[1698.0,1400.0],[193.0,1861.0]],[[529.0,1491.0],[246.0,1430.0],[480.0,1005.0],[510.0,1788.0]],[[609.0,78.0],[1496.0,532.0],[616.0,1180.0],[101.0,1934.0]],[[109.0,1978.0],[274.0,1765.0],[376.0,1924.0],[396.0,527.0]],[[1612.0,1679.0],[990.0,1555.0],[1956.0,1299.0],[1793.0,478.0]],[[275.0,862.0],[1512.0,427.0],[393.0,1453.0],[432.0,802.0]],[[455.0,358.0],[14.0,1768.0],[960.0,374.0],[1258.0,1997.0]],[[253.0,1757.0],[1221.0,1605.0],[167.0,118.0],[1133.0,1959.0]],[[1793.0,896.0],[1100.0,1317.0],[1956.0,1808.0],[224.0,1101.0]],[[711.0,1793.0],[1865.0,1211.0],[747.0,1314.0],[1629.0,1694.0]],[[1631.0,1955.0],[903.0,1254.0],[70.0,258.0],[605.0,2021.0]],[[474.0,1472.0],[1061.0,1266.0],[1241.0,567.0],[437.0,565.0]],[[1864.0,155.0],[1825.0,1923.0],[1334.0,1520.0],[512.0,59.0]],[[825.0,1100.0],[265.0,1892.0],[1160.0,49.0],[1089.0,88.0]],[[1644.0,458.0],[400.0,1319.0],[1832.0,374.0],[2041.0,1407.0]],[[178.0,769.0],[694.0,227.0],[476.0,174.0],[480.0,1249.0]],[[821.0,663.0],[615.0,933.0],[890.0,367.0],[1445.0,1783.0]],[[1092.0,551.0],[1171.0,1016.0],[284.0,1084.0],[232.0,89.0]],[[1768.0,1156.0],[1944.0,1728.0],[1787.0,278.0],[758.0,879.0]],[[139.0,1758.0],[1697.0,1453.0],[1453.0,607.0],[732.0,925.0]],[[939.0,243.0],[1497.0,274.0],[1828.0,1318.0],[891.0,897.0]],[[1055.0,634.0],[1562.0,439.0],[1956.0,7.0],[1933.0,1278.0]],[[1075.0,1192.0],[854.0,543.0],[1558.0,143.0],[1566.0,1872.0]],[[99.0,539.0],[948.0,2020.0],[405.0,1212.0],[1786.0,822.0]],[[1367.0,402.0],[1019.0,993.0],[2013.0,474.0],[728.0,2033.0]],[[1468.0,1774.0],[1639.0,1727.0],[97.0,1635.0],[579.0,1743.0]],[[521.0,248.0],[1197.0,1591.0],[1761.0,390.0],[825.0,1111.0]],[[1961.0,1729.0],[1082.0,436.0],[1334.0,626.0],[1063.0,100.0]],[[397.0,1518.0],[1860.0,1085.0],[387.0,1163.0],[569.0,346.0]],[[1664.0,1558.0],[114.0,1961.0],[532.0,1603.0],[2015.0,954.0]],[[115.0,1540.0],[253.0,1681.0],[344.0,1023.0],[162.0,1860.0]],[[343.0,1202.0],[162.0,1423.0],[173.0,279.0],[299.0,185.0]],[[1256.0,1451.0],[1261.0,371.0],[1927.0,1464.0],[1338.0,700.0]],[[1454.0,1023.0],[1340.0,953.0],[1017.0,891.0],[1272.0,1253.0]],[[1322.0,1236.0],[19.0,1970.0],[1035.0,942.0],[604.0,989.0]],[[660.0,346.0],[1063.0,1633.0],[829.0,564.0],[675.0,303.0]],[[1295.0,1581.0],[864.0,648.0],[158.0,1825.0],[884.0,1641.0]],[[461.0,1273.0],[900.0,1186.0],[1826.0,1378.0],[341.0,280.0]],[[288.0,945.0],[490.0,1898.0],[1877.0,40.0],[686.0,1876.0]],[[1772.0,449.0],[787.0,63.0],[996.0,1260.0],[877.0,1204.0]],[[1261.0,1081.0],[1431.0,1088.0],[1177.0,194.0],[119.0,43.0]],[[1807.0,173.0],[844.0,315.0],[1292.0,1852.0],[1246.0,468.0]],[[1010.0,454.0],[790.0,123.0],[797.0,555.0],[105.0,1803.0]],[[117.0,931.0],[1946.0,708.0],[36.0,917.0],[566.0,256.0]],[[65.0,561.0],[1312.0,346.0],[1068.0,798.0],[1631.0,32.0]],[[1145.0,1441.0],[1060.0,1578.0],[1654.0,1906.0],[1142.0,362.0]],[[737.0,1963.0],[1613.0,545.0],[853.0,105.0],[211.0,1299.0]],[[592.0,896.0],[1305.0,1625.0],[167.0,1672.0],[1944.0,265.0]],[[140.0,537.0],[1682.0,1595.0],[1112.0,181.0],[891.0,795.0]],[[1246.0,1557.0],[1227.0,93.0],[1092.0,781.0],[665.0,941.0]],[[360.0,863.0],[1967.0,674.0],[215.0,1648.0],[1158.0,60.0]],[[618.0,405.0],[162.0,1761.0],[1945.0,717.0],[893.0,1919.0]],[[441.0,1658.0],[917.0,259.0],[520.0,1384.0],[1944.0,2021.0]],[[1505.0,1772.0],[1016.0,1814.0],[1064.0,1655.0],[1457.0,1582.0]],[[937.0,1545.0],[435.0,740.0],[1411.0,310.0],[105.0,1718.0]],[[2023.0,249.0],[1885.0,451.0],[959.0,1862.0],[1438.0,374.0]],[[1372.0,151.0],[1133.0,1372.0],[531.0,684.0],[1760.0,1276.0]],[[1813.0,996.0],[2004.0,1571.0],[113.0,1043.0],[493.0,1174.0]],[[1063.0,101.0],[345.0,1329.0],[741.0,896.0],[1202.0,331.0]],[[698.0,1865.0],[1523.0,1633.0],[1854.0,1933.0],[420.0,2001.0]],[[341.0,139.0],[242.0,76.0],[1141.0,149.0],[1100.0,1273.0]],[[722.0,1955.0],[1381.0,69.0],[1862.0,1400.0],[972.0,927.0]],[[1416.0,237.0],[93.0,1804.0],[811.0,1612.0],[627.0,734.0]],[[950.0,333.0],[1617.0,167.0],[713.0,1311.0],[19.0,1860.0]],[[665.0,156.0],[1730.0,909.0],[1053.0,1793.0],[773.0,166.0]],[[1546.0,1681.0],[1632.0,1745.0],[1113.0,1813.0],[1380.0,97.0]],[[320.0,1935.0],[1717.0,663.0],[1763.0,656.0],[704.0,1094.0]],[[1691.0,1971.0],[1169.0,1422.0],[1870.0,1628.0],[1542.0,1172.0]],[[983.0,1469.0],[923.0,1084.0],[82.0,296.0],[1078.0,1596.0]],[[657.0,1081.0],[1033.0,2009.0],[64.0,652.0],[1980.0,452.0]],[[899.0,622.0],[462.0,1574.0],[232.0,706.0],[279.0,388.0]],[[1918.0,1918.0],[102.0,237.0],[1111.0,210.0],[1934.0,851.0]],[[1457.0,1793.0],[452.0,1387.0],[1304.0,1565.0],[1593.0,1188.0]],[[338.0,938.0],[1807.0,1431.0],[1750.0,1766.0],[1785.0,1091.0]],[[764.0,617.0],[216.0,1353.0],[1440.0,1542.0],[275.0,1302.0]],[[725.0,595.0],[469.0,836.0],[1954.0,954.0],[1468.0,661.0]],[[832.0,1224.0],[703.0,566.0],[1638.0,1743.0],[2003.0,1437.0]],[[139.0,308.0],[99.0,1507.0],[1019.0,637.0],[874.0,1622.0]],[[1817.0,1117.0],[1745.0,1384.0],[1974.0,1395.0],[332.0,224.0]],[[570.0,1924.0],[721.0,372.0],[33.0,266.0],[98.0,751.0]],[[1141.0,795.0],[1886.0,1647.0],[1111.0,1081.0],[1574.0,431.0]],[[1619.0,1897.0],[988.0,291.0],[1280.0,550.0],[108.0,1550.0]],[[230.0,1189.0],[1413.0,69.0],[1798.0,1299.0],[41.0,1293.0]],[[1605.0,209.0],[1829.0,398.0],[1734.0,1663.0],[504.0,71.0]],[[47.0,1673.0],[1426.0,719.0],[1656.0,166.0],[586.0,1169.0]],[[1683.0,680.0],[1921.0,1202.0],[1049.0,143.0],[1600.0,1687.0]],[[599.0,1327.0],[697.0,1856.0],[1610.0,514.0],[323.0,1609.0]],[[1066.0,1604.0],[2003.0,137.0],[1190.0,653.0],[1101.0,1590.0]],[[1122.0,511.0],[1046.0,36.0],[489.0,437.0],[1916.0,619.0]],[[1908.0,986.0],[973.0,170.0],[920.0,327.0],[443.0,395.0]],[[153.0,467.0],[179.0,1033.0],[1699.0,600.0],[1420.0,467.0]],[[204.0,1595.0],[915.0,652.0],[2004.0,702.0],[1442.0,1630.0]],[[701.0,1335.0],[288.0,203.0],[62.0,1220.0],[407.0,1845.0]],[[356.0,2.0],[194.0,1151.0],[1249.0,1042.0],[1878.0,1569.0]],[[480.0,915.0],[1253.0,514.0],[98.0,1499.0],[1828.0,386.0]],[[1765.0,636.0],[1125.0,466.0],[1528.0,1033.0],[864.0,1345.0]],[[577.0,913.0],[30.0,942.0],[1976.0,1469.0],[521.0,1672.0]],[[1404.0,1750.0],[1802.0,458.0],[1025.0,217.0],[1209.0,1305.0]],[[815.0,852.0],[939.0,991.0],[1540.0,1421.0],[1050.0,6.0]],[[2015.0,575.0],[1751.0,1981.0],[370.0,1130.0],[409.0,898.0]],[[444.0,1745.0],[1659.0,582.0],[469.0,1800.0],[886.0,660.0]],[[882.0,1116.0],[1497.0,1337.0],[1422.0,1031.0],[611.0,127.0]],[[906.0,1053.0],[1974.0,65.0],[1400.0,68.0],[714.0,822.0]],[[1063.0,942.0],[299.0,1745.0],[1511.0,1516.0],[776.0,432.0]],[[18.0,1606.0],[1388.0,1350.0],[1680.0,1405.0],[1054.0,1648.0]],[[1129.0,1446.0],[307.0,1791.0],[913.0,1933.0],[1417.0,1158.0]],[[119.0,434.0],[220.0,700.0],[922.0,1799.0],[1203.0,1733.0]],[[1632.0,18.0],[278.0,1625.0],[625.0,850.0],[1942.0,1612.0]],[[2022.0,404.0],[1679.0,675.0],[2018.0,880.0],[1264.0,148.0]],[[1223.0,1200.0],[568.0,1028.0],[1244.0,1949.0],[546.0,1787.0]],[[1365.0,1315.0],[863.0,1138.0],[162.0,1272.0],[1206.0,2036.0]],[[1224.0,1082.0],[654.0,1186.0],[1077.0,1368.0],[610.0,1060.0]],[[1586.0,1810.0],[2027.0,690.0],[1571.0,162.0],[379.0,842.0]],[[1298.0,209.0],[1251.0,164.0],[1701.0,445.0],[1326.0,529.0]],[[42.0,1410.0],[988.0,1451.0],[1779.0,986.0],[342.0,133.0]],[[1371.0,77.0],[1816.0,106.0],[690.0,1151.0],[857.0,1756.0]],[[1184.0,675.0],[179.0,159.0],[2036.0,1598.0],[456.0,1556.0]],[[1179.0,1786.0],[204.0,938.0],[1366.0,1717.0],[1994.0,832.0]],[[364.0,1378.0],[1657.0,734.0],[964.0,1987.0],[295.0,1716.0]],[[1618.0,893.0],[1047.0,6.0],[1154.0,133.0],[1065.0,349.0]],[[736.0,1034.0],[1838.0,1780.0],[1251.0,411.0],[1217.0,220.0]],[[1954.0,719.0],[1042.0,855.0],[516.0,172.0],[1635.0,40.0]],[[1216.0,11.0],[1563.0,1392.0],[396.0,1051.0],[663.0,818.0]],[[297.0,716.0],[1544.0,95.0],[902.0,1663.0],[73.0,17.0]],[[1702.0,719.0],[218.0,1621.0],[1697.0,781.0],[651.0,909.0]],[[375.0,1851.0],[1369.0,1024.0],[785.0,1047.0],[1591.0,1013.0]],[[1197.0,1055.0],[602.0,1089.0],[1481.0,1128.0],[896.0,775.0]],[[89.0,431.0],[895.0,1129.0],[691.0,1319.0],[899.0,666.0]],[[134.0,897.0],[1588.0,1072.0],[1054.0,869.0],[1070.0,1538.0]],[[171.0,135.0],[630.0,2035.0],[1788.0,1234.0],[1501.0,1661.0]],[[1458.0,810.0],[1173.0,1147.0],[1082.0,1979.0],[625.0,1460.0]],[[579.0,1596.0],[250.0,295.0],[1065.0,308.0],[2021.0,852.0]],[[1858.0,1259.0],[164.0,1101.0],[1380.0,17.0],[2029.0,1767.0]],[[1766.0,1735.0],[1501.0,1990.0],[792.0,1771.0],[1603.0,1184.0]],[[393.0,331.0],[659.0,1381.0],[1496.0,1758.0],[1564.0,504.0]],[[1541.0,212.0],[1776.0,823.0],[461.0,938.0],[1956.0,1571.0]],[[708.0,545.0],[901.0,392.0],[1420.0,1323.0],[1800.0,682.0]],[[1549.0,1983.0],[754.0,153.0],[812.0,1023.0],[537.0,489.0]],[[1121.0,53.0],[20.0,1523.0],[1169.0,879.0],[222.0,1277.0]],[[606.0,521.0],[275.0,640.0],[1712.0,1099.0],[535.0,298.0]],[[791.0,658.0],[1707.0,887.0],[1608.0,2007.0],[709.0,263.0]],[[2041.0,994.0],[835.0,298.0],[621.0,1001.0],[775.0,603.0]],[[1063.0,267.0],[1524.0,323.0],[1456.0,1141.0],[734.0,1923.0]],[[1775.0,904.0],[516.0,481.0],[1783.0,1755.0],[1506.0,917.0]],[[1817.0,1604.0],[1362.0,751.0],[214.0,199.0],[1504.0,1897.0]],[[661.0,1911.0],[1528.0,1442.0],[639.0,1873.0],[823.0,1954.0]],[[1155.0,852.0],[520.0,902.0],[1157.0,433.0],[360.0,929.0]],[[1738.0,877.0],[1231.0,2016.0],[252.0,1538.0],[835.0,218.0]],[[1265.0,1226.0],[863.0,1755.0],[51.0,1870.0],[1333.0,1719.0]],[[999.0,431.0],[690.0,208.0],[1565.0,667.0],[70.0,2031.0]],[[1987.0,1510.0],[1747.0,117.0],[1785.0,1594.0],[972.0,33.0]],[[176.0,818.0],[1292.0,146.0],[552.0,1796.0],[731.0,1851.0]],[[599.0,588.0],[1030.0,1564.0],[380.0,505.0],[290.0,1570.0]],[[1982.0,1501.0],[862.0,154.0],[1676.0,903.0],[1970.0,809.0]],[[691.0,969.0],[807.0,1386.0],[1223.0,1955.0],[963.0,872.0]],[[1153.0,504.0],[41.0,150.0],[1291.0,364.0],[731.0,1868.0]],[[329.0,1678.0],[574.0,177.0],[574.0,1309.0],[1469.0,1851.0]],[[780.0,1639.0],[1898.0,351.0],[1615.0,1498.0],[40.0,1167.0]],[[866.0,1458.0],[1533.0,30.0],[388.0,1824.0],[1660.0,1256.0]],[[709.0,1225.0],[898.0,1351.0],[1361.0,867.0],[167.0,208.0]],[[76.0,745.0],[1894.0,1328.0],[150.0,1089.0],[1112.0,269.0]],[[1023.0,48.0],[532.0,1692.0],[1423.0,1105.0],[2041.0,159.0]],[[1580.0,453.0],[1250.0,1717.0],[1016.0,939.0],[1785.0,1081.0]],[[42.0,23.0],[620.0,1945.0],[610.0,1433.0],[317.0,1013.0]],[[632.0,543.0],[1642.0,568.0],[1352.0,795.0],[530.0,560.0]],[[477.0,521.0],[136.0,1139.0],[1118.0,1443.0],[30.0,595.0]],[[35.0,261.0],[1868.0,1772.0],[1628.0,1267.0],[547.0,1604.0]],[[1745.0,1474.0],[1834.0,1432.0],[1197.0,1946.0],[760.0,1101.0]],[[32.0,1275.0],[941.0,217.0],[2045.0,244.0],[30.0,324.0]],[[1897.0,10.0],[1005.0,542.0],[1605.0,1591.0],[911.0,1133.0]],[[750.0,893.0],[661.0,371.0],[1353.0,1420.0],[352.0,499.0]],[[945.0,838.0],[1345.0,1834.0],[339.0,1766.0],[1459.0,676.0]],[[741.0,416.0],[1451.0,756.0],[2020.0,324.0],[1868.0,1766.0]],[[895.0,259.0],[277.0,1030.0],[1344.0,1605.0],[1508.0,1336.0]],[[1762.0,289.0],[779.0,1686.0],[1423.0,2036.0],[1419.0,488.0]],[[1832.0,1348.0],[35.0,922.0],[1245.0,1682.0],[573.0,784.0]],[[1139.0,189.0],[664.0,1269.0],[233.0,455.0],[1088.0,457.0]],[[736.0,1852.0],[1015.0,1919.0],[1765.0,223.0],[577.0,2018.0]],[[1473.0,1195.0],[1537.0,364.0],[1790.0,531.0],[955.0,1753.0]],[[1993.0,256.0],[1481.0,758.0],[253.0,835.0],[776.0,76.0]],[[1421.0,973.0],[978.0,1682.0],[1699.0,676.0],[961.0,3.0]],[[899.0,232.0],[636.0,369.0],[101.0,582.0],[1091.0,940.0]],[[1477.0,1362.0],[564.0,384.0],[1047.0,1690.0],[1456.0,173.0]],[[254.0,1877.0],[154.0,1288.0],[1275.0,1229.0],[1596.0,1256.0]],[[1576.0,1976.0],[1206.0,491.0],[46.0,433.0],[1736.0,301.0]],[[854.0,504.0],[38.0,1006.0],[1921.0,290.0],[871.0,1396.0]],[[879.0,1212.0],[1170.0,1905.0],[1905.0,861.0],[1895.0,1542.0]],[[342.0,126.0],[302.0,1232.0],[1840.0,839.0],[1209.0,1697.0]],[[757.0,1616.0],[1536.0,1896.0],[906.0,1010.0],[2022.0,57.0]],[[1198.0,1099.0],[1942.0,2021.0],[1441.0,448.0],[491.0,876.0]],[[1828.0,1589.0],[880.0,1724.0],[252.0,720.0],[1583.0,1741.0]],[[1530.0,580.0],[278.0,654.0],[184.0,868.0],[1905.0,1269.0]],[[1232.0,1947.0],[551.0,86.0],[1848.0,1776.0],[1413.0,1784.0]],[[1488.0,892.0],[1106.0,832.0],[1888.0,1940.0],[1111.0,1701.0]],[[1165.0,1134.0],[1817.0,269.0],[455.0,1332.0],[1833.0,1176.0]],[[929.0,1311.0],[1016.0,635.0],[643.0,1041.0],[1016.0,1686.0]],[[123.0,1758.0],[1630.0,923.0],[557.0,294.0],[347.0,676.0]],[[1919.0,1554.0],[900.0,1196.0],[1602.0,1099.0],[32.0,1162.0]],[[613.0,492.0],[1765.0,1153.0],[1232.0,1714.0],[250.0,609.0]],[[398.0,678.0],[1996.0,1773.0],[454.0,235.0],[1469.0,1303.0]],[[1258.0,147.0],[1254.0,1848.0],[128.0,1409.0],[1165.0,870.0]],[[1079.0,1121.0],[691.0,1175.0],[1385.0,367.0],[145.0,527.0]],[[538.0,1571.0],[1323.0,1388.0],[1929.0,685.0],[1199.0,111.0]],[[1086.0,72.0],[94.0,1721.0],[1900.0,99.0],[1593.0,435.0]],[[509.0,67.0],[1571.0,366.0],[2045.0,879.0],[1449.0,133.0]],[[1678.0,1933.0],[1307.0,775.0],[34.0,520.0],[1932.0,1928.0]],[[1026.0,1770.0],[412.0,1704.0],[1853.0,1208.0],[381.0,213.0]],[[1735.0,630.0],[1437.0,811.0],[339.0,1869.0],[1481.0,453.0]],[[1356.0,412.0],[833.0,1301.0],[649.0,657.0],[1353.0,334.0]],[[854.0,1201.0],[269.0,2009.0],[1889.0,2048.0],[1820.0,1581.0]],[[1491.0,1945.0],[714.0,583.0],[1.0,717.0],[1263.0,725.0]],[[614.0,849.0],[550.0,998.0],[1873.0,565.0],[347.0,1984.0]],[[1595.0,1615.0],[1737.0,1786.0],[1927.0,1147.0],[1955.0,513.0]],[[810.0,1548.0],[144.0,1123.0],[575.0,1802.0],[891.0,635.0]],[[1598.0,1811.0],[253.0,1423.0],[925.0,639.0],[1170.0,2005.0]],[[1354.0,627.0],[264.0,1611.0],[299.0,303.0],[0.0,123.0]],[[307.0,357.0],[536.0,1030.0],[251.0,853.0],[1764.0,1383.0]],[[1140.0,1455.0],[820.0,649.0],[1678.0,328.0],[1451.0,472.0]],[[1731.0,1846.0],[1366.0,416.0],[42.0,229.0],[607.0,1670.0]],[[864.0,826.0],[279.0,656.0],[1865.0,97.0],[1339.0,1206.0]],[[1271.0,628.0],[1852.0,214.0],[179.0,1180.0],[652.0,99.0]],[[1293.0,97.0],[605.0,1032.0],[436.0,956.0],[1050.0,2026.0]],[[2044.0,785.0],[316.0,536.0],[1169.0,123.0],[966.0,645.0]],[[716.0,997.0],[1884.0,440.0],[14.0,801.0],[1497.0,698.0]],[[1106.0,388.0],[330.0,1230.0],[950.0,1543.0],[1219.0,555.0]],[[1234.0,570.0],[1219.0,493.0],[1226.0,411.0],[854.0,1802.0]],[[1636.0,400.0],[124.0,1619.0],[1952.0,31.0],[1203.0,1922.0]],[[1920.0,1511.0],[737.0,857.0],[1954.0,817.0],[927.0,564.0]],[[1772.0,813.0],[1493.0,2012.0],[933.0,199.0],[1006.0,470.0]],[[1487.0,273.0],[174.0,870.0],[1769.0,1356.0],[1667.0,1840.0]],[[1809.0,1885.0],[1839.0,1520.0],[160.0,833.0],[1063.0,533.0]],[[443.0,1700.0],[819.0,1341.0],[422.0,21.0],[914.0,812.0]],[[1573.0,798.0],[1241.0,1265.0],[1533.0,953.0],[115.0,1022.0]],[[1136.0,1249.0],[742.0,468.0],[60.0,1425.0],[632.0,1595.0]],[[2011.0,1864.0],[460.0,925.0],[1438.0,252.0],[336.0,988.0]],[[703.0,808.0],[1751.0,575.0],[1550.0,1642.0],[1442.0,336.0]],[[152.0,1865.0],[1448.0,1179.0],[1524.0,1347.0],[1532.0,45.0]],[[468.0,1584.0],[1235.0,1119.0],[239.0,1965.0],[1132.0,213.0]],[[2013.0,1301.0],[1754.0,1866.0],[901.0,698.0],[168.0,1642.0]],[[1050.0,785.0],[1289.0,824.0],[457.0,685.0],[1722.0,1727.0]],[[1035.0,528.0],[380.0,1056.0],[981.0,1144.0],[753.0,1856.0]],[[1743.0,69.0],[592.0,1250.0],[567.0,581.0],[1685.0,150.0]],[[1913.0,2029.0],[183.0,1584.0],[434.0,1204.0],[1693.0,1897.0]],[[440.0,1750.0],[1681.0,109.0],[1075.0,253.0],[1193.0,1062.0]],[[1332.0,117.0],[573.0,225.0],[894.0,1294.0],[397.0,671.0]],[[1236.0,1691.0],[587.0,324.0],[2030.0,258.0],[1744.0,1497.0]],[[612.0,1886.0],[1663.0,1342.0],[1155.0,2042.0],[318.0,553.0]],[[73.0,360.0],[840.0,1489.0],[1965.0,607.0],[715.0,543.0]],[[1739.0,186.0],[305.0,1458.0],[1277.0,1028.0],[1476.0,1515.0]],[[1270.0,1665.0],[1632.0,1949.0],[1795.0,1508.0],[1335.0,1690.0]],[[620.0,543.0],[1957.0,1025.0],[1035.0,1749.0],[1931.0,198.0]],[[1204.0,2020.0],[1411.0,2027.0],[538.0,1830.0],[593.0,1942.0]],[[619.0,953.0],[1364.0,287.0],[1495.0,696.0],[1720.0,1678.0]],[[1246.0,1105.0],[904.0,41.0],[1965.0,1464.0],[331.0,1076.0]],[[1990.0,1609.0],[1881.0,186.0],[1749.0,1036.0],[1996.0,612.0]],[[1318.0,607.0],[843.0,1561.0],[498.0,454.0],[1316.0,588.0]],[[1921.0,1839.0],[632.0,2023.0],[638.0,249.0],[775.0,1632.0]],[[1369.0,1059.0],[1999.0,1185.0],[151.0,1785.0],[329.0,878.0]],[[109.0,1310.0],[1657.0,1194.0],[1008.0,1229.0],[1768.0,1433.0]],[[1809.0,1328.0],[1137.0,493.0],[1522.0,139.0],[1182.0,832.0]],[[445.0,1058.0],[69.0,1056.0],[1368.0,452.0],[1632.0,1887.0]],[[1207.0,1145.0],[1526.0,591.0],[2016.0,236.0],[427.0,1551.0]],[[1820.0,1282.0],[28.0,1911.0],[963.0,558.0],[1284.0,614.0]],[[835.0,1987.0],[703.0,1152.0],[1411.0,898.0],[849.0,250.0]],[[1861.0,1129.0],[1898.0,1888.0],[1924.0,1495.0],[1749.0,1732.0]],[[279.0,921.0],[1411.0,227.0],[1331.0,425.0],[1571.0,2047.0]],[[1355.0,583.0],[831.0,280.0],[1098.0,2035.0],[1992.0,1919.0]],[[1305.0,1906.0],[328.0,2017.0],[1147.0,464.0],[539.0,1706.0]],[[381.0,592.0],[1565.0,394.0],[1735.0,893.0],[600.0,15.0]],[[460.0,415.0],[335.0,1353.0],[509.0,1533.0],[1707.0,1616.0]],[[305.0,1695.0],[1847.0,1229.0],[1785.0,1804.0],[1629.0,546.0]],[[1872.0,1958.0],[1585.0,434.0],[1360.0,1136.0],[578.0,1084.0]],[[178.0,387.0],[681.0,145.0],[18.0,1339.0],[1384.0,168.0]],[[662.0,1727.0],[1798.0,70.0],[1766.0,1645.0],[500.0,1618.0]],[[232.0,112.0],[558.0,983.0],[1990.0,1599.0],[1285.0,525.0]],[[1181.0,570.0],[573.0,578.0],[597.0,970.0],[812.0,125.0]],[[870.0,2005.0],[1875.0,1490.0],[1923.0,1753.0],[2.0,1720.0]],[[977.0,1552.0],[1092.0,109.0],[1326.0,445.0],[1005.0,1755.0]],[[1052.0,529.0],[1916.0,1504.0],[1031.0,496.0],[373.0,1433.0]],[[1658.0,1810.0],[1493.0,1727.0],[1798.0,2046.0],[1542.0,115.0]],[[196.0,1998.0],[1321.0,946.0],[422.0,80.0],[1433.0,315.0]],[[735.0,1946.0],[502.0,946.0],[592.0,1882.0],[309.0,686.0]],[[1143.0,1939.0],[1494.0,765.0],[954.0,178.0],[1197.0,1816.0]],[[1856.0,1154.0],[1006.0,45.0],[1245.0,1925.0],[609.0,812.0]],[[806.0,743.0],[1254.0,295.0],[1051.0,690.0],[1604.0,1238.0]],[[740.0,1861.0],[1630.0,383.0],[1463.0,1461.0],[944.0,11.0]],[[673.0,1862.0],[515.0,1156.0],[1583.0,608.0],[1379.0,1404.0]],[[1026.0,13.0],[587.0,770.0],[1053.0,872.0],[25.0,237.0]],[[148.0,1881.0],[1165.0,911.0],[449.0,319.0],[612.0,831.0]],[[729.0,127.0],[1784.0,642.0],[703.0,1802.0],[1313.0,212.0]],[[1829.0,1464.0],[1175.0,522.0],[215.0,996.0],[465.0,1852.0]],[[2013.0,941.0],[1296.0,457.0],[1253.0,618.0],[1091.0,1719.0]],[[1085.0,470.0],[74.0,17.0],[1518.0,753.0],[232.0,1340.0]],[[651.0,173.0],[141.0,120.0],[1070.0,1014.0],[125.0,1193.0]],[[1975.0,2045.0],[1383.0,366.0],[817.0,717.0],[1438.0,365.0]],[[1515.0,591.0],[1474.0,794.0],[1891.0,1551.0],[1835.0,1420.0]],[[320.0,1010.0],[955.0,389.0],[966.0,361.0],[1278.0,1514.0]],[[332.0,499.0],[1476.0,1021.0],[1161.0,1268.0],[510.0,685.0]],[[1665.0,867.0],[1900.0,559.0],[806.0,325.0],[1777.0,297.0]],[[1561.0,630.0],[999.0,1234.0],[1049.0,1961.0],[1582.0,480.0]],[[444.0,1472.0],[1860.0,1974.0],[1616.0,869.0],[1365.0,615.0]],[[1099.0,1331.0],[802.0,184.0],[1648.0,1088.0],[1318.0,440.0]],[[543.0,835.0],[1529.0,1926.0],[1329.0,176.0],[225.0,1877.0]],[[549.0,1860.0],[2043.0,873.0],[1139.0,1054.0],[639.0,1163.0]],[[486.0,1301.0],[915.0,1399.0],[1280.0,804.0],[497.0,1702.0]],[[864.0,1722.0],[544.0,363.0],[1591.0,119.0],[1580.0,570.0]],[[1613.0,1416.0],[1624.0,599.0],[381.0,945.0],[817.0,1992.0]],[[1937.0,1551.0],[1301.0,1034.0],[36.0,1067.0],[99.0,1561.0]],[[1610.0,592.0],[698.0,1063.0],[406.0,1666.0],[467.0,1956.0]],[[1654.0,219.0],[1998.0,334.0],[325.0,911.0],[1381.0,1580.0]],[[1406.0,1456.0],[1027.0,989.0],[1678.0,562.0],[906.0,1642.0]],[[190.0,1008.0],[769.0,604.0],[1388.0,767.0],[445.0,853.0]],[[1722.0,215.0],[1361.0,1480.0],[1430.0,1788.0],[933.0,1435.0]],[[1559.0,292.0],[921.0,1916.0],[525.0,1461.0],[1510.0,378.0]],[[1896.0,1712.0],[1546.0,1076.0],[300.0,1875.0],[1912.0,610.0]],[[1079.0,58.0],[1484.0,1735.0],[968.0,1438.0],[1907.0,1357.0]],[[1805.0,47.0],[592.0,984.0],[405.0,922.0],[1116.0,1495.0]],[[917.0,755.0],[1821.0,1465.0],[1506.0,159.0],[747.0,1592.0]],[[1447.0,1423.0],[1674.0,1237.0],[1066.0,1877.0],[336.0,218.0]],[[424.0,1103.0],[1268.0,870.0],[1749.0,819.0],[1006.0,1142.0]],[[376.0,1708.0],[1606.0,1178.0],[1197.0,1989.0],[378.0,1691.0]],[[919.0,818.0],[1972.0,497.0],[1470.0,341.0],[128.0,334.0]],[[1323.0,1000.0],[1812.0,371.0],[789.0,135.0],[1807.0,543.0]],[[350.0,1928.0],[264.0,204.0],[590.0,2024.0],[513.0,2024.0]],[[1786.0,1963.0],[1205.0,46.0],[1024.0,487.0],[373.0,1496.0]],[[137.0,955.0],[620.0,89.0],[1560.0,171.0],[542.0,1365.0]],[[1569.0,297.0],[1844.0,1261.0],[1342.0,847.0],[1748.0,1982.0]],[[262.0,1559.0],[1032.0,18.0],[431.0,1237.0],[901.0,1548.0]],[[53.0,1603.0],[309.0,368.0],[997.0,256.0],[1716.0,1830.0]],[[1274.0,133.0],[588.0,2023.0],[1987.0,1505.0],[614.0,477.0]],[[845.0,1096.0],[57.0,2035.0],[1854.0,589.0],[604.0,1295.0]],[[1639.0,1808.0],[1116.0,1878.0],[1516.0,1625.0],[343.0,89.0]],[[883.0,912.0],[1009.0,1423.0],[1774.0,393.0],[339.0,119.0]],[[956.0,1357.0],[983.0,822.0],[670.0,344.0],[661.0,251.0]],[[1230.0,1026.0],[1367.0,1425.0],[1735.0,1522.0],[843.0,6.0]],[[2044.0,536.0],[731.0,1561.0],[8.0,746.0],[68.0,1085.0]],[[1498.0,894.0],[1666.0,775.0],[997.0,1712.0],[831.0,1701.0]],[[1554.0,176.0],[700.0,5.0],[851.0,410.0],[235.0,1192.0]],[[603.0,1609.0],[1475.0,753.0],[690.0,669.0],[602.0,2047.0]],[[362.0,1832.0],[748.0,1179.0],[1094.0,1432.0],[1812.0,992.0]],[[178.0,937.0],[891.0,1101.0],[980.0,1762.0],[1146.0,963.0]],[[1473.0,2007.0],[1683.0,827.0],[1878.0,1292.0],[190.0,952.0]],[[911.0,635.0],[1734.0,504.0],[300.0,1706.0],[1744.0,1560.0]],[[1876.0,387.0],[829.0,241.0],[1600.0,854.0],[864.0,1770.0]],[[1931.0,1532.0],[430.0,1541.0],[1204.0,1505.0],[1281.0,720.0]],[[1727.0,1009.0],[779.0,307.0],[929.0,350.0],[1042.0,1720.0]],[[913.0,2016.0],[1048.0,137.0],[1613.0,1411.0],[1644.0,1901.0]],[[1707.0,836.0],[223.0,1169.0],[951.0,618.0],[585.0,1379.0]],[[1215.0,1848.0],[1743.0,1234.0],[1532.0,1282.0],[1062.0,931.0]],[[1857.0,1615.0],[1350.0,156.0],[862.0,390.0],[558.0,1012.0]],[[1440.0,589.0],[1830.0,1634.0],[1026.0,51.0],[1706.0,1293.0]],[[586.0,1304.0],[283.0,847.0],[1582.0,861.0],[1638.0,369.0]],[[1917.0,865.0],[461.0,567.0],[1556.0,457.0],[1581.0,1003.0]],[[1912.0,1978.0],[335.0,662.0],[23.0,1445.0],[230.0,1882.0]],[[559.0,2047.0],[1571.0,826.0],[773.0,251.0],[1393.0,805.0]],[[1960.0,1148.0],[731.0,2037.0],[1709.0,196.0],[635.0,787.0]],[[41.0,1259.0],[1715.0,292.0],[755.0,98.0],[1542.0,1185.0]],[[607.0,1168.0],[564.0,699.0],[1222.0,957.0],[1263.0,1837.0]],[[866.0,796.0],[213.0,843.0],[1541.0,1342.0],[1459.0,1569.0]],[[180.0,1619.0],[361.0,644.0],[2021.0,630.0],[1443.0,1266.0]],[[740.0,164.0],[1974.0,1888.0],[1459.0,1412.0],[1422.0,891.0]],[[547.0,988.0],[1697.0,258.0],[982.0,1053.0],[1226.0,1899.0]],[[1369.0,1813.0],[66.0,2014.0],[1998.0,543.0],[108.0,1741.0]],[[1586.0,766.0],[1170.0,1547.0],[780.0,1635.0],[105.0,996.0]],[[1983.0,1392.0],[1484.0,1823.0],[1267.0,322.0],[237.0,1291.0]],[[644.0,557.0],[216.0,1481.0],[1935.0,990.0],[174.0,142.0]],[[59.0,1955.0],[1878.0,1912.0],[1758.0,994.0],[1662.0,720.0]],[[424.0,994.0],[1166.0,1246.0],[942.0,102.0],[432.0,841.0]],[[1759.0,1169.0],[2030.0,1148.0],[1255.0,449.0],[1910.0,568.0]],[[1151.0,1281.0],[1275.0,1391.0],[145.0,1216.0],[805.0,1045.0]],[[1902.0,912.0],[13.0,1282.0],[1870.0,454.0],[264.0,1746.0]],[[1446.0,1033.0],[172.0,573.0],[1250.0,1534.0],[1406.0,1635.0]],[[733.0,214.0],[1917.0,1336.0],[669.0,939.0],[1966.0,667.0]],[[1747.0,1630.0],[448.0,1279.0],[374.0,1880.0],[665.0,1782.0]],[[2009.0,574.0],[258.0,127.0],[1963.0,542.0],[978.0,182.0]],[[1235.0,1695.0],[1897.0,1053.0],[1428.0,1364.0],[1496.0,138.0]],[[737.0,1749.0],[911.0,2034.0],[1521.0,1036.0],[995.0,270.0]],[[1063.0,1198.0],[138.0,1202.0],[1958.0,1973.0],[670.0,378.0]],[[815.0,205.0],[1390.0,1171.0],[270.0,925.0],[694.0,595.0]],[[1774.0,1285.0],[818.0,1904.0],[758.0,3.0],[828.0,207.0]],[[71.0,313.0],[1584.0,1480.0],[1790.0,768.0],[660.0,20.0]],[[1744.0,129.0],[1007.0,254.0],[1609.0,461.0],[1513.0,1533.0]],[[547.0,1559.0],[384.0,1303.0],[2006.0,15.0],[1915.0,962.0]],[[1653.0,327.0],[1773.0,1540.0],[78.0,1409.0],[1201.0,949.0]],[[1631.0,2033.0],[1655.0,1512.0],[204.0,252.0],[1669.0,1754.0]],[[643.0,594.0],[1354.0,780.0],[577.0,2014.0],[1692.0,1284.0]],[[24.0,1497.0],[1526.0,1484.0],[328.0,1571.0],[539.0,148.0]],[[579.0,202.0],[1264.0,1083.0],[1363.0,166.0],[324.0,522.0]],[[562.0,982.0],[1300.0,863.0],[644.0,1818.0],[815.0,1673.0]],[[1525.0,539.0],[1274.0,751.0],[1884.0,101.0],[730.0,499.0]],[[129.0,577.0],[1696.0,1195.0],[870.0,233.0],[290.0,1737.0]],[[1099.0,1925.0],[1806.0,1906.0],[333.0,1405.0],[435.0,1228.0]],[[938.0,182.0],[973.0,475.0],[842.0,733.0],[1609.0,1659.0]],[[527.0,946.0],[846.0,1998.0],[628.0,477.0],[1569.0,1822.0]],[[1470.0,85.0],[1971.0,1998.0],[240.0,1020.0],[1162.0,710.0]],[[1920.0,279.0],[1302.0,354.0],[1069.0,1236.0],[531.0,243.0]],[[1291.0,324.0],[603.0,2048.0],[533.0,707.0],[100.0,2.0]],[[251.0,283.0],[1478.0,1954.0],[196.0,317.0],[1882.0,1861.0]],[[72.0,1128.0],[1457.0,1837.0],[329.0,1421.0],[263.0,716.0]],[[725.0,17.0],[1616.0,793.0],[917.0,633.0],[1992.0,502.0]],[[1424.0,2010.0],[421.0,724.0],[2048.0,1265.0],[398.0,1228.0]],[[361.0,477.0],[1319.0,1807.0],[1181.0,1801.0],[1182.0,1798.0]],[[1890.0,612.0],[1244.0,1104.0],[317.0,1171.0],[138.0,1623.0]],[[532.0,2005.0],[1324.0,1074.0],[497.0,1185.0],[1784.0,908.0]],[[999.0,1599.0],[298.0,1647.0],[517.0,1039.0],[172.0,1038.0]],[[963.0,1388.0],[330.0,1058.0],[1562.0,427.0],[538.0,990.0]],[[1991.0,1327.0],[1893.0,1666.0],[332.0,1918.0],[147.0,1779.0]],[[813.0,1614.0],[1066.0,524.0],[545.0,1546.0],[226.0,73.0]],[[219.0,1805.0],[15.0,1417.0],[1824.0,1337.0],[760.0,856.0]],[[1805.0,877.0],[819.0,1594.0],[1359.0,1813.0],[1142.0,1123.0]],[[661.0,1229.0],[357.0,288.0],[1964.0,998.0],[391.0,2046.0]],[[491.0,1842.0],[683.0,462.0],[1330.0,1545.0],[918.0,392.0]],[[1846.0,936.0],[458.0,357.0],[1950.0,1031.0],[1238.0,81.0]],[[1366.0,1574.0],[999.0,1766.0],[625.0,1838.0],[278.0,1948.0]],[[1050.0,1677.0],[278.0,500.0],[1573.0,485.0],[1095.0,1549.0]],[[131.0,376.0],[1409.0,305.0],[1605.0,1924.0],[1963.0,643.0]],[[1638.0,173.0],[1070.0,1631.0],[1605.0,1578.0],[1853.0,63.0]],[[994.0,535.0],[300.0,2043.0],[1655.0,858.0],[439.0,1891.0]],[[804.0,1655.0],[1663.0,1780.0],[105.0,1149.0],[89.0,178.0]],[[1992.0,1713.0],[535.0,721.0],[774.0,1541.0],[1162.0,324.0]],[[173.0,1692.0],[598.0,1912.0],[651.0,1216.0],[162.0,1231.0]],[[1198.0,128.0],[1341.0,1203.0],[130.0,1997.0],[355.0,669.0]],[[1569.0,2019.0],[1080.0,1839.0],[92.0,1720.0],[143.0,1208.0]],[[201.0,1421.0],[817.0,1402.0],[740.0,1002.0],[566.0,372.0]],[[166.0,386.0],[632.0,1258.0],[1294.0,2019.0],[1941.0,87.0]],[[1577.0,1553.0],[960.0,582.0],[428.0,1708.0],[1580.0,916.0]],[[34.0,1295.0],[1679.0,1591.0],[894.0,543.0],[1790.0,723.0]],[[448.0,461.0],[1220.0,719.0],[1440.0,1935.0],[2038.0,657.0]],[[1094.0,982.0],[1081.0,288.0],[1332.0,1002.0],[899.0,1076.0]],[[661.0,536.0],[232.0,1895.0],[1460.0,528.0],[1017.0,1247.0]],[[169.0,1738.0],[1829.0,2018.0],[217.0,710.0],[1549.0,2041.0]],[[1280.0,1256.0],[1139.0,648.0],[1465.0,1509.0],[379.0,1758.0]],[[992.0,1488.0],[386.0,1443.0],[994.0,270.0],[1501.0,1272.0]],[[176.0,1450.0],[51.0,1577.0],[393.0,9.0],[9.0,733.0]],[[1892.0,446.0],[886.0,1528.0],[272.0,565.0],[1641.0,754.0]],[[1793.0,388.0],[1115.0,1962.0],[746.0,1533.0],[618.0,495.0]],[[546.0,318.0],[1622.0,660.0],[747.0,919.0],[1176.0,438.0]],[[201.0,891.0],[25.0,881.0],[51.0,1811.0],[785.0,1540.0]],[[1216.0,611.0],[1389.0,1523.0],[1551.0,443.0],[795.0,1389.0]],[[33.0,1730.0],[1828.0,791.0],[677.0,90.0],[1078.0,1918.0]],[[953.0,337.0],[266.0,880.0],[574.0,1018.0],[981.0,1478.0]],[[76.0,810.0],[1842.0,131.0],[404.0,713.0],[1683.0,526.0]],[[1989.0,940.0],[982.0,230.0],[1521.0,692.0],[668.0,1767.0]],[[1007.0,1101.0],[1418.0,831.0],[1209.0,969.0],[419.0,168.0]],[[1350.0,1252.0],[731.0,515.0],[1692.0,1301.0],[1164.0,95.0]],[[1014.0,117.0],[1302.0,1954.0],[207.0,838.0],[1635.0,405.0]],[[1802.0,1658.0],[2023.0,829.0],[1833.0,438.0],[788.0,718.0]],[[1055.0,1075.0],[30.0,275.0],[1582.0,75.0],[783.0,1363.0]],[[1122.0,840.0],[1957.0,606.0],[1852.0,169.0],[1557.0,1617.0]],[[1646.0,226.0],[247.0,1184.0],[1448.0,959.0],[804.0,1882.0]],[[1925.0,1922.0],[154.0,782.0],[482.0,1316.0],[1226.0,1753.0]],[[1019.0,643.0],[1135.0,1091.0],[1534.0,438.0],[1472.0,1740.0]],[[1736.0,1848.0],[1962.0,915.0],[402.0,724.0],[1848.0,1913.0]],[[233.0,419.0],[345.0,1642.0],[1633.0,1089.0],[783.0,2015.0]],[[1464.0,1539.0],[462.0,50.0],[972.0,2001.0],[1578.0,1077.0]],[[1092.0,349.0],[664.0,1613.0],[401.0,210.0],[868.0,1412.0]],[[737.0,712.0],[1190.0,472.0],[959.0,60.0],[1713.0,1180.0]],[[642.0,597.0],[546.0,1342.0],[779.0,503.0],[1369.0,2021.0]],[[827.0,1279.0],[160.0,781.0],[722.0,1352.0],[780.0,787.0]],[[1735.0,453.0],[1336.0,1103.0],[731.0,10.0],[1242.0,1567.0]],[[1580.0,1655.0],[260.0,1298.0],[1376.0,552.0],[1061.0,1096.0]],[[1807.0,654.0],[1888.0,784.0],[1571.0,1922.0],[382.0,1811.0]],[[498.0,765.0],[1052.0,1267.0],[1680.0,1205.0],[1223.0,816.0]],[[1462.0,533.0],[880.0,426.0],[1765.0,887.0],[1073.0,969.0]],[[540.0,278.0],[1381.0,213.0],[1826.0,1026.0],[239.0,235.0]],[[1006.0,150.0],[1450.0,380.0],[692.0,739.0],[784.0,768.0]],[[177.0,47.0],[1673.0,2023.0],[245.0,982.0],[984.0,442.0]],[[1331.0,1746.0],[723.0,131.0],[1582.0,1248.0],[1449.0,126.0]],[[1882.0,1398.0],[1581.0,1793.0],[2043.0,1939.0],[1455.0,670.0]],[[1790.0,249.0],[1346.0,1061.0],[196.0,127.0],[1573.0,630.0]],[[1945.0,804.0],[1597.0,1914.0],[731.0,927.0],[244.0,673.0]],[[1684.0,1856.0],[4.0,811.0],[190.0,1624.0],[301.0,1647.0]],[[23.0,579.0],[921.0,1636.0],[1389.0,852.0],[419.0,1593.0]],[[1297.0,134.0],[313.0,827.0],[1434.0,1441.0],[174.0,1750.0]],[[1252.0,1783.0],[1201.0,658.0],[691.0,549.0],[51.0,2.0]],[[1784.0,881.0],[909.0,1798.0],[393.0,30.0],[1787.0,652.0]],[[1179.0,1892.0],[761.0,1600.0],[786.0,1188.0],[1297.0,470.0]],[[484.0,485.0],[1981.0,210.0],[1573.0,1456.0],[226.0,432.0]],[[1900.0,1094.0],[238.0,1342.0],[1792.0,512.0],[1272.0,1876.0]],[[195.0,519.0],[1180.0,464.0],[500.0,333.0],[1754.0,1763.0]],[[351.0,1732.0],[1457.0,689.0],[2017.0,2045.0],[1698.0,1202.0]],[[1892.0,1913.0],[991.0,855.0],[788.0,540.0],[254.0,1134.0]],[[56.0,1809.0],[1837.0,718.0],[853.0,1184.0],[1239.0,595.0]],[[348.0,755.0],[369.0,682.0],[698.0,1668.0],[689.0,873.0]],[[1727.0,1035.0],[1389.0,628.0],[950.0,1698.0],[1344.0,46.0]],[[945.0,699.0],[1197.0,232.0],[458.0,924.0],[124.0,1746.0]],[[18.0,138.0],[713.0,77.0],[1800.0,1734.0],[600.0,1491.0]],[[1642.0,923.0],[2028.0,1144.0],[499.0,1180.0],[96.0,1201.0]],[[253.0,1172.0],[225.0,377.0],[1516.0,1458.0],[469.0,1844.0]],[[1124.0,140.0],[227.0,1118.0],[1387.0,1428.0],[1004.0,1149.0]],[[2007.0,1082.0],[276.0,939.0],[1672.0,1559.0],[1924.0,664.0]],[[1691.0,1877.0],[1779.0,907.0],[1870.0,335.0],[1616.0,1556.0]],[[772.0,822.0],[545.0,153.0],[585.0,1871.0],[1438.0,1443.0]],[[384.0,1038.0],[987.0,1309.0],[1268.0,72.0],[1045.0,1780.0]],[[1863.0,1087.0],[1395.0,340.0],[50.0,1100.0],[1743.0,633.0]],[[946.0,1521.0],[1577.0,20.0],[967.0,717.0],[909.0,490.0]],[[786.0,385.0],[790.0,945.0],[173.0,1695.0],[1400.0,590.0]],[[51.0,1909.0],[886.0,248.0],[140.0,409.0],[147.0,768.0]],[[1447.0,257.0],[1542.0,888.0],[1304.0,1602.0],[1192.0,702.0]],[[1196.0,1264.0],[1143.0,1484.0],[935.0,901.0],[489.0,1547.0]],[[582.0,1474.0],[1163.0,1440.0],[1459.0,215.0],[232.0,370.0]],[[1778.0,1388.0],[1460.0,986.0],[1249.0,1169.0],[1582.0,1321.0]],[[683.0,609.0],[410.0,621.0],[911.0,1239.0],[1780.0,1728.0]],[[1079.0,1498.0],[1265.0,1812.0],[1832.0,231.0],[1863.0,1680.0]],[[1.0,506.0],[1220.0,742.0],[298.0,461.0],[979.0,1486.0]],[[1835.0,1501.0],[1185.0,615.0],[1136.0,419.0],[528.0,2002.0]],[[1357.0,950.0],[1443.0,154.0],[228.0,481.0],[752.0,2035.0]],[[1863.0,382.0],[1663.0,250.0],[614.0,296.0],[1244.0,45.0]],[[1879.0,993.0],[945.0,884.0],[534.0,1662.0],[541.0,610.0]],[[641.0,1449.0],[229.0,1523.0],[120.0,2032.0],[1851.0,377.0]],[[143.0,1835.0],[562.0,1566.0],[1088.0,247.0],[155.0,155.0]],[[754.0,910.0],[1155.0,486.0],[1248.0,756.0],[146.0,438.0]],[[1959.0,608.0],[1041.0,472.0],[344.0,1347.0],[543.0,944.0]],[[931.0,1377.0],[1803.0,1427.0],[46.0,269.0],[1118.0,757.0]],[[59.0,1514.0],[1205.0,697.0],[46.0,2009.0],[686.0,1485.0]],[[1496.0,1758.0],[2046.0,1933.0],[1411.0,1672.0],[400.0,309.0]],[[404.0,937.0],[1330.0,845.0],[154.0,244.0],[1442.0,906.0]],[[1708.0,1543.0],[211.0,209.0],[1771.0,1137.0],[1535.0,299.0]],[[423.0,1345.0],[735.0,1425.0],[1590.0,1912.0],[650.0,717.0]],[[1717.0,1933.0],[774.0,108.0],[652.0,811.0],[751.0,331.0]],[[107.0,366.0],[781.0,1854.0],[1054.0,249.0],[1632.0,1104.0]],[[1727.0,970.0],[1851.0,508.0],[284.0,868.0],[851.0,891.0]],[[125.0,717.0],[1686.0,2002.0],[1800.0,1356.0],[728.0,784.0]],[[1722.0,380.0],[1561.0,1490.0],[1482.0,353.0],[1883.0,30.0]],[[802.0,1142.0],[1461.0,1471.0],[114.0,768.0],[1007.0,1741.0]],[[1329.0,1511.0],[1804.0,1895.0],[452.0,145.0],[857.0,1402.0]],[[316.0,1766.0],[1034.0,997.0],[237.0,1274.0],[385.0,1274.0]],[[604.0,1762.0],[1479.0,340.0],[1254.0,295.0],[1812.0,1958.0]],[[671.0,980.0],[4.0,121.0],[813.0,863.0],[1343.0,375.0]],[[1596.0,1680.0],[1549.0,1401.0],[1551.0,1793.0],[1153.0,1460.0]],[[779.0,573.0],[1220.0,388.0],[1996.0,1434.0],[1624.0,756.0]],[[135.0,347.0],[2016.0,245.0],[1608.0,633.0],[561.0,751.0]],[[282.0,1611.0],[791.0,1606.0],[1454.0,1696.0],[713.0,1666.0]],[[1124.0,956.0],[1535.0,33.0],[1199.0,1178.0],[1096.0,597.0]],[[843.0,1907.0],[159.0,1109.0],[470.0,359.0],[210.0,272.0]],[[2039.0,554.0],[1993.0,1892.0],[1595.0,925.0],[217.0,1700.0]],[[694.0,215.0],[1190.0,1860.0],[183.0,636.0],[781.0,852.0]],[[660.0,875.0],[517.0,77.0],[1539.0,70.0],[1659.0,1506.0]],[[1477.0,1366.0],[619.0,1319.0],[1321.0,1390.0],[240.0,1326.0]],[[1856.0,664.0],[380.0,61.0],[109.0,1996.0],[424.0,771.0]],[[1596.0,1686.0],[449.0,1074.0],[1787.0,179.0],[1880.0,886.0]],[[178.0,11.0],[1201.0,1722.0],[260.0,1371.0],[1414.0,1644.0]],[[252.0,1102.0],[539.0,838.0],[53.0,657.0],[1828.0,217.0]],[[1685.0,447.0],[133.0,689.0],[1887.0,266.0],[47.0,35.0]],[[577.0,924.0],[11.0,128.0],[962.0,1783.0],[441.0,1995.0]],[[1527.0,1367.0],[671.0,871.0],[1000.0,343.0],[891.0,676.0]],[[1233.0,379.0],[322.0,853.0],[529.0,308.0],[1842.0,1056.0]],[[1479.0,1012.0],[577.0,705.0],[979.0,1739.0],[305.0,1523.0]],[[711.0,246.0],[177.0,1143.0],[26.0,1955.0],[1704.0,786.0]],[[460.0,1444.0],[1372.0,1058.0],[674.0,1165.0],[1215.0,1996.0]],[[1327.0,1752.0],[455.0,196.0],[266.0,260.0],[1277.0,1724.0]],[[1582.0,1524.0],[1344.0,367.0],[601.0,1804.0],[1710.0,921.0]],[[1036.0,1697.0],[1377.0,1277.0],[708.0,171.0],[462.0,411.0]],[[1793.0,498.0],[1947.0,1429.0],[1128.0,489.0],[1287.0,1564.0]],[[498.0,673.0],[1836.0,363.0],[2040.0,1402.0],[508.0,1317.0]],[[400.0,404.0],[998.0,2028.0],[993.0,1990.0],[1380.0,181.0]],[[682.0,252.0],[63.0,1755.0],[1358.0,1248.0],[1007.0,1455.0]],[[598.0,289.0],[771.0,142.0],[721.0,1464.0],[1785.0,1079.0]],[[860.0,659.0],[858.0,1660.0],[758.0,716.0],[979.0,1903.0]],[[586.0,1154.0],[1327.0,659.0],[1308.0,1154.0],[986.0,799.0]],[[683.0,1154.0],[131.0,582.0],[533.0,105.0],[1787.0,213.0]],[[1434.0,1838.0],[593.0,1752.0],[884.0,642.0],[1467.0,713.0]],[[280.0,1073.0],[1521.0,1374.0],[198.0,1249.0],[637.0,1968.0]],[[212.0,1906.0],[1708.0,359.0],[74.0,33.0],[177.0,66.0]],[[118.0,881.0],[1512.0,834.0],[1845.0,181.0],[203.0,907.0]],[[1221.0,821.0],[732.0,790.0],[813.0,1521.0],[880.0,554.0]],[[409.0,1286.0],[656.0,1903.0],[2044.0,94.0],[1959.0,277.0]],[[53.0,1860.0],[1309.0,1470.0],[1416.0,1685.0],[586.0,508.0]],[[446.0,1895.0],[1332.0,681.0],[287.0,1577.0],[85.0,1818.0]],[[0.0,552.0],[1214.0,1151.0],[1244.0,244.0],[1949.0,1945.0]],[[251.0,611.0],[3.0,2036.0],[1686.0,151.0],[997.0,477.0]],[[1591.0,114.0],[1260.0,27.0],[92.0,987.0],[1577.0,1140.0]],[[1490.0,22.0],[873.0,1756.0],[874.0,1853.0],[202.0,529.0]],[[1107.0,139.0],[397.0,1623.0],[391.0,197.0],[2026.0,2006.0]],[[612.0,456.0],[2001.0,1026.0],[746.0,246.0],[443.0,1902.0]],[[293.0,750.0],[1381.0,1908.0],[643.0,1997.0],[1533.0,1053.0]],[[1218.0,1982.0],[705.0,1236.0],[119.0,722.0],[996.0,428.0]],[[1593.0,315.0],[496.0,1209.0],[404.0,1039.0],[904.0,710.0]],[[1480.0,438.0],[1841.0,407.0],[1322.0,271.0],[1828.0,1779.0]],[[357.0,458.0],[1916.0,1935.0],[1050.0,1561.0],[1905.0,1937.0]],[[1552.0,1571.0],[399.0,1540.0],[1367.0,42.0],[283.0,711.0]],[[2016.0,1763.0],[122.0,350.0],[1590.0,1352.0],[162.0,110.0]],[[3.0,1847.0],[717.0,1853.0],[1239.0,1664.0],[316.0,837.0]],[[1749.0,1303.0],[2015.0,1759.0],[1603.0,126.0],[418.0,700.0]],[[1659.0,634.0],[1043.0,881.0],[2026.0,563.0],[1407.0,422.0]],[[647.0,2018.0],[79.0,1274.0],[154.0,399.0],[1102.0,2018.0]],[[643.0,1683.0],[1029.0,1441.0],[1206.0,1326.0],[1037.0,760.0]],[[876.0,445.0],[640.0,1032.0],[495.0,828.0],[181.0,562.0]],[[1857.0,471.0],[1012.0,727.0],[1710.0,1727.0],[679.0,163.0]],[[1344.0,51.0],[1313.0,697.0],[604.0,1509.0],[1011.0,172.0]],[[1715.0,640.0],[1337.0,877.0],[997.0,1970.0],[1153.0,1105.0]],[[1975.0,916.0],[663.0,269.0],[1021.0,1862.0],[568.0,1540.0]],[[688.0,84.0],[385.0,233.0],[139.0,225.0],[2040.0,1901.0]],[[99.0,2016.0],[1074.0,1160.0],[1129.0,1561.0],[1960.0,487.0]],[[359.0,1272.0],[1545.0,1783.0],[806.0,963.0],[629.0,282.0]],[[1184.0,845.0],[414.0,1432.0],[1102.0,560.0],[905.0,1466.0]],[[1439.0,652.0],[424.0,429.0],[805.0,1243.0],[964.0,268.0]],[[168.0,1361.0],[1545.0,874.0],[1495.0,314.0],[1880.0,1915.0]],[[1359.0,1198.0],[1361.0,78.0],[352.0,527.0],[677.0,82.0]],[[108.0,1015.0],[836.0,1769.0],[1268.0,758.0],[437.0,1538.0]],[[36.0,807.0],[273.0,894.0],[654.0,1282.0],[834.0,1297.0]],[[938.0,1073.0],[1422.0,1605.0],[1300.0,200.0],[1864.0,819.0]],[[449.0,1889.0],[636.0,1596.0],[1544.0,849.0],[1285.0,1389.0]],[[975.0,2030.0],[1912.0,1633.0],[17.0,1908.0],[1440.0,1971.0]],[[1381.0,224.0],[1813.0,1607.0],[1948.0,1998.0],[1178.0,246.0]],[[1894.0,949.0],[383.0,1239.0],[667.0,1847.0],[864.0,1095.0]],[[666.0,1239.0],[1606.0,27.0],[771.0,1966.0],[56.0,1199.0]],[[1087.0,1063.0],[315.0,1598.0],[190.0,157.0],[803.0,1937.0]],[[885.0,1616.0],[1325.0,1224.0],[1994.0,1049.0],[1079.0,658.0]],[[1622.0,1655.0],[2047.0,924.0],[964.0,1665.0],[1830.0,307.0]],[[1586.0,230.0],[5.0,777.0],[1442.0,807.0],[432.0,154.0]],[[1932.0,782.0],[222.0,731.0],[1293.0,175.0],[1046.0,844.0]],[[782.0,1670.0],[265.0,735.0],[1047.0,184.0],[595.0,56.0]],[[242.0,883.0],[717.0,1342.0],[573.0,706.0],[1654.0,4.0]],[[11.0,1364.0],[109.0,881.0],[326.0,1974.0],[1900.0,303.0]],[[699.0,1105.0],[75.0,1695.0],[1193.0,820.0],[742.0,1309.0]],[[402.0,1192.0],[1242.0,820.0],[456.0,50.0],[1148.0,850.0]],[[886.0,963.0],[813.0,2041.0],[1300.0,1634.0],[1974.0,428.0]],[[1521.0,307.0],[1907.0,1033.0],[1948.0,244.0],[82.0,1361.0]],[[1959.0,43.0],[1009.0,514.0],[201.0,1616.0],[393.0,948.0]],[[216.0,1228.0],[1515.0,420.0],[394.0,1129.0],[1149.0,627.0]],[[964.0,639.0],[1955.0,228.0],[1686.0,1802.0],[123.0,50.0]],[[1356.0,1779.0],[1221.0,1998.0],[211.0,1807.0],[1303.0,1740.0]],[[104.0,690.0],[1150.0,1485.0],[985.0,277.0],[593.0,1308.0]],[[1618.0,1267.0],[1320.0,1503.0],[1998.0,577.0],[858.0,1704.0]],[[881.0,424.0],[332.0,703.0],[60.0,87.0],[339.0,1860.0]],[[300.0,760.0],[1470.0,709.0],[751.0,1706.0],[310.0,1892.0]],[[444.0,10.0],[1973.0,1494.0],[1653.0,589.0],[1490.0,569.0]],[[969.0,1595.0],[1337.0,773.0],[408.0,1264.0],[1803.0,846.0]],[[1859.0,622.0],[1049.0,219.0],[669.0,804.0],[2011.0,807.0]],[[174.0,1636.0],[1411.0,1956.0],[1701.0,906.0],[796.0,329.0]],[[63.0,637.0],[2027.0,883.0],[2035.0,1101.0],[1612.0,506.0]],[[286.0,401.0],[1420.0,690.0],[814.0,1751.0],[1268.0,1676.0]],[[1055.0,1004.0],[1544.0,1670.0],[139.0,163.0],[788.0,1524.0]],[[1661.0,1318.0],[1678.0,1132.0],[1851.0,1604.0],[719.0,527.0]],[[1762.0,1430.0],[1498.0,1528.0],[1781.0,140.0],[1507.0,506.0]],[[1368.0,219.0],[871.0,1467.0],[732.0,1173.0],[2044.0,712.0]],[[1732.0,1509.0],[1520.0,124.0],[682.0,749.0],[1470.0,1925.0]],[[1827.0,786.0],[501.0,1314.0],[67.0,1755.0],[911.0,1798.0]],[[1264.0,1721.0],[1129.0,325.0],[813.0,1854.0],[457.0,156.0]],[[19.0,918.0],[981.0,130.0],[2041.0,1358.0],[838.0,780.0]],[[455.0,116.0],[1226.0,1149.0],[387.0,546.0],[1518.0,1843.0]],[[1735.0,1348.0],[254.0,1244.0],[343.0,1899.0],[911.0,652.0]],[[859.0,1198.0],[1924.0,1174.0],[1148.0,405.0],[1039.0,660.0]],[[727.0,681.0],[1757.0,1236.0],[1626.0,1630.0],[949.0,686.0]],[[1687.0,702.0],[1352.0,999.0],[891.0,609.0],[1178.0,306.0]],[[308.0,980.0],[472.0,1248.0],[43.0,540.0],[1662.0,1620.0]],[[230.0,510.0],[215.0,539.0],[1906.0,1617.0],[1196.0,976.0]],[[651.0,1927.0],[958.0,922.0],[1029.0,1711.0],[1886.0,1152.0]],[[541.0,528.0],[132.0,535.0],[630.0,38.0],[1035.0,712.0]],[[140.0,1420.0],[1969.0,763.0],[949.0,1332.0],[755.0,864.0]],[[706.0,2019.0],[1013.0,513.0],[855.0,191.0],[1370.0,1010.0]],[[1656.0,1872.0],[1085.0,746.0],[479.0,180.0],[356.0,148.0]],[[1172.0,2040.0],[206.0,492.0],[1278.0,1519.0],[1416.0,979.0]],[[867.0,1050.0],[778.0,664.0],[1391.0,1142.0],[1323.0,1484.0]],[[151.0,319.0],[873.0,710.0],[1613.0,1875.0],[859.0,50.0]],[[1897.0,1624.0],[1548.0,1427.0],[1519.0,2017.0],[34.0,1033.0]],[[316.0,238.0],[1656.0,1666.0],[1530.0,1642.0],[757.0,1247.0]],[[800.0,367.0],[1244.0,121.0],[1739.0,158.0],[1875.0,23.0]],[[1653.0,831.0],[1949.0,1049.0],[97.0,857.0],[914.0,569.0]],[[1357.0,980.0],[1078.0,1356.0],[146.0,1577.0],[1187.0,71.0]],[[1916.0,105.0],[1741.0,64.0],[447.0,709.0],[1016.0,76.0]],[[1657.0,1822.0],[629.0,315.0],[879.0,782.0],[1707.0,1466.0]],[[1504.0,256.0],[902.0,804.0],[385.0,522.0],[1133.0,1420.0]],[[1341.0,1738.0],[1080.0,1689.0],[1455.0,933.0],[306.0,1861.0]],[[896.0,1132.0],[42.0,1304.0],[774.0,1471.0],[1246.0,1532.0]],[[807.0,1437.0],[1321.0,1097.0],[1666.0,367.0],[1544.0,780.0]],[[1838.0,806.0],[886.0,1333.0],[1962.0,1799.0],[20.0,197.0]],[[1227.0,517.0],[1594.0,290.0],[1202.0,525.0],[1321.0,1319.0]],[[1581.0,1948.0],[598.0,1052.0],[900.0,1009.0],[1544.0,1509.0]],[[204.0,1234.0],[1896.0,1409.0],[21.0,611.0],[1950.0,2040.0]],[[78.0,133.0],[1601.0,1784.0],[440.0,839.0],[1740.0,1523.0]],[[1764.0,1845.0],[1574.0,1740.0],[257.0,2044.0],[747.0,876.0]],[[761.0,408.0],[1739.0,1479.0],[900.0,736.0],[1577.0,1455.0]],[[1515.0,578.0],[652.0,956.0],[1051.0,1013.0],[292.0,324.0]],[[829.0,1789.0],[2015.0,156.0],[1316.0,901.0],[307.0,1759.0]],[[345.0,1307.0],[746.0,1956.0],[965.0,1449.0],[815.0,1160.0]],[[685.0,1855.0],[460.0,115.0],[418.0,1039.0],[1250.0,423.0]],[[1163.0,829.0],[1895.0,920.0],[116.0,1701.0],[303.0,1392.0]],[[1906.0,1850.0],[1850.0,915.0],[1771.0,1131.0],[1554.0,356.0]],[[1635.0,1624.0],[409.0,427.0],[1493.0,1446.0],[1438.0,1622.0]],[[1952.0,1994.0],[843.0,882.0],[577.0,847.0],[474.0,56.0]],[[754.0,1994.0],[1407.0,1031.0],[1273.0,366.0],[860.0,577.0]],[[1035.0,976.0],[392.0,1224.0],[1705.0,1318.0],[1460.0,635.0]],[[1880.0,932.0],[1281.0,849.0],[1346.0,525.0],[563.0,1618.0]],[[1154.0,151.0],[120.0,140.0],[1666.0,1503.0],[174.0,1889.0]],[[1866.0,1212.0],[1635.0,1655.0],[1353.0,1037.0],[1994.0,327.0]],[[82.0,612.0],[1294.0,264.0],[1474.0,223.0],[248.0,1570.0]],[[1318.0,884.0],[568.0,1755.0],[957.0,1160.0],[1395.0,19.0]],[[921.0,871.0],[1085.0,1656.0],[1231.0,1927.0],[1660.0,1997.0]],[[1909.0,1080.0],[69.0,1910.0],[1836.0,1863.0],[1744.0,892.0]],[[1499.0,1791.0],[696.0,714.0],[1872.0,1449.0],[94.0,881.0]],[[454.0,1530.0],[164.0,1837.0],[266.0,1332.0],[397.0,372.0]],[[1496.0,936.0],[371.0,1362.0],[528.0,996.0],[1439.0,960.0]],[[1095.0,1004.0],[1600.0,149.0],[59.0,1065.0],[1147.0,2041.0]],[[476.0,1992.0],[1687.0,1146.0],[396.0,252.0],[1408.0,1998.0]],[[1504.0,1082.0],[821.0,1755.0],[1567.0,695.0],[1510.0,286.0]],[[1823.0,1154.0],[1924.0,1508.0],[827.0,1351.0],[1575.0,1511.0]],[[697.0,1823.0],[1483.0,1026.0],[523.0,906.0],[653.0,1361.0]],[[9.0,508.0],[568.0,823.0],[538.0,204.0],[1564.0,575.0]],[[530.0,1391.0],[1935.0,1903.0],[393.0,64.0],[1592.0,599.0]],[[1552.0,353.0],[546.0,349.0],[1065.0,1214.0],[619.0,1367.0]],[[411.0,1814.0],[350.0,50.0],[791.0,1473.0],[1799.0,468.0]],[[773.0,70.0],[100.0,427.0],[1248.0,87.0],[1707.0,706.0]],[[1071.0,720.0],[191.0,94.0],[774.0,770.0],[708.0,495.0]],[[1472.0,197.0],[1264.0,452.0],[685.0,886.0],[0.0,206.0]],[[956.0,702.0],[1727.0,958.0],[578.0,20.0],[1913.0,2014.0]],[[129.0,604.0],[2041.0,1044.0],[1902.0,1457.0],[1385.0,1897.0]],[[1705.0,967.0],[1528.0,1908.0],[1963.0,2024.0],[26.0,768.0]],[[1361.0,784.0],[409.0,1371.0],[1909.0,184.0],[764.0,1070.0]],[[995.0,1834.0],[1771.0,524.0],[704.0,162.0],[1281.0,1979.0]],[[1220.0,1043.0],[1136.0,1543.0],[1002.0,917.0],[1406.0,1263.0]],[[1132.0,1305.0],[1559.0,1070.0],[995.0,340.0],[2031.0,678.0]],[[1526.0,652.0],[334.0,1809.0],[1953.0,1491.0],[1301.0,306.0]],[[885.0,909.0],[599.0,1454.0],[1404.0,702.0],[679.0,784.0]],[[837.0,845.0],[129.0,1698.0],[770.0,1882.0],[1680.0,1355.0]],[[118.0,1293.0],[733.0,516.0],[947.0,1713.0],[1994.0,709.0]],[[484.0,510.0],[401.0,65.0],[1908.0,730.0],[342.0,361.0]],[[572.0,52.0],[1671.0,1138.0],[780.0,1414.0],[1796.0,2002.0]],[[1898.0,2022.0],[1915.0,1071.0],[418.0,1378.0],[1394.0,260.0]],[[1870.0,1588.0],[1148.0,1615.0],[1358.0,278.0],[1238.0,560.0]],[[1063.0,81.0],[601.0,738.0],[767.0,1566.0],[511.0,1013.0]],[[1653.0,699.0],[1195.0,1417.0],[525.0,1630.0],[471.0,1557.0]],[[1484.0,935.0],[53.0,417.0],[870.0,1562.0],[320.0,119.0]],[[1503.0,1451.0],[1582.0,476.0],[567.0,678.0],[888.0,859.0]],[[1907.0,901.0],[742.0,1889.0],[1054.0,1982.0],[920.0,1603.0]],[[77.0,50.0],[507.0,711.0],[206.0,958.0],[1304.0,1292.0]],[[437.0,1710.0],[1935.0,568.0],[162.0,1116.0],[1463.0,859.0]],[[1404.0,2031.0],[560.0,1158.0],[1190.0,91.0],[1488.0,2027.0]]]
\ No newline at end of file
diff --git a/Tests/cu2qu/ufo_test.py b/Tests/cu2qu/ufo_test.py
deleted file mode 100644
index b678ae3..0000000
--- a/Tests/cu2qu/ufo_test.py
+++ /dev/null
@@ -1,285 +0,0 @@
-import os
-
-from fontTools.misc.loggingTools import CapturingLogHandler
-from fontTools.cu2qu.ufo import (
-    fonts_to_quadratic,
-    font_to_quadratic,
-    glyphs_to_quadratic,
-    glyph_to_quadratic,
-    logger,
-    CURVE_TYPE_LIB_KEY,
-)
-from fontTools.cu2qu.errors import (
-    IncompatibleSegmentNumberError,
-    IncompatibleSegmentTypesError,
-    IncompatibleFontsError,
-)
-
-import pytest
-
-
-ufoLib2 = pytest.importorskip("ufoLib2")
-
-DATADIR = os.path.join(os.path.dirname(__file__), 'data')
-
-TEST_UFOS = [
-    os.path.join(DATADIR, "RobotoSubset-Regular.ufo"),
-    os.path.join(DATADIR, "RobotoSubset-Bold.ufo"),
-]
-
-
-@pytest.fixture
-def fonts():
-    return [ufoLib2.Font.open(ufo) for ufo in TEST_UFOS]
-
-
-class FontsToQuadraticTest(object):
-
-    def test_modified(self, fonts):
-        modified = fonts_to_quadratic(fonts)
-        assert modified
-
-    def test_stats(self, fonts):
-        stats = {}
-        fonts_to_quadratic(fonts, stats=stats)
-        assert stats == {'1': 1, '2': 79, '3': 130, '4': 2}
-
-    def test_dump_stats(self, fonts):
-        with CapturingLogHandler(logger, "INFO") as captor:
-            fonts_to_quadratic(fonts, dump_stats=True)
-        assert captor.assertRegex("New spline lengths:")
-
-    def test_remember_curve_type(self, fonts):
-        fonts_to_quadratic(fonts, remember_curve_type=True)
-        assert fonts[0].lib[CURVE_TYPE_LIB_KEY] == "quadratic"
-        with CapturingLogHandler(logger, "INFO") as captor:
-            fonts_to_quadratic(fonts, remember_curve_type=True)
-        assert captor.assertRegex("already converted")
-
-    def test_no_remember_curve_type(self, fonts):
-        assert CURVE_TYPE_LIB_KEY not in fonts[0].lib
-        fonts_to_quadratic(fonts, remember_curve_type=False)
-        assert CURVE_TYPE_LIB_KEY not in fonts[0].lib
-
-    def test_different_glyphsets(self, fonts):
-        del fonts[0]['a']
-        assert 'a' not in fonts[0]
-        assert 'a' in fonts[1]
-        assert fonts_to_quadratic(fonts)
-
-    def test_max_err_em_float(self, fonts):
-        stats = {}
-        fonts_to_quadratic(fonts, max_err_em=0.002, stats=stats)
-        assert stats == {'1': 5, '2': 193, '3': 14}
-
-    def test_max_err_em_list(self, fonts):
-        stats = {}
-        fonts_to_quadratic(fonts, max_err_em=[0.002, 0.002], stats=stats)
-        assert stats == {'1': 5, '2': 193, '3': 14}
-
-    def test_max_err_float(self, fonts):
-        stats = {}
-        fonts_to_quadratic(fonts, max_err=4.096, stats=stats)
-        assert stats == {'1': 5, '2': 193, '3': 14}
-
-    def test_max_err_list(self, fonts):
-        stats = {}
-        fonts_to_quadratic(fonts, max_err=[4.096, 4.096], stats=stats)
-        assert stats == {'1': 5, '2': 193, '3': 14}
-
-    def test_both_max_err_and_max_err_em(self, fonts):
-        with pytest.raises(TypeError, match="Only one .* can be specified"):
-            fonts_to_quadratic(fonts, max_err=1.000, max_err_em=0.001)
-
-    def test_single_font(self, fonts):
-        assert font_to_quadratic(fonts[0], max_err_em=0.002,
-                                 reverse_direction=True)
-
-
-class GlyphsToQuadraticTest(object):
-
-    @pytest.mark.parametrize(
-        ["glyph", "expected"],
-        [('A', False),  # contains no curves, it is not modified
-         ('a', True)],
-        ids=['lines-only', 'has-curves']
-    )
-    def test_modified(self, fonts, glyph, expected):
-        glyphs = [f[glyph] for f in fonts]
-        assert glyphs_to_quadratic(glyphs) == expected
-
-    def test_stats(self, fonts):
-        stats = {}
-        glyphs_to_quadratic([f['a'] for f in fonts], stats=stats)
-        assert stats == {'2': 1, '3': 7, '4': 3, '5': 1}
-
-    def test_max_err_float(self, fonts):
-        glyphs = [f['a'] for f in fonts]
-        stats = {}
-        glyphs_to_quadratic(glyphs, max_err=4.096, stats=stats)
-        assert stats == {'2': 11, '3': 1}
-
-    def test_max_err_list(self, fonts):
-        glyphs = [f['a'] for f in fonts]
-        stats = {}
-        glyphs_to_quadratic(glyphs, max_err=[4.096, 4.096], stats=stats)
-        assert stats == {'2': 11, '3': 1}
-
-    def test_reverse_direction(self, fonts):
-        glyphs = [f['A'] for f in fonts]
-        assert glyphs_to_quadratic(glyphs, reverse_direction=True)
-
-    def test_single_glyph(self, fonts):
-        assert glyph_to_quadratic(fonts[0]['a'], max_err=4.096,
-                                  reverse_direction=True)
-
-    @pytest.mark.parametrize(
-        ["outlines", "exception", "message"],
-        [
-            [
-                [
-                    [
-                        ('moveTo', ((0, 0),)),
-                        ('curveTo', ((1, 1), (2, 2), (3, 3))),
-                        ('curveTo', ((4, 4), (5, 5), (6, 6))),
-                        ('closePath', ()),
-                    ],
-                    [
-                        ('moveTo', ((7, 7),)),
-                        ('curveTo', ((8, 8), (9, 9), (10, 10))),
-                        ('closePath', ()),
-                    ]
-                ],
-                IncompatibleSegmentNumberError,
-                "have different number of segments",
-            ],
-            [
-                [
-
-                    [
-                        ('moveTo', ((0, 0),)),
-                        ('curveTo', ((1, 1), (2, 2), (3, 3))),
-                        ('closePath', ()),
-                    ],
-                    [
-                        ('moveTo', ((4, 4),)),
-                        ('lineTo', ((5, 5),)),
-                        ('closePath', ()),
-                    ],
-                ],
-                IncompatibleSegmentTypesError,
-                "have incompatible segment types",
-            ],
-        ],
-        ids=[
-            "unequal-length",
-            "different-segment-types",
-        ]
-    )
-    def test_incompatible_glyphs(self, outlines, exception, message):
-        glyphs = []
-        for i, outline in enumerate(outlines):
-            glyph = ufoLib2.objects.Glyph("glyph%d" % i)
-            pen = glyph.getPen()
-            for operator, args in outline:
-                getattr(pen, operator)(*args)
-            glyphs.append(glyph)
-        with pytest.raises(exception) as excinfo:
-            glyphs_to_quadratic(glyphs)
-        assert excinfo.match(message)
-
-    def test_incompatible_fonts(self):
-        font1 = ufoLib2.Font()
-        font1.info.unitsPerEm = 1000
-        glyph1 = font1.newGlyph("a")
-        pen1 = glyph1.getPen()
-        for operator, args in [("moveTo", ((0, 0),)),
-                               ("lineTo", ((1, 1),)),
-                               ("endPath", ())]:
-            getattr(pen1, operator)(*args)
-
-        font2 = ufoLib2.Font()
-        font2.info.unitsPerEm = 1000
-        glyph2 = font2.newGlyph("a")
-        pen2 = glyph2.getPen()
-        for operator, args in [("moveTo", ((0, 0),)),
-                               ("curveTo", ((1, 1), (2, 2), (3, 3))),
-                               ("endPath", ())]:
-            getattr(pen2, operator)(*args)
-
-        with pytest.raises(IncompatibleFontsError) as excinfo:
-            fonts_to_quadratic([font1, font2])
-        assert excinfo.match("fonts contains incompatible glyphs: 'a'")
-
-        assert hasattr(excinfo.value, "glyph_errors")
-        error = excinfo.value.glyph_errors['a']
-        assert isinstance(error, IncompatibleSegmentTypesError)
-        assert error.segments == {1: ["line", "curve"]}
-
-    def test_already_quadratic(self):
-        glyph = ufoLib2.objects.Glyph()
-        pen = glyph.getPen()
-        pen.moveTo((0, 0))
-        pen.qCurveTo((1, 1), (2, 2))
-        pen.closePath()
-        assert not glyph_to_quadratic(glyph)
-
-    def test_open_paths(self):
-        glyph = ufoLib2.objects.Glyph()
-        pen = glyph.getPen()
-        pen.moveTo((0, 0))
-        pen.lineTo((1, 1))
-        pen.curveTo((2, 2), (3, 3), (4, 4))
-        pen.endPath()
-        assert glyph_to_quadratic(glyph)
-        # open contour is still open
-        assert glyph[-1][0].segmentType == "move"
-
-    def test_ignore_components(self):
-        glyph = ufoLib2.objects.Glyph()
-        pen = glyph.getPen()
-        pen.addComponent('a', (1, 0, 0, 1, 0, 0))
-        pen.moveTo((0, 0))
-        pen.curveTo((1, 1), (2, 2), (3, 3))
-        pen.closePath()
-        assert glyph_to_quadratic(glyph)
-        assert len(glyph.components) == 1
-
-    def test_overlapping_start_end_points(self):
-        # https://github.com/googlefonts/fontmake/issues/572
-        glyph1 = ufoLib2.objects.Glyph()
-        pen = glyph1.getPointPen()
-        pen.beginPath()
-        pen.addPoint((0, 651), segmentType="line")
-        pen.addPoint((0, 101), segmentType="line")
-        pen.addPoint((0, 101), segmentType="line")
-        pen.addPoint((0, 651), segmentType="line")
-        pen.endPath()
-
-        glyph2 = ufoLib2.objects.Glyph()
-        pen = glyph2.getPointPen()
-        pen.beginPath()
-        pen.addPoint((1, 651), segmentType="line")
-        pen.addPoint((2, 101), segmentType="line")
-        pen.addPoint((3, 101), segmentType="line")
-        pen.addPoint((4, 651), segmentType="line")
-        pen.endPath()
-
-        glyphs = [glyph1, glyph2]
-
-        assert glyphs_to_quadratic(glyphs, reverse_direction=True)
-
-        assert [[(p.x, p.y) for p in glyph[0]] for glyph in glyphs] == [
-            [
-                (0, 651),
-                (0, 651),
-                (0, 101),
-                (0, 101),
-            ],
-            [
-                (1, 651),
-                (4, 651),
-                (3, 101),
-                (2, 101)
-            ],
-        ]
diff --git a/Tests/designspaceLib/data/test.designspace b/Tests/designspaceLib/data/test.designspace
index e12f156..901a0ee 100644
--- a/Tests/designspaceLib/data/test.designspace
+++ b/Tests/designspaceLib/data/test.designspace
@@ -1,5 +1,5 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<designspace format="4.1">
+<designspace format="4.0">
   <axes>
     <axis tag="wght" name="weight" minimum="0" maximum="1000" default="0">
       <labelname xml:lang="en">Wéíght</labelname>
@@ -13,7 +13,7 @@
       <map input="1000" output="990"/>
     </axis>
   </axes>
-  <rules processing="last">
+  <rules>
     <rule name="named.rule.1">
       <conditionset>
         <condition name="axisName_a" minimum="0" maximum="1"/>
diff --git a/Tests/designspaceLib/designspace_test.py b/Tests/designspaceLib/designspace_test.py
index 8daf741..608ffb1 100644
--- a/Tests/designspaceLib/designspace_test.py
+++ b/Tests/designspaceLib/designspace_test.py
@@ -1,10 +1,14 @@
 # coding=utf-8
 
+from __future__ import (print_function, division, absolute_import,
+                        unicode_literals)
+
 import os
 import sys
 import pytest
 import warnings
 
+from fontTools.misc.py23 import open
 from fontTools.misc import plistlib
 from fontTools.designspaceLib import (
     DesignSpaceDocument, SourceDescriptor, AxisDescriptor, RuleDescriptor,
@@ -48,7 +52,6 @@
     instancePath1 = os.path.join(tmpdir, "instances", "instanceTest1.ufo")
     instancePath2 = os.path.join(tmpdir, "instances", "instanceTest2.ufo")
     doc = DesignSpaceDocument()
-    doc.rulesProcessingLast = True
 
     # write some axes
     a1 = AxisDescriptor()
@@ -698,7 +701,6 @@
     testDocPath = os.path.join(tmpdir, "testRules.designspace")
     testDocPath2 = os.path.join(tmpdir, "testRules_roundtrip.designspace")
     doc = DesignSpaceDocument()
-    doc.rulesProcessingLast = True
     a1 = AxisDescriptor()
     a1.minimum = 0
     a1.maximum = 1000
@@ -742,7 +744,6 @@
     _addUnwrappedCondition(testDocPath)
     doc2 = DesignSpaceDocument()
     doc2.read(testDocPath)
-    assert doc2.rulesProcessingLast
     assert len(doc2.axes) == 2
     assert len(doc2.rules) == 1
     assert len(doc2.rules[0].conditionSets) == 2
@@ -948,77 +949,3 @@
 
     with pytest.raises(DesignSpaceDocumentError, match="no 'path' attribute"):
         designspace.loadSourceFonts(lambda p: p)
-
-
-def test_addAxisDescriptor():
-    ds = DesignSpaceDocument()
-
-    axis = ds.addAxisDescriptor(
-      name="Weight", tag="wght", minimum=100, default=400, maximum=900
-    )
-
-    assert ds.axes[0] is axis
-    assert isinstance(axis, AxisDescriptor)
-    assert axis.name == "Weight"
-    assert axis.tag == "wght"
-    assert axis.minimum == 100
-    assert axis.default == 400
-    assert axis.maximum == 900
-
-
-def test_addSourceDescriptor():
-    ds = DesignSpaceDocument()
-
-    source = ds.addSourceDescriptor(name="TestSource", location={"Weight": 400})
-
-    assert ds.sources[0] is source
-    assert isinstance(source, SourceDescriptor)
-    assert source.name == "TestSource"
-    assert source.location == {"Weight": 400}
-
-
-def test_addInstanceDescriptor():
-    ds = DesignSpaceDocument()
-
-    instance = ds.addInstanceDescriptor(
-      name="TestInstance",
-      location={"Weight": 400},
-      styleName="Regular",
-      styleMapStyleName="regular",
-    )
-
-    assert ds.instances[0] is instance
-    assert isinstance(instance, InstanceDescriptor)
-    assert instance.name == "TestInstance"
-    assert instance.location == {"Weight": 400}
-    assert instance.styleName == "Regular"
-    assert instance.styleMapStyleName == "regular"
-
-
-def test_addRuleDescriptor(tmp_path):
-    ds = DesignSpaceDocument()
-
-    rule = ds.addRuleDescriptor(
-        name="TestRule",
-        conditionSets=[
-            [
-                dict(name="Weight", minimum=100, maximum=200),
-                dict(name="Weight", minimum=700, maximum=900),
-            ]
-        ],
-        subs=[("a", "a.alt")],
-    )
-
-    assert ds.rules[0] is rule
-    assert isinstance(rule, RuleDescriptor)
-    assert rule.name == "TestRule"
-    assert rule.conditionSets == [
-        [
-            dict(name="Weight", minimum=100, maximum=200),
-            dict(name="Weight", minimum=700, maximum=900),
-        ]
-    ]
-    assert rule.subs == [("a", "a.alt")]
-
-    # Test it doesn't crash.
-    ds.write(tmp_path / "test.designspace")
diff --git a/Tests/encodings/codecs_test.py b/Tests/encodings/codecs_test.py
index 9dac416..29e3a0d 100644
--- a/Tests/encodings/codecs_test.py
+++ b/Tests/encodings/codecs_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 import unittest
 import fontTools.encodings.codecs # Not to be confused with "import codecs"
 
@@ -5,19 +7,19 @@
 
 	def test_decode_mac_japanese(self):
 		self.assertEqual(b'x\xfe\xfdy'.decode("x_mac_japanese_ttx"),
-				 chr(0x78)+chr(0x2122)+chr(0x00A9)+chr(0x79))
+				 unichr(0x78)+unichr(0x2122)+unichr(0x00A9)+unichr(0x79))
 
 	def test_encode_mac_japanese(self):
 		self.assertEqual(b'x\xfe\xfdy',
-				 (chr(0x78)+chr(0x2122)+chr(0x00A9)+chr(0x79)).encode("x_mac_japanese_ttx"))
+				 (unichr(0x78)+unichr(0x2122)+unichr(0x00A9)+unichr(0x79)).encode("x_mac_japanese_ttx"))
 
 	def test_decode_mac_trad_chinese(self):
 		self.assertEqual(b'\x80'.decode("x_mac_trad_chinese_ttx"),
-				 chr(0x5C))
+				 unichr(0x5C))
 
 	def test_decode_mac_romanian(self):
 		self.assertEqual(b'x\xfb'.decode("mac_romanian"),
-				 chr(0x78)+chr(0x02DA))
+				 unichr(0x78)+unichr(0x02DA))
 
 if __name__ == '__main__':
 	import sys
diff --git a/Tests/feaLib/STAT2.fea b/Tests/feaLib/STAT2.fea
deleted file mode 100644
index 2595a9a..0000000
--- a/Tests/feaLib/STAT2.fea
+++ /dev/null
@@ -1,4 +0,0 @@
-table STAT {
-    ElidedFallbackName { name "Roman"; };
-    DesignAxis zonk 0 { name "Zonkey"; };'
-} STAT;
diff --git a/Tests/feaLib/ast_test.py b/Tests/feaLib/ast_test.py
index 4462f05..54bd5b3 100644
--- a/Tests/feaLib/ast_test.py
+++ b/Tests/feaLib/ast_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
 from fontTools.feaLib import ast
 import unittest
 
@@ -13,12 +15,6 @@
         statement = ast.ValueRecord(xPlacement=10, xAdvance=20)
         self.assertEqual(statement.asFea(), "<10 0 20 0>")
 
-    def test_non_object_location(self):
-        el = ast.Element(location=("file.fea", 1, 2))
-        self.assertEqual(el.location.file, "file.fea")
-        self.assertEqual(el.location.line, 1)
-        self.assertEqual(el.location.column, 2)
-
 
 if __name__ == "__main__":
     import sys
diff --git a/Tests/feaLib/builder_test.py b/Tests/feaLib/builder_test.py
index 0a55239..3d852af 100644
--- a/Tests/feaLib/builder_test.py
+++ b/Tests/feaLib/builder_test.py
@@ -1,3 +1,6 @@
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.loggingTools import CapturingLogHandler
 from fontTools.feaLib.builder import Builder, addOpenTypeFeatures, \
         addOpenTypeFeaturesFromString
@@ -7,9 +10,7 @@
 from fontTools.feaLib import ast
 from fontTools.feaLib.lexer import Lexer
 import difflib
-from io import StringIO
 import os
-import re
 import shutil
 import sys
 import tempfile
@@ -42,9 +43,8 @@
         a_n_d T_h T_h.swash germandbls ydieresis yacute breve
         grave acute dieresis macron circumflex cedilla umlaut ogonek caron
         damma hamza sukun kasratan lam_meem_jeem noon.final noon.initial
-        by feature lookup sub table uni0327 uni0328 e.fina
+        by feature lookup sub table
     """.split()
-    glyphs.extend("cid{:05d}".format(cid) for cid in range(800, 1001 + 1))
     font = TTFont()
     font.setGlyphOrder(glyphs)
     return font
@@ -53,7 +53,7 @@
 class BuilderTest(unittest.TestCase):
     # Feature files in data/*.fea; output gets compared to data/*.ttx.
     TEST_FEATURE_FILES = """
-        Attach cid_range enum markClass language_required
+        Attach enum markClass language_required
         GlyphClassDef LigatureCaretByIndex LigatureCaretByPos
         lookup lookupflag feature_aalt ignore_pos
         GPOS_1 GPOS_1_zero GPOS_2 GPOS_2b GPOS_3 GPOS_4 GPOS_5 GPOS_6 GPOS_8
@@ -70,11 +70,8 @@
         ZeroValue_SinglePos_horizontal ZeroValue_SinglePos_vertical
         ZeroValue_PairPos_horizontal ZeroValue_PairPos_vertical
         ZeroValue_ChainSinglePos_horizontal ZeroValue_ChainSinglePos_vertical
-        PairPosSubtable ChainSubstSubtable SubstSubtable ChainPosSubtable 
-        LigatureSubtable AlternateSubtable MultipleSubstSubtable 
-        SingleSubstSubtable aalt_chain_contextual_subst AlternateChained 
-        MultipleLookupsPerGlyph MultipleLookupsPerGlyph2 GSUB_6_formats
-        GSUB_5_formats delete_glyph STAT_test STAT_test_elidedFallbackNameID
+        PairPosSubtable ChainSubstSubtable ChainPosSubtable LigatureSubtable
+        AlternateSubtable MultipleSubstSubtable SingleSubstSubtable
     """.split()
 
     def __init__(self, methodName):
@@ -116,16 +113,12 @@
                     lines.append(line.rstrip() + os.linesep)
         return lines
 
-    def expect_ttx(self, font, expected_ttx, replace=None):
+    def expect_ttx(self, font, expected_ttx):
         path = self.temp_path(suffix=".ttx")
         font.saveXML(path, tables=['head', 'name', 'BASE', 'GDEF', 'GSUB',
-                                   'GPOS', 'OS/2', 'STAT', 'hhea', 'vhea'])
+                                   'GPOS', 'OS/2', 'hhea', 'vhea'])
         actual = self.read_ttx(path)
         expected = self.read_ttx(expected_ttx)
-        if replace:
-            for i in range(len(expected)):
-                for k, v in replace.items():
-                    expected[i] = expected[i].replace(k, v)
         if actual != expected:
             for line in difflib.unified_diff(
                     expected, actual, fromfile=expected_ttx, tofile=path):
@@ -139,22 +132,12 @@
 
     def check_feature_file(self, name):
         font = makeTTFont()
-        feapath = self.getpath("%s.fea" % name)
-        addOpenTypeFeatures(font, feapath)
+        addOpenTypeFeatures(font, self.getpath("%s.fea" % name))
         self.expect_ttx(font, self.getpath("%s.ttx" % name))
-        # Check that:
-        # 1) tables do compile (only G* tables as long as we have a mock font)
-        # 2) dumping after save-reload yields the same TTX dump as before
+        # Make sure we can produce binary OpenType tables, not just XML.
         for tag in ('GDEF', 'GSUB', 'GPOS'):
             if tag in font:
-                data = font[tag].compile(font)
-                font[tag].decompile(data, font)
-        self.expect_ttx(font, self.getpath("%s.ttx" % name))
-        # Optionally check a debug dump.
-        debugttx = self.getpath("%s-debug.ttx" % name)
-        if os.path.exists(debugttx):
-            addOpenTypeFeatures(font, feapath, debug=True)
-            self.expect_ttx(font, debugttx, replace = {"__PATH__": feapath})
+                font[tag].compile(font)
 
     def check_fea2fea_file(self, name, base=None, parser=Parser):
         font = makeTTFont()
@@ -206,17 +189,6 @@
             "    sub A from [A.alt1 A.alt2];"
             "} test;")
 
-    def test_singleSubst_multipleIdenticalSubstitutionsForSameGlyph_info(self):
-        logger = logging.getLogger("fontTools.feaLib.builder")
-        with CapturingLogHandler(logger, "INFO") as captor:
-            self.build(
-                "feature test {"
-                "    sub A by A.sc;"
-                "    sub B by B.sc;"
-                "    sub A by A.sc;"
-                "} test;")
-        captor.assertRegex('Removing duplicate single substitution from glyph "A" to "A.sc"')
-
     def test_multipleSubst_multipleSubstitutionsForSameGlyph(self):
         self.assertRaisesRegex(
             FeatureLibError,
@@ -225,23 +197,12 @@
             "feature test {"
             "    sub f_f_i by f f i;"
             "    sub c_t by c t;"
-            "    sub f_f_i by f_f i;"
+            "    sub f_f_i by f f i;"
             "} test;")
 
-    def test_multipleSubst_multipleIdenticalSubstitutionsForSameGlyph_info(self):
-        logger = logging.getLogger("fontTools.feaLib.builder")
-        with CapturingLogHandler(logger, "INFO") as captor:
-            self.build(
-                "feature test {"
-                "    sub f_f_i by f f i;"
-                "    sub c_t by c t;"
-                "    sub f_f_i by f f i;"
-                "} test;")
-        captor.assertRegex(r"Removing duplicate multiple substitution from glyph \"f_f_i\" to \('f', 'f', 'i'\)")
-
     def test_pairPos_redefinition_warning(self):
         # https://github.com/fonttools/fonttools/issues/1147
-        logger = logging.getLogger("fontTools.otlLib.builder")
+        logger = logging.getLogger("fontTools.feaLib.builder")
         with CapturingLogHandler(logger, "DEBUG") as captor:
             # the pair "yacute semicolon" is redefined in the enum pos
             font = self.build(
@@ -354,12 +315,6 @@
             "Script statements are not allowed within \"feature size\"",
             self.build, "feature size { script latn; } size;")
 
-    def test_script_in_standalone_lookup(self):
-        self.assertRaisesRegex(
-            FeatureLibError,
-            "Script statements are not allowed within standalone lookup blocks",
-            self.build, "lookup test { script latn; } test;")
-
     def test_language(self):
         builder = Builder(makeTTFont(), (None, None))
         builder.add_language_system(None, 'latn', 'FRA ')
@@ -387,12 +342,6 @@
             "Language statements are not allowed within \"feature size\"",
             self.build, "feature size { language FRA; } size;")
 
-    def test_language_in_standalone_lookup(self):
-        self.assertRaisesRegex(
-            FeatureLibError,
-            "Language statements are not allowed within standalone lookup blocks",
-            self.build, "lookup test { language FRA; } test;")
-
     def test_language_required_duplicate(self):
         self.assertRaisesRegex(
             FeatureLibError,
@@ -447,223 +396,6 @@
             "Lookup blocks cannot be placed inside 'aalt' features",
             self.build, "feature aalt {lookup L {} L;} aalt;")
 
-    def test_chain_subst_refrences_GPOS_looup(self):
-        self.assertRaisesRegex(
-            FeatureLibError,
-            "Missing index of the specified lookup, might be a positioning lookup",
-            self.build,
-            "lookup dummy { pos a 50; } dummy;"
-            "feature test {"
-            "    sub a' lookup dummy b;"
-            "} test;"
-        )
-
-    def test_chain_pos_refrences_GSUB_looup(self):
-        self.assertRaisesRegex(
-            FeatureLibError,
-            "Missing index of the specified lookup, might be a substitution lookup",
-            self.build,
-            "lookup dummy { sub a by A; } dummy;"
-            "feature test {"
-            "    pos a' lookup dummy b;"
-            "} test;"
-        )
-
-    def test_STAT_elidedfallbackname_already_defined(self):
-        self.assertRaisesRegex(
-            FeatureLibError,
-            'ElidedFallbackName is already set.',
-            self.build,
-            'table name {'
-            '   nameid 256 "Roman"; '
-            '} name;'
-            'table STAT {'
-            '    ElidedFallbackName { name "Roman"; };'
-            '    ElidedFallbackNameID 256;'
-            '} STAT;')
-
-    def test_STAT_elidedfallbackname_set_twice(self):
-        self.assertRaisesRegex(
-            FeatureLibError,
-            'ElidedFallbackName is already set.',
-            self.build,
-            'table name {'
-            '   nameid 256 "Roman"; '
-            '} name;'
-            'table STAT {'
-            '    ElidedFallbackName { name "Roman"; };'
-            '    ElidedFallbackName { name "Italic"; };'
-            '} STAT;')
-
-    def test_STAT_elidedfallbacknameID_already_defined(self):
-        self.assertRaisesRegex(
-            FeatureLibError,
-            'ElidedFallbackNameID is already set.',
-            self.build,
-            'table name {'
-            '   nameid 256 "Roman"; '
-            '} name;'
-            'table STAT {'
-            '    ElidedFallbackNameID 256;'
-            '    ElidedFallbackName { name "Roman"; };'
-            '} STAT;')
-
-    def test_STAT_elidedfallbacknameID_not_in_name_table(self):
-        self.assertRaisesRegex(
-            FeatureLibError,
-            'ElidedFallbackNameID 256 points to a nameID that does not '
-            'exist in the "name" table',
-            self.build,
-            'table name {'
-            '   nameid 257 "Roman"; '
-            '} name;'
-            'table STAT {'
-            '    ElidedFallbackNameID 256;'
-            '    DesignAxis opsz 1 { name "Optical Size"; };'
-            '} STAT;')
-
-    def test_STAT_design_axis_name(self):
-        self.assertRaisesRegex(
-            FeatureLibError,
-            'Expected "name"',
-            self.build,
-            'table name {'
-            '   nameid 256 "Roman"; '
-            '} name;'
-            'table STAT {'
-            '    ElidedFallbackName { name "Roman"; };'
-            '    DesignAxis opsz 0 { badtag "Optical Size"; };'
-            '} STAT;')
-
-    def test_STAT_duplicate_design_axis_name(self):
-        self.assertRaisesRegex(
-            FeatureLibError,
-            'DesignAxis already defined for tag "opsz".',
-            self.build,
-            'table name {'
-            '   nameid 256 "Roman"; '
-            '} name;'
-            'table STAT {'
-            '    ElidedFallbackName { name "Roman"; };'
-            '    DesignAxis opsz 0 { name "Optical Size"; };'
-            '    DesignAxis opsz 1 { name "Optical Size"; };'
-            '} STAT;')
-
-    def test_STAT_design_axis_duplicate_order(self):
-        self.assertRaisesRegex(
-            FeatureLibError,
-            "DesignAxis already defined for axis number 0.",
-            self.build,
-            'table name {'
-            '   nameid 256 "Roman"; '
-            '} name;'
-            'table STAT {'
-            '    ElidedFallbackName { name "Roman"; };'
-            '    DesignAxis opsz 0 { name "Optical Size"; };'
-            '    DesignAxis wdth 0 { name "Width"; };'
-            '    AxisValue {'
-            '         location opsz 8;'
-            '         location wdth 400;'
-            '         name "Caption";'
-            '     };'
-            '} STAT;')
-
-    def test_STAT_undefined_tag(self):
-        self.assertRaisesRegex(
-            FeatureLibError,
-            'DesignAxis not defined for wdth.',
-            self.build,
-            'table name {'
-            '   nameid 256 "Roman"; '
-            '} name;'
-            'table STAT {'
-            '    ElidedFallbackName { name "Roman"; };'
-            '    DesignAxis opsz 0 { name "Optical Size"; };'
-            '    AxisValue { '
-            '        location wdth 125; '
-            '        name "Wide"; '
-            '    };'
-            '} STAT;')
-
-    def test_STAT_axis_value_format4(self):
-        self.assertRaisesRegex(
-            FeatureLibError,
-            'Axis tag wdth already defined.',
-            self.build,
-            'table name {'
-            '   nameid 256 "Roman"; '
-            '} name;'
-            'table STAT {'
-            '    ElidedFallbackName { name "Roman"; };'
-            '    DesignAxis opsz 0 { name "Optical Size"; };'
-            '    DesignAxis wdth 1 { name "Width"; };'
-            '    DesignAxis wght 2 { name "Weight"; };'
-            '    AxisValue { '
-            '        location opsz 8; '
-            '        location wdth 125; '
-            '        location wdth 125; '
-            '        location wght 500; '
-            '        name "Caption Medium Wide"; '
-            '    };'
-            '} STAT;')
-
-    def test_STAT_duplicate_axis_value_record(self):
-        # Test for Duplicate AxisValueRecords even when the definition order
-        # is different.
-        self.assertRaisesRegex(
-            FeatureLibError,
-            'An AxisValueRecord with these values is already defined.',
-            self.build,
-            'table name {'
-            '   nameid 256 "Roman"; '
-            '} name;'
-            'table STAT {'
-            '    ElidedFallbackName { name "Roman"; };'
-            '    DesignAxis opsz 0 { name "Optical Size"; };'
-            '    DesignAxis wdth 1 { name "Width"; };'
-            '    AxisValue {'
-            '         location opsz 8;'
-            '         location wdth 400;'
-            '         name "Caption";'
-            '     };'
-            '    AxisValue {'
-            '         location wdth 400;'
-            '         location opsz 8;'
-            '         name "Caption";'
-            '     };'
-            '} STAT;')
-
-    def test_STAT_axis_value_missing_location(self):
-        self.assertRaisesRegex(
-            FeatureLibError,
-            'Expected "Axis location"',
-            self.build,
-            'table name {'
-            '   nameid 256 "Roman"; '
-            '} name;'
-            'table STAT {'
-            '    ElidedFallbackName {   name "Roman"; '
-            '};'
-            '    DesignAxis opsz 0 { name "Optical Size"; };'
-            '    AxisValue { '
-            '        name "Wide"; '
-            '    };'
-            '} STAT;')
-
-    def test_STAT_invalid_location_tag(self):
-        self.assertRaisesRegex(
-            FeatureLibError,
-            'Tags cannot be longer than 4 characters',
-            self.build,
-            'table name {'
-            '   nameid 256 "Roman"; '
-            '} name;'
-            'table STAT {'
-            '    ElidedFallbackName { name "Roman"; '
-            '                         name 3 1 0x0411 "ローマン"; }; '
-            '    DesignAxis width 0 { name "Width"; };'
-            '} STAT;')
-
     def test_extensions(self):
         class ast_BaseClass(ast.MarkClass):
             def asFea(self, indent=""):
@@ -772,17 +504,17 @@
         assert "GSUB" not in font2
 
     def test_build_unsupported_tables(self):
-        self.assertRaises(NotImplementedError, self.build, "", tables={"FOO"})
+        self.assertRaises(AssertionError, self.build, "", tables={"FOO"})
 
     def test_build_pre_parsed_ast_featurefile(self):
-        f = StringIO("feature liga {sub f i by f_i;} liga;")
+        f = UnicodeIO("feature liga {sub f i by f_i;} liga;")
         tree = Parser(f).parse()
         font = makeTTFont()
         addOpenTypeFeatures(font, tree)
         assert "GSUB" in font
 
     def test_unsupported_subtable_break(self):
-        logger = logging.getLogger("fontTools.otlLib.builder")
+        logger = logging.getLogger("fontTools.feaLib.builder")
         with CapturingLogHandler(logger, level='WARNING') as captor:
             self.build(
                 "feature test {"
@@ -809,26 +541,6 @@
         self.assertIn("GSUB", font)
         self.assertNotIn("name", font)
 
-    def test_singlePos_multiplePositionsForSameGlyph(self):
-        self.assertRaisesRegex(
-            FeatureLibError,
-            "Already defined different position for glyph",
-            self.build,
-            "lookup foo {"
-            "    pos A -45; "
-            "    pos A 45; "
-            "} foo;")
-
-    def test_pairPos_enumRuleOverridenBySinglePair_DEBUG(self):
-        logger = logging.getLogger("fontTools.otlLib.builder")
-        with CapturingLogHandler(logger, "DEBUG") as captor:
-            self.build(
-                "feature test {"
-                "    enum pos A [V Y] -80;"
-                "    pos A V -75;"
-                "} test;")
-        captor.assertRegex('Already defined position for pair A V at')
-
 
 def generate_feature_file_test(name):
     return lambda self: self.check_feature_file(name)
diff --git a/Tests/feaLib/data/AlternateChained.fea b/Tests/feaLib/data/AlternateChained.fea
deleted file mode 100644
index 4517769..0000000
--- a/Tests/feaLib/data/AlternateChained.fea
+++ /dev/null
@@ -1,3 +0,0 @@
-feature test {
-  sub A B a' [Y y] Z from [a.alt1 a.alt2 a.alt3];
-} test;
diff --git a/Tests/feaLib/data/AlternateChained.ttx b/Tests/feaLib/data/AlternateChained.ttx
deleted file mode 100644
index e02bb7d..0000000
--- a/Tests/feaLib/data/AlternateChained.ttx
+++ /dev/null
@@ -1,78 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont>
-
-  <GSUB>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=1 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="test"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="0"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=2 -->
-      <Lookup index="0">
-        <LookupType value="6"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <ChainContextSubst index="0" Format="3">
-          <!-- BacktrackGlyphCount=2 -->
-          <BacktrackCoverage index="0">
-            <Glyph value="B"/>
-          </BacktrackCoverage>
-          <BacktrackCoverage index="1">
-            <Glyph value="A"/>
-          </BacktrackCoverage>
-          <!-- InputGlyphCount=1 -->
-          <InputCoverage index="0">
-            <Glyph value="a"/>
-          </InputCoverage>
-          <!-- LookAheadGlyphCount=2 -->
-          <LookAheadCoverage index="0">
-            <Glyph value="Y"/>
-            <Glyph value="y"/>
-          </LookAheadCoverage>
-          <LookAheadCoverage index="1">
-            <Glyph value="Z"/>
-          </LookAheadCoverage>
-          <!-- SubstCount=1 -->
-          <SubstLookupRecord index="0">
-            <SequenceIndex value="0"/>
-            <LookupListIndex value="1"/>
-          </SubstLookupRecord>
-        </ChainContextSubst>
-      </Lookup>
-      <Lookup index="1">
-        <LookupType value="3"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <AlternateSubst index="0">
-          <AlternateSet glyph="a">
-            <Alternate glyph="a.alt1"/>
-            <Alternate glyph="a.alt2"/>
-            <Alternate glyph="a.alt3"/>
-          </AlternateSet>
-        </AlternateSubst>
-      </Lookup>
-    </LookupList>
-  </GSUB>
-
-</ttFont>
diff --git a/Tests/feaLib/data/ChainPosSubtable.fea b/Tests/feaLib/data/ChainPosSubtable.fea
index e64f886..4650622 100644
--- a/Tests/feaLib/data/ChainPosSubtable.fea
+++ b/Tests/feaLib/data/ChainPosSubtable.fea
@@ -1,7 +1,7 @@
 feature test {
-    pos X [A - B]' -40 B' -40 A' -40 Y;
+    pos X [A-B]' -40 B' -40 A' -40 Y;
     subtable;
     pos X A' -111 Y;
     subtable;
-    pos X B' -40 A' -111 [A - C]' -40 Y;
+    pos X B' -40 A' -111 [A-C]' -40 Y;
 } test;
diff --git a/Tests/feaLib/data/ChainPosSubtable.ttx b/Tests/feaLib/data/ChainPosSubtable.ttx
index 695dd86..a780ccb 100644
--- a/Tests/feaLib/data/ChainPosSubtable.ttx
+++ b/Tests/feaLib/data/ChainPosSubtable.ttx
@@ -67,26 +67,24 @@
             <LookupListIndex value="1"/>
           </PosLookupRecord>
         </ChainContextPos>
-        <ChainContextPos index="1" Format="1">
-          <Coverage>
+        <ChainContextPos index="1" Format="3">
+          <!-- BacktrackGlyphCount=1 -->
+          <BacktrackCoverage index="0">
+            <Glyph value="X"/>
+          </BacktrackCoverage>
+          <!-- InputGlyphCount=1 -->
+          <InputCoverage index="0">
             <Glyph value="A"/>
-          </Coverage>
-          <!-- ChainPosRuleSetCount=1 -->
-          <ChainPosRuleSet index="0">
-            <!-- ChainPosRuleCount=1 -->
-            <ChainPosRule index="0">
-              <!-- BacktrackGlyphCount=1 -->
-              <Backtrack index="0" value="X"/>
-              <!-- InputGlyphCount=1 -->
-              <!-- LookAheadGlyphCount=1 -->
-              <LookAhead index="0" value="Y"/>
-              <!-- PosCount=1 -->
-              <PosLookupRecord index="0">
-                <SequenceIndex value="0"/>
-                <LookupListIndex value="2"/>
-              </PosLookupRecord>
-            </ChainPosRule>
-          </ChainPosRuleSet>
+          </InputCoverage>
+          <!-- LookAheadGlyphCount=1 -->
+          <LookAheadCoverage index="0">
+            <Glyph value="Y"/>
+          </LookAheadCoverage>
+          <!-- PosCount=1 -->
+          <PosLookupRecord index="0">
+            <SequenceIndex value="0"/>
+            <LookupListIndex value="2"/>
+          </PosLookupRecord>
         </ChainContextPos>
         <ChainContextPos index="2" Format="3">
           <!-- BacktrackGlyphCount=1 -->
diff --git a/Tests/feaLib/data/ChainSubstSubtable.fea b/Tests/feaLib/data/ChainSubstSubtable.fea
index ec24880..b6e959a 100644
--- a/Tests/feaLib/data/ChainSubstSubtable.fea
+++ b/Tests/feaLib/data/ChainSubstSubtable.fea
@@ -1,9 +1,9 @@
 feature test {
-    sub A G' by G.swash;
+    sub G' by G.swash;
     subtable;
-    sub A H' by H.swash;
+    sub H' by H.swash;
     subtable;
-    sub A G' by g;
+    sub G' by g;
     subtable;
-    sub A H' by H.swash;
+    sub H' by H.swash;
 } test;
diff --git a/Tests/feaLib/data/ChainSubstSubtable.ttx b/Tests/feaLib/data/ChainSubstSubtable.ttx
index 75348dc..f7a09c7 100644
--- a/Tests/feaLib/data/ChainSubstSubtable.ttx
+++ b/Tests/feaLib/data/ChainSubstSubtable.ttx
@@ -34,10 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=4 -->
         <ChainContextSubst index="0" Format="3">
-          <!-- BacktrackGlyphCount=1 -->
-          <BacktrackCoverage index="0">
-            <Glyph value="A"/>
-          </BacktrackCoverage>
+          <!-- BacktrackGlyphCount=0 -->
           <!-- InputGlyphCount=1 -->
           <InputCoverage index="0">
             <Glyph value="G"/>
@@ -50,10 +47,7 @@
           </SubstLookupRecord>
         </ChainContextSubst>
         <ChainContextSubst index="1" Format="3">
-          <!-- BacktrackGlyphCount=1 -->
-          <BacktrackCoverage index="0">
-            <Glyph value="A"/>
-          </BacktrackCoverage>
+          <!-- BacktrackGlyphCount=0 -->
           <!-- InputGlyphCount=1 -->
           <InputCoverage index="0">
             <Glyph value="H"/>
@@ -66,10 +60,7 @@
           </SubstLookupRecord>
         </ChainContextSubst>
         <ChainContextSubst index="2" Format="3">
-          <!-- BacktrackGlyphCount=1 -->
-          <BacktrackCoverage index="0">
-            <Glyph value="A"/>
-          </BacktrackCoverage>
+          <!-- BacktrackGlyphCount=0 -->
           <!-- InputGlyphCount=1 -->
           <InputCoverage index="0">
             <Glyph value="G"/>
@@ -82,10 +73,7 @@
           </SubstLookupRecord>
         </ChainContextSubst>
         <ChainContextSubst index="3" Format="3">
-          <!-- BacktrackGlyphCount=1 -->
-          <BacktrackCoverage index="0">
-            <Glyph value="A"/>
-          </BacktrackCoverage>
+          <!-- BacktrackGlyphCount=0 -->
           <!-- InputGlyphCount=1 -->
           <InputCoverage index="0">
             <Glyph value="H"/>
diff --git a/Tests/feaLib/data/GPOS_2.ttx b/Tests/feaLib/data/GPOS_2.ttx
index c9a6c14..84dc819 100644
--- a/Tests/feaLib/data/GPOS_2.ttx
+++ b/Tests/feaLib/data/GPOS_2.ttx
@@ -76,7 +76,6 @@
           <!-- Class2Count=2 -->
           <Class1Record index="0">
             <Class2Record index="0">
-              <Value1 XAdvance="0"/>
             </Class2Record>
             <Class2Record index="1">
               <Value1 XAdvance="-26"/>
diff --git a/Tests/feaLib/data/GPOS_2b.ttx b/Tests/feaLib/data/GPOS_2b.ttx
index 8a892c1..40f458f 100644
--- a/Tests/feaLib/data/GPOS_2b.ttx
+++ b/Tests/feaLib/data/GPOS_2b.ttx
@@ -50,7 +50,6 @@
           <!-- Class2Count=2 -->
           <Class1Record index="0">
             <Class2Record index="0">
-              <Value1 XAdvance="0"/>
             </Class2Record>
             <Class2Record index="1">
               <Value1 XAdvance="1"/>
@@ -80,7 +79,6 @@
           <!-- Class2Count=3 -->
           <Class1Record index="0">
             <Class2Record index="0">
-              <Value1 XAdvance="0"/>
             </Class2Record>
             <Class2Record index="1">
               <Value1 XAdvance="4"/>
@@ -91,10 +89,8 @@
           </Class1Record>
           <Class1Record index="1">
             <Class2Record index="0">
-              <Value1 XAdvance="0"/>
             </Class2Record>
             <Class2Record index="1">
-              <Value1 XAdvance="0"/>
             </Class2Record>
             <Class2Record index="2">
               <Value1 XAdvance="2"/>
@@ -118,7 +114,6 @@
           <!-- Class2Count=2 -->
           <Class1Record index="0">
             <Class2Record index="0">
-              <Value1 XPlacement="0" YPlacement="0" XAdvance="0" YAdvance="0"/>
             </Class2Record>
             <Class2Record index="1">
               <Value1 XPlacement="5" YPlacement="5" XAdvance="5" YAdvance="5"/>
diff --git a/Tests/feaLib/data/GPOS_4.fea b/Tests/feaLib/data/GPOS_4.fea
index 7c90ab6..cfd2d75 100644
--- a/Tests/feaLib/data/GPOS_4.fea
+++ b/Tests/feaLib/data/GPOS_4.fea
@@ -6,11 +6,7 @@
 markClass [ogonek] <anchor 333 33> @SIDE_MARKS;
 
 feature test {
-    pos base a
-        <anchor 11 1> mark @TOP_MARKS
-        <anchor 12 -1> mark @BOTTOM_MARKS;
-    pos base [b c]
-        <anchor 22 -2> mark @BOTTOM_MARKS;
-    pos base d
-        <anchor 33 3> mark @SIDE_MARKS;
+    pos base a <anchor 11 1> mark @TOP_MARKS <anchor 12 -1> mark @BOTTOM_MARKS;
+    pos base [b c] <anchor 22 -2> mark @BOTTOM_MARKS;
+    pos base d <anchor 33 3> mark @SIDE_MARKS;
 } test;
diff --git a/Tests/feaLib/data/GPOS_5.fea b/Tests/feaLib/data/GPOS_5.fea
index a8f8536..b116539 100644
--- a/Tests/feaLib/data/GPOS_5.fea
+++ b/Tests/feaLib/data/GPOS_5.fea
@@ -5,29 +5,14 @@
 
 feature test {
 
-    pos ligature [c_t s_t]
-            <anchor 500 800> mark @TOP_MARKS
-            <anchor 500 -200> mark @BOTTOM_MARKS
-        ligComponent
-            <anchor 1500 800> mark @TOP_MARKS
-            <anchor 1500 -200> mark @BOTTOM_MARKS
-            <anchor 1550 0> mark @OGONEK;
+    pos ligature [c_t s_t] <anchor 500 800> mark @TOP_MARKS <anchor 500 -200> mark @BOTTOM_MARKS
+        ligComponent <anchor 1500 800> mark @TOP_MARKS <anchor 1500 -200> mark @BOTTOM_MARKS <anchor 1550 0> mark @OGONEK;
 
-    pos ligature f_l
-            <anchor 300 800> mark @TOP_MARKS
-            <anchor 300 -200> mark @BOTTOM_MARKS
-        ligComponent
-            <anchor 600 800> mark @TOP_MARKS
-            <anchor 600 -200> mark @BOTTOM_MARKS;
+    pos ligature f_l <anchor 300 800> mark @TOP_MARKS <anchor 300 -200> mark @BOTTOM_MARKS
+        ligComponent <anchor 600 800> mark @TOP_MARKS <anchor 600 -200> mark @BOTTOM_MARKS;
 
-    pos ligature [f_f_l]
-            <anchor 300 800> mark @TOP_MARKS
-            <anchor 300 -200> mark @BOTTOM_MARKS
-        ligComponent
-            <anchor 600 800> mark @TOP_MARKS
-            <anchor 600 -200> mark @BOTTOM_MARKS
-        ligComponent
-            <anchor 900 800> mark @TOP_MARKS
-            <anchor 900 -200> mark @BOTTOM_MARKS;
+    pos ligature [f_f_l] <anchor 300 800> mark @TOP_MARKS <anchor 300 -200> mark @BOTTOM_MARKS
+        ligComponent <anchor 600 800> mark @TOP_MARKS <anchor 600 -200> mark @BOTTOM_MARKS
+        ligComponent <anchor 900 800> mark @TOP_MARKS <anchor 900 -200> mark @BOTTOM_MARKS;
 
 } test;
diff --git a/Tests/feaLib/data/GPOS_6.fea b/Tests/feaLib/data/GPOS_6.fea
index e54ff6e..37b2936 100644
--- a/Tests/feaLib/data/GPOS_6.fea
+++ b/Tests/feaLib/data/GPOS_6.fea
@@ -5,9 +5,6 @@
 markClass [cedilla] <anchor 3 3 contourpoint 33> @BOTTOM_MARKS;
 
 feature test {
-    pos mark [acute grave macron ogonek]
-        <anchor 500 200> mark @TOP_MARKS
-        <anchor 500 -80> mark @BOTTOM_MARKS;
-    pos mark [dieresis caron]
-        <anchor 500 200> mark @TOP_MARKS;
+    pos mark [acute grave macron ogonek] <anchor 500 200> mark @TOP_MARKS <anchor 500 -80> mark @BOTTOM_MARKS;
+    pos mark [dieresis caron] <anchor 500 200> mark @TOP_MARKS;
 } test;
diff --git a/Tests/feaLib/data/GPOS_8.ttx b/Tests/feaLib/data/GPOS_8.ttx
index 4d79071..86f9756 100644
--- a/Tests/feaLib/data/GPOS_8.ttx
+++ b/Tests/feaLib/data/GPOS_8.ttx
@@ -34,40 +34,42 @@
         <LookupType value="8"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <ChainContextPos index="0" Format="1">
-          <Coverage>
+        <ChainContextPos index="0" Format="3">
+          <!-- BacktrackGlyphCount=1 -->
+          <BacktrackCoverage index="0">
+            <Glyph value="A"/>
+          </BacktrackCoverage>
+          <!-- InputGlyphCount=4 -->
+          <InputCoverage index="0">
             <Glyph value="one"/>
-          </Coverage>
-          <!-- ChainPosRuleSetCount=1 -->
-          <ChainPosRuleSet index="0">
-            <!-- ChainPosRuleCount=1 -->
-            <ChainPosRule index="0">
-              <!-- BacktrackGlyphCount=1 -->
-              <Backtrack index="0" value="A"/>
-              <!-- InputGlyphCount=4 -->
-              <Input index="0" value="two"/>
-              <Input index="1" value="one"/>
-              <Input index="2" value="two"/>
-              <!-- LookAheadGlyphCount=0 -->
-              <!-- PosCount=4 -->
-              <PosLookupRecord index="0">
-                <SequenceIndex value="0"/>
-                <LookupListIndex value="1"/>
-              </PosLookupRecord>
-              <PosLookupRecord index="1">
-                <SequenceIndex value="1"/>
-                <LookupListIndex value="1"/>
-              </PosLookupRecord>
-              <PosLookupRecord index="2">
-                <SequenceIndex value="2"/>
-                <LookupListIndex value="2"/>
-              </PosLookupRecord>
-              <PosLookupRecord index="3">
-                <SequenceIndex value="3"/>
-                <LookupListIndex value="2"/>
-              </PosLookupRecord>
-            </ChainPosRule>
-          </ChainPosRuleSet>
+          </InputCoverage>
+          <InputCoverage index="1">
+            <Glyph value="two"/>
+          </InputCoverage>
+          <InputCoverage index="2">
+            <Glyph value="one"/>
+          </InputCoverage>
+          <InputCoverage index="3">
+            <Glyph value="two"/>
+          </InputCoverage>
+          <!-- LookAheadGlyphCount=0 -->
+          <!-- PosCount=4 -->
+          <PosLookupRecord index="0">
+            <SequenceIndex value="0"/>
+            <LookupListIndex value="1"/>
+          </PosLookupRecord>
+          <PosLookupRecord index="1">
+            <SequenceIndex value="1"/>
+            <LookupListIndex value="1"/>
+          </PosLookupRecord>
+          <PosLookupRecord index="2">
+            <SequenceIndex value="2"/>
+            <LookupListIndex value="2"/>
+          </PosLookupRecord>
+          <PosLookupRecord index="3">
+            <SequenceIndex value="3"/>
+            <LookupListIndex value="2"/>
+          </PosLookupRecord>
         </ChainContextPos>
       </Lookup>
       <Lookup index="1">
diff --git a/Tests/feaLib/data/GSUB_5_formats.fea b/Tests/feaLib/data/GSUB_5_formats.fea
deleted file mode 100644
index 3acb7ed..0000000
--- a/Tests/feaLib/data/GSUB_5_formats.fea
+++ /dev/null
@@ -1,20 +0,0 @@
-lookup GSUB5f1 {
-    ignore sub three four;
-    ignore sub four five;
-} GSUB5f1;
-
-lookup GSUB5f2 {
-    ignore sub [a - z] [A - H] [I - Z];
-    ignore sub [a - z] [A - H] [I - Z];
-    ignore sub [a - z] [I - Z] [A - H];
-} GSUB5f2;
-
-lookup GSUB5f3 {
-    ignore sub e;
-} GSUB5f3;
-
-feature test {
-    lookup GSUB5f1;
-    lookup GSUB5f2;
-    lookup GSUB5f3;
-} test;
diff --git a/Tests/feaLib/data/GSUB_5_formats.ttx b/Tests/feaLib/data/GSUB_5_formats.ttx
deleted file mode 100644
index 80196aa..0000000
--- a/Tests/feaLib/data/GSUB_5_formats.ttx
+++ /dev/null
@@ -1,197 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont>
-
-  <GSUB>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=1 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="test"/>
-        <Feature>
-          <!-- LookupCount=3 -->
-          <LookupListIndex index="0" value="0"/>
-          <LookupListIndex index="1" value="1"/>
-          <LookupListIndex index="2" value="2"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=3 -->
-      <Lookup index="0">
-        <LookupType value="5"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <ContextSubst index="0" Format="1">
-          <Coverage>
-            <Glyph value="three"/>
-            <Glyph value="four"/>
-          </Coverage>
-          <!-- SubRuleSetCount=2 -->
-          <SubRuleSet index="0">
-            <!-- SubRuleCount=1 -->
-            <SubRule index="0">
-              <!-- GlyphCount=2 -->
-              <!-- SubstCount=0 -->
-              <Input index="0" value="four"/>
-            </SubRule>
-          </SubRuleSet>
-          <SubRuleSet index="1">
-            <!-- SubRuleCount=1 -->
-            <SubRule index="0">
-              <!-- GlyphCount=2 -->
-              <!-- SubstCount=0 -->
-              <Input index="0" value="five"/>
-            </SubRule>
-          </SubRuleSet>
-        </ContextSubst>
-      </Lookup>
-      <Lookup index="1">
-        <LookupType value="5"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <ContextSubst index="0" Format="2">
-          <Coverage>
-            <Glyph value="a"/>
-            <Glyph value="b"/>
-            <Glyph value="c"/>
-            <Glyph value="d"/>
-            <Glyph value="e"/>
-            <Glyph value="f"/>
-            <Glyph value="g"/>
-            <Glyph value="h"/>
-            <Glyph value="i"/>
-            <Glyph value="j"/>
-            <Glyph value="k"/>
-            <Glyph value="l"/>
-            <Glyph value="m"/>
-            <Glyph value="n"/>
-            <Glyph value="o"/>
-            <Glyph value="p"/>
-            <Glyph value="q"/>
-            <Glyph value="r"/>
-            <Glyph value="s"/>
-            <Glyph value="t"/>
-            <Glyph value="u"/>
-            <Glyph value="v"/>
-            <Glyph value="w"/>
-            <Glyph value="x"/>
-            <Glyph value="y"/>
-            <Glyph value="z"/>
-          </Coverage>
-          <ClassDef>
-            <ClassDef glyph="A" class="3"/>
-            <ClassDef glyph="B" class="3"/>
-            <ClassDef glyph="C" class="3"/>
-            <ClassDef glyph="D" class="3"/>
-            <ClassDef glyph="E" class="3"/>
-            <ClassDef glyph="F" class="3"/>
-            <ClassDef glyph="G" class="3"/>
-            <ClassDef glyph="H" class="3"/>
-            <ClassDef glyph="I" class="2"/>
-            <ClassDef glyph="J" class="2"/>
-            <ClassDef glyph="K" class="2"/>
-            <ClassDef glyph="L" class="2"/>
-            <ClassDef glyph="M" class="2"/>
-            <ClassDef glyph="N" class="2"/>
-            <ClassDef glyph="O" class="2"/>
-            <ClassDef glyph="P" class="2"/>
-            <ClassDef glyph="Q" class="2"/>
-            <ClassDef glyph="R" class="2"/>
-            <ClassDef glyph="S" class="2"/>
-            <ClassDef glyph="T" class="2"/>
-            <ClassDef glyph="U" class="2"/>
-            <ClassDef glyph="V" class="2"/>
-            <ClassDef glyph="W" class="2"/>
-            <ClassDef glyph="X" class="2"/>
-            <ClassDef glyph="Y" class="2"/>
-            <ClassDef glyph="Z" class="2"/>
-            <ClassDef glyph="a" class="1"/>
-            <ClassDef glyph="b" class="1"/>
-            <ClassDef glyph="c" class="1"/>
-            <ClassDef glyph="d" class="1"/>
-            <ClassDef glyph="e" class="1"/>
-            <ClassDef glyph="f" class="1"/>
-            <ClassDef glyph="g" class="1"/>
-            <ClassDef glyph="h" class="1"/>
-            <ClassDef glyph="i" class="1"/>
-            <ClassDef glyph="j" class="1"/>
-            <ClassDef glyph="k" class="1"/>
-            <ClassDef glyph="l" class="1"/>
-            <ClassDef glyph="m" class="1"/>
-            <ClassDef glyph="n" class="1"/>
-            <ClassDef glyph="o" class="1"/>
-            <ClassDef glyph="p" class="1"/>
-            <ClassDef glyph="q" class="1"/>
-            <ClassDef glyph="r" class="1"/>
-            <ClassDef glyph="s" class="1"/>
-            <ClassDef glyph="t" class="1"/>
-            <ClassDef glyph="u" class="1"/>
-            <ClassDef glyph="v" class="1"/>
-            <ClassDef glyph="w" class="1"/>
-            <ClassDef glyph="x" class="1"/>
-            <ClassDef glyph="y" class="1"/>
-            <ClassDef glyph="z" class="1"/>
-          </ClassDef>
-          <!-- SubClassSetCount=4 -->
-          <SubClassSet index="0">
-            <!-- SubClassRuleCount=0 -->
-          </SubClassSet>
-          <SubClassSet index="1">
-            <!-- SubClassRuleCount=3 -->
-            <SubClassRule index="0">
-              <!-- GlyphCount=3 -->
-              <!-- SubstCount=0 -->
-              <Class index="0" value="3"/>
-              <Class index="1" value="2"/>
-            </SubClassRule>
-            <SubClassRule index="1">
-              <!-- GlyphCount=3 -->
-              <!-- SubstCount=0 -->
-              <Class index="0" value="3"/>
-              <Class index="1" value="2"/>
-            </SubClassRule>
-            <SubClassRule index="2">
-              <!-- GlyphCount=3 -->
-              <!-- SubstCount=0 -->
-              <Class index="0" value="2"/>
-              <Class index="1" value="3"/>
-            </SubClassRule>
-          </SubClassSet>
-          <SubClassSet index="2">
-            <!-- SubClassRuleCount=0 -->
-          </SubClassSet>
-          <SubClassSet index="3">
-            <!-- SubClassRuleCount=0 -->
-          </SubClassSet>
-        </ContextSubst>
-      </Lookup>
-      <Lookup index="2">
-        <LookupType value="5"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <ContextSubst index="0" Format="3">
-          <!-- GlyphCount=1 -->
-          <!-- SubstCount=0 -->
-          <Coverage index="0">
-            <Glyph value="e"/>
-          </Coverage>
-        </ContextSubst>
-      </Lookup>
-    </LookupList>
-  </GSUB>
-
-</ttFont>
diff --git a/Tests/feaLib/data/GSUB_6.fea b/Tests/feaLib/data/GSUB_6.fea
index 2230670..82fdac2 100644
--- a/Tests/feaLib/data/GSUB_6.fea
+++ b/Tests/feaLib/data/GSUB_6.fea
@@ -1,10 +1,10 @@
 lookup ChainedSingleSubst {
     sub [one two] three A' by A.sc;
-    sub [B - D]' seven [eight nine] by [B.sc - D.sc];
+    sub [B-D]' seven [eight nine] by [B.sc-D.sc];
 } ChainedSingleSubst;
 
 lookup ChainedMultipleSubst {
-    sub [A - C a - c] [D d] E c_t' V [W w] [X - Z x - z] by c t;
+    sub [A-C a-c] [D d] E c_t' V [W w] [X-Z x-z] by c t;
 } ChainedMultipleSubst;
 
 lookup ChainedAlternateSubst {
diff --git a/Tests/feaLib/data/GSUB_6.ttx b/Tests/feaLib/data/GSUB_6.ttx
index 18405d2..f32e47d 100644
--- a/Tests/feaLib/data/GSUB_6.ttx
+++ b/Tests/feaLib/data/GSUB_6.ttx
@@ -229,30 +229,36 @@
         <LookupType value="6"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <ChainContextSubst index="0" Format="1">
-          <Coverage>
+        <ChainContextSubst index="0" Format="3">
+          <!-- BacktrackGlyphCount=3 -->
+          <BacktrackCoverage index="0">
+            <Glyph value="E"/>
+          </BacktrackCoverage>
+          <BacktrackCoverage index="1">
+            <Glyph value="D"/>
+          </BacktrackCoverage>
+          <BacktrackCoverage index="2">
+            <Glyph value="A"/>
+          </BacktrackCoverage>
+          <!-- InputGlyphCount=1 -->
+          <InputCoverage index="0">
             <Glyph value="c_t"/>
-          </Coverage>
-          <!-- ChainSubRuleSetCount=1 -->
-          <ChainSubRuleSet index="0">
-            <!-- ChainSubRuleCount=1 -->
-            <ChainSubRule index="0">
-              <!-- BacktrackGlyphCount=3 -->
-              <Backtrack index="0" value="E"/>
-              <Backtrack index="1" value="D"/>
-              <Backtrack index="2" value="A"/>
-              <!-- InputGlyphCount=1 -->
-              <!-- LookAheadGlyphCount=3 -->
-              <LookAhead index="0" value="V"/>
-              <LookAhead index="1" value="W"/>
-              <LookAhead index="2" value="X"/>
-              <!-- SubstCount=1 -->
-              <SubstLookupRecord index="0">
-                <SequenceIndex value="0"/>
-                <LookupListIndex value="2"/>
-              </SubstLookupRecord>
-            </ChainSubRule>
-          </ChainSubRuleSet>
+          </InputCoverage>
+          <!-- LookAheadGlyphCount=3 -->
+          <LookAheadCoverage index="0">
+            <Glyph value="V"/>
+          </LookAheadCoverage>
+          <LookAheadCoverage index="1">
+            <Glyph value="W"/>
+          </LookAheadCoverage>
+          <LookAheadCoverage index="2">
+            <Glyph value="X"/>
+          </LookAheadCoverage>
+          <!-- SubstCount=1 -->
+          <SubstLookupRecord index="0">
+            <SequenceIndex value="0"/>
+            <LookupListIndex value="2"/>
+          </SubstLookupRecord>
         </ChainContextSubst>
       </Lookup>
     </LookupList>
diff --git a/Tests/feaLib/data/GSUB_6_formats.fea b/Tests/feaLib/data/GSUB_6_formats.fea
deleted file mode 100644
index 44135d2..0000000
--- a/Tests/feaLib/data/GSUB_6_formats.fea
+++ /dev/null
@@ -1,20 +0,0 @@
-lookup GSUB6f1 {
-    ignore sub one two three' four' five six seven;
-    ignore sub two one three' four' six five seven;
-} GSUB6f1;
-
-lookup GSUB6f2 {
-    ignore sub [A - H] [I - Z] [a - z]' [A - H]' [I - Z]';
-    ignore sub [I - Z] [A - H] [a - z]' [A - H]' [I - Z]';
-    ignore sub [A - H] [I - Z] [a - z]' [I - Z]' [A - H]';
-} GSUB6f2;
-
-lookup GSUB6f3 {
-    ignore sub [space comma semicolon] e';
-} GSUB6f3;
-
-feature test {
-    lookup GSUB6f1;
-    lookup GSUB6f2;
-    lookup GSUB6f3;
-} test;
diff --git a/Tests/feaLib/data/GSUB_6_formats.ttx b/Tests/feaLib/data/GSUB_6_formats.ttx
deleted file mode 100644
index ad2a1c5..0000000
--- a/Tests/feaLib/data/GSUB_6_formats.ttx
+++ /dev/null
@@ -1,256 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont>
-
-  <GSUB>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=1 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="test"/>
-        <Feature>
-          <!-- LookupCount=3 -->
-          <LookupListIndex index="0" value="0"/>
-          <LookupListIndex index="1" value="1"/>
-          <LookupListIndex index="2" value="2"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=3 -->
-      <Lookup index="0">
-        <LookupType value="6"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <ChainContextSubst index="0" Format="1">
-          <Coverage>
-            <Glyph value="three"/>
-          </Coverage>
-          <!-- ChainSubRuleSetCount=1 -->
-          <ChainSubRuleSet index="0">
-            <!-- ChainSubRuleCount=2 -->
-            <ChainSubRule index="0">
-              <!-- BacktrackGlyphCount=2 -->
-              <Backtrack index="0" value="two"/>
-              <Backtrack index="1" value="one"/>
-              <!-- InputGlyphCount=2 -->
-              <Input index="0" value="four"/>
-              <!-- LookAheadGlyphCount=3 -->
-              <LookAhead index="0" value="five"/>
-              <LookAhead index="1" value="six"/>
-              <LookAhead index="2" value="seven"/>
-              <!-- SubstCount=0 -->
-            </ChainSubRule>
-            <ChainSubRule index="1">
-              <!-- BacktrackGlyphCount=2 -->
-              <Backtrack index="0" value="one"/>
-              <Backtrack index="1" value="two"/>
-              <!-- InputGlyphCount=2 -->
-              <Input index="0" value="four"/>
-              <!-- LookAheadGlyphCount=3 -->
-              <LookAhead index="0" value="six"/>
-              <LookAhead index="1" value="five"/>
-              <LookAhead index="2" value="seven"/>
-              <!-- SubstCount=0 -->
-            </ChainSubRule>
-          </ChainSubRuleSet>
-        </ChainContextSubst>
-      </Lookup>
-      <Lookup index="1">
-        <LookupType value="6"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <ChainContextSubst index="0" Format="2">
-          <Coverage>
-            <Glyph value="a"/>
-            <Glyph value="b"/>
-            <Glyph value="c"/>
-            <Glyph value="d"/>
-            <Glyph value="e"/>
-            <Glyph value="f"/>
-            <Glyph value="g"/>
-            <Glyph value="h"/>
-            <Glyph value="i"/>
-            <Glyph value="j"/>
-            <Glyph value="k"/>
-            <Glyph value="l"/>
-            <Glyph value="m"/>
-            <Glyph value="n"/>
-            <Glyph value="o"/>
-            <Glyph value="p"/>
-            <Glyph value="q"/>
-            <Glyph value="r"/>
-            <Glyph value="s"/>
-            <Glyph value="t"/>
-            <Glyph value="u"/>
-            <Glyph value="v"/>
-            <Glyph value="w"/>
-            <Glyph value="x"/>
-            <Glyph value="y"/>
-            <Glyph value="z"/>
-          </Coverage>
-          <BacktrackClassDef>
-            <ClassDef glyph="A" class="2"/>
-            <ClassDef glyph="B" class="2"/>
-            <ClassDef glyph="C" class="2"/>
-            <ClassDef glyph="D" class="2"/>
-            <ClassDef glyph="E" class="2"/>
-            <ClassDef glyph="F" class="2"/>
-            <ClassDef glyph="G" class="2"/>
-            <ClassDef glyph="H" class="2"/>
-            <ClassDef glyph="I" class="1"/>
-            <ClassDef glyph="J" class="1"/>
-            <ClassDef glyph="K" class="1"/>
-            <ClassDef glyph="L" class="1"/>
-            <ClassDef glyph="M" class="1"/>
-            <ClassDef glyph="N" class="1"/>
-            <ClassDef glyph="O" class="1"/>
-            <ClassDef glyph="P" class="1"/>
-            <ClassDef glyph="Q" class="1"/>
-            <ClassDef glyph="R" class="1"/>
-            <ClassDef glyph="S" class="1"/>
-            <ClassDef glyph="T" class="1"/>
-            <ClassDef glyph="U" class="1"/>
-            <ClassDef glyph="V" class="1"/>
-            <ClassDef glyph="W" class="1"/>
-            <ClassDef glyph="X" class="1"/>
-            <ClassDef glyph="Y" class="1"/>
-            <ClassDef glyph="Z" class="1"/>
-          </BacktrackClassDef>
-          <InputClassDef>
-            <ClassDef glyph="A" class="3"/>
-            <ClassDef glyph="B" class="3"/>
-            <ClassDef glyph="C" class="3"/>
-            <ClassDef glyph="D" class="3"/>
-            <ClassDef glyph="E" class="3"/>
-            <ClassDef glyph="F" class="3"/>
-            <ClassDef glyph="G" class="3"/>
-            <ClassDef glyph="H" class="3"/>
-            <ClassDef glyph="I" class="2"/>
-            <ClassDef glyph="J" class="2"/>
-            <ClassDef glyph="K" class="2"/>
-            <ClassDef glyph="L" class="2"/>
-            <ClassDef glyph="M" class="2"/>
-            <ClassDef glyph="N" class="2"/>
-            <ClassDef glyph="O" class="2"/>
-            <ClassDef glyph="P" class="2"/>
-            <ClassDef glyph="Q" class="2"/>
-            <ClassDef glyph="R" class="2"/>
-            <ClassDef glyph="S" class="2"/>
-            <ClassDef glyph="T" class="2"/>
-            <ClassDef glyph="U" class="2"/>
-            <ClassDef glyph="V" class="2"/>
-            <ClassDef glyph="W" class="2"/>
-            <ClassDef glyph="X" class="2"/>
-            <ClassDef glyph="Y" class="2"/>
-            <ClassDef glyph="Z" class="2"/>
-            <ClassDef glyph="a" class="1"/>
-            <ClassDef glyph="b" class="1"/>
-            <ClassDef glyph="c" class="1"/>
-            <ClassDef glyph="d" class="1"/>
-            <ClassDef glyph="e" class="1"/>
-            <ClassDef glyph="f" class="1"/>
-            <ClassDef glyph="g" class="1"/>
-            <ClassDef glyph="h" class="1"/>
-            <ClassDef glyph="i" class="1"/>
-            <ClassDef glyph="j" class="1"/>
-            <ClassDef glyph="k" class="1"/>
-            <ClassDef glyph="l" class="1"/>
-            <ClassDef glyph="m" class="1"/>
-            <ClassDef glyph="n" class="1"/>
-            <ClassDef glyph="o" class="1"/>
-            <ClassDef glyph="p" class="1"/>
-            <ClassDef glyph="q" class="1"/>
-            <ClassDef glyph="r" class="1"/>
-            <ClassDef glyph="s" class="1"/>
-            <ClassDef glyph="t" class="1"/>
-            <ClassDef glyph="u" class="1"/>
-            <ClassDef glyph="v" class="1"/>
-            <ClassDef glyph="w" class="1"/>
-            <ClassDef glyph="x" class="1"/>
-            <ClassDef glyph="y" class="1"/>
-            <ClassDef glyph="z" class="1"/>
-          </InputClassDef>
-          <LookAheadClassDef>
-          </LookAheadClassDef>
-          <!-- ChainSubClassSetCount=4 -->
-          <ChainSubClassSet index="0">
-            <!-- ChainSubClassRuleCount=0 -->
-          </ChainSubClassSet>
-          <ChainSubClassSet index="1">
-            <!-- ChainSubClassRuleCount=3 -->
-            <ChainSubClassRule index="0">
-              <!-- BacktrackGlyphCount=2 -->
-              <Backtrack index="0" value="1"/>
-              <Backtrack index="1" value="2"/>
-              <!-- InputGlyphCount=3 -->
-              <Input index="0" value="3"/>
-              <Input index="1" value="2"/>
-              <!-- LookAheadGlyphCount=0 -->
-              <!-- SubstCount=0 -->
-            </ChainSubClassRule>
-            <ChainSubClassRule index="1">
-              <!-- BacktrackGlyphCount=2 -->
-              <Backtrack index="0" value="2"/>
-              <Backtrack index="1" value="1"/>
-              <!-- InputGlyphCount=3 -->
-              <Input index="0" value="3"/>
-              <Input index="1" value="2"/>
-              <!-- LookAheadGlyphCount=0 -->
-              <!-- SubstCount=0 -->
-            </ChainSubClassRule>
-            <ChainSubClassRule index="2">
-              <!-- BacktrackGlyphCount=2 -->
-              <Backtrack index="0" value="1"/>
-              <Backtrack index="1" value="2"/>
-              <!-- InputGlyphCount=3 -->
-              <Input index="0" value="2"/>
-              <Input index="1" value="3"/>
-              <!-- LookAheadGlyphCount=0 -->
-              <!-- SubstCount=0 -->
-            </ChainSubClassRule>
-          </ChainSubClassSet>
-          <ChainSubClassSet index="2">
-            <!-- ChainSubClassRuleCount=0 -->
-          </ChainSubClassSet>
-          <ChainSubClassSet index="3">
-            <!-- ChainSubClassRuleCount=0 -->
-          </ChainSubClassSet>
-        </ChainContextSubst>
-      </Lookup>
-      <Lookup index="2">
-        <LookupType value="6"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <ChainContextSubst index="0" Format="3">
-          <!-- BacktrackGlyphCount=1 -->
-          <BacktrackCoverage index="0">
-            <Glyph value="space"/>
-            <Glyph value="semicolon"/>
-            <Glyph value="comma"/>
-          </BacktrackCoverage>
-          <!-- InputGlyphCount=1 -->
-          <InputCoverage index="0">
-            <Glyph value="e"/>
-          </InputCoverage>
-          <!-- LookAheadGlyphCount=0 -->
-          <!-- SubstCount=0 -->
-        </ChainContextSubst>
-      </Lookup>
-    </LookupList>
-  </GSUB>
-
-</ttFont>
diff --git a/Tests/feaLib/data/GSUB_8.fea b/Tests/feaLib/data/GSUB_8.fea
index 8f41749..62c7bee 100644
--- a/Tests/feaLib/data/GSUB_8.fea
+++ b/Tests/feaLib/data/GSUB_8.fea
@@ -2,7 +2,7 @@
 
 feature test {
     rsub [a A] [b B] [c C] q' [d D] [e E] [f F] by Q;
-    rsub [a A] [b B] [c C] [s - z]' [d D] [e E] [f F] by [S - Z];
+    rsub [a A] [b B] [c C] [s-z]' [d D] [e E] [f F] by [S-Z];
 
     # Having no context for a reverse chaining substitution rule
     # is a little degenerate (we define a chain without linking it
diff --git a/Tests/feaLib/data/GSUB_error.fea b/Tests/feaLib/data/GSUB_error.fea
deleted file mode 100644
index ae175c5..0000000
--- a/Tests/feaLib/data/GSUB_error.fea
+++ /dev/null
@@ -1,13 +0,0 @@
-# Trigger a parser error in the function parse_substitute_ in order to improve the error message.
-# Note that this is not a valid substitution, this test is made to trigger an error.
-
-languagesystem latn dflt;
-
-@base = [a e];
-@accents = [acute grave];
-
-feature abvs {
-    lookup lookup1 {
-        sub @base @accents by @base;
-    } lookup1;
-} abvs;
diff --git a/Tests/feaLib/data/LigatureCaretByIndex.fea b/Tests/feaLib/data/LigatureCaretByIndex.fea
index 5f74fc6..1968172 100644
--- a/Tests/feaLib/data/LigatureCaretByIndex.fea
+++ b/Tests/feaLib/data/LigatureCaretByIndex.fea
@@ -1,6 +1,10 @@
 table GDEF {
     LigatureCaretByIndex [c_t s_t] 11;
 
+    # The OpenType Feature File specification does not define what should
+    # happen when there are multiple LigatureCaretByIndex statements for
+    # the same glyph. Our behavior matches that of Adobe makeotf v2.0.90.
+    # https://github.com/adobe-type-tools/afdko/issues/95
     LigatureCaretByIndex o_f_f_i 66 33;
     LigatureCaretByIndex o_f_f_i 55;
 } GDEF;
diff --git a/Tests/feaLib/data/LigatureCaretByIndex.ttx b/Tests/feaLib/data/LigatureCaretByIndex.ttx
index f3a378c..a758077 100644
--- a/Tests/feaLib/data/LigatureCaretByIndex.ttx
+++ b/Tests/feaLib/data/LigatureCaretByIndex.ttx
@@ -17,11 +17,14 @@
         </CaretValue>
       </LigGlyph>
       <LigGlyph index="1">
-        <!-- CaretCount=2 -->
+        <!-- CaretCount=3 -->
         <CaretValue index="0" Format="2">
           <CaretValuePoint value="33"/>
         </CaretValue>
         <CaretValue index="1" Format="2">
+          <CaretValuePoint value="55"/>
+        </CaretValue>
+        <CaretValue index="2" Format="2">
           <CaretValuePoint value="66"/>
         </CaretValue>
       </LigGlyph>
diff --git a/Tests/feaLib/data/LigatureCaretByPos.fea b/Tests/feaLib/data/LigatureCaretByPos.fea
index e799c3c..a8ccf6f 100644
--- a/Tests/feaLib/data/LigatureCaretByPos.fea
+++ b/Tests/feaLib/data/LigatureCaretByPos.fea
@@ -1,6 +1,10 @@
 table GDEF {
     LigatureCaretByPos [c_h c_k] 500;
 
+    # The OpenType Feature File specification does not define what should
+    # happen when there are multiple LigatureCaretByPos statements for
+    # the same glyph. Our behavior matches that of Adobe makeotf v2.0.90.
+    # https://github.com/adobe-type-tools/afdko/issues/95
     LigatureCaretByPos o_f_f_i 700 300;
     LigatureCaretByPos o_f_f_i 900;
 } GDEF;
diff --git a/Tests/feaLib/data/LigatureCaretByPos.ttx b/Tests/feaLib/data/LigatureCaretByPos.ttx
index 8c0bf8c..911db6b 100644
--- a/Tests/feaLib/data/LigatureCaretByPos.ttx
+++ b/Tests/feaLib/data/LigatureCaretByPos.ttx
@@ -23,13 +23,16 @@
         </CaretValue>
       </LigGlyph>
       <LigGlyph index="2">
-        <!-- CaretCount=2 -->
+        <!-- CaretCount=3 -->
         <CaretValue index="0" Format="1">
           <Coordinate value="300"/>
         </CaretValue>
         <CaretValue index="1" Format="1">
           <Coordinate value="700"/>
         </CaretValue>
+        <CaretValue index="2" Format="1">
+          <Coordinate value="900"/>
+        </CaretValue>
       </LigGlyph>
     </LigCaretList>
   </GDEF>
diff --git a/Tests/feaLib/data/MultipleLookupsPerGlyph.fea b/Tests/feaLib/data/MultipleLookupsPerGlyph.fea
deleted file mode 100644
index e0c2222..0000000
--- a/Tests/feaLib/data/MultipleLookupsPerGlyph.fea
+++ /dev/null
@@ -1,11 +0,0 @@
-lookup a_to_bc {
-	sub a by b c;
-} a_to_bc;
-
-lookup b_to_d {
-	sub b by d;
-} b_to_d;
-
-feature test {
-	sub a' lookup a_to_bc lookup b_to_d b;
-} test;
\ No newline at end of file
diff --git a/Tests/feaLib/data/MultipleLookupsPerGlyph.ttx b/Tests/feaLib/data/MultipleLookupsPerGlyph.ttx
deleted file mode 100644
index 927694c..0000000
--- a/Tests/feaLib/data/MultipleLookupsPerGlyph.ttx
+++ /dev/null
@@ -1,76 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont>
-
-  <GSUB>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=1 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="test"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="2"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=3 -->
-      <Lookup index="0">
-        <LookupType value="2"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
-          <Substitution in="a" out="b,c"/>
-        </MultipleSubst>
-      </Lookup>
-      <Lookup index="1">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="b" out="d"/>
-        </SingleSubst>
-      </Lookup>
-      <Lookup index="2">
-        <LookupType value="6"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <ChainContextSubst index="0" Format="3">
-          <!-- BacktrackGlyphCount=0 -->
-          <!-- InputGlyphCount=1 -->
-          <InputCoverage index="0">
-            <Glyph value="a"/>
-          </InputCoverage>
-          <!-- LookAheadGlyphCount=1 -->
-          <LookAheadCoverage index="0">
-            <Glyph value="b"/>
-          </LookAheadCoverage>
-          <!-- SubstCount=2 -->
-          <SubstLookupRecord index="0">
-            <SequenceIndex value="0"/>
-            <LookupListIndex value="0"/>
-          </SubstLookupRecord>
-          <SubstLookupRecord index="1">
-            <SequenceIndex value="0"/>
-            <LookupListIndex value="1"/>
-          </SubstLookupRecord>
-        </ChainContextSubst>
-      </Lookup>
-    </LookupList>
-  </GSUB>
-
-</ttFont>
diff --git a/Tests/feaLib/data/MultipleLookupsPerGlyph2.fea b/Tests/feaLib/data/MultipleLookupsPerGlyph2.fea
deleted file mode 100644
index 5a9d19b..0000000
--- a/Tests/feaLib/data/MultipleLookupsPerGlyph2.fea
+++ /dev/null
@@ -1,11 +0,0 @@
-lookup a_reduce_sb {
-       pos a <-80 0 -160 0>;
-} a_reduce_sb;
-
-lookup a_raise {
-       pos a <0 100 0 0>;
-} a_raise;
-
-feature test {
-       pos a' lookup a_reduce_sb lookup a_raise b;
-} test;
\ No newline at end of file
diff --git a/Tests/feaLib/data/MultipleLookupsPerGlyph2.ttx b/Tests/feaLib/data/MultipleLookupsPerGlyph2.ttx
deleted file mode 100644
index 008d95b..0000000
--- a/Tests/feaLib/data/MultipleLookupsPerGlyph2.ttx
+++ /dev/null
@@ -1,84 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont>
-
-  <GPOS>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=1 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="test"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="2"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=3 -->
-      <Lookup index="0">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SinglePos index="0" Format="1">
-          <Coverage>
-            <Glyph value="a"/>
-          </Coverage>
-          <ValueFormat value="5"/>
-          <Value XPlacement="-80" XAdvance="-160"/>
-        </SinglePos>
-      </Lookup>
-      <Lookup index="1">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SinglePos index="0" Format="1">
-          <Coverage>
-            <Glyph value="a"/>
-          </Coverage>
-          <ValueFormat value="2"/>
-          <Value YPlacement="100"/>
-        </SinglePos>
-      </Lookup>
-      <Lookup index="2">
-        <LookupType value="8"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <ChainContextPos index="0" Format="3">
-          <!-- BacktrackGlyphCount=0 -->
-          <!-- InputGlyphCount=1 -->
-          <InputCoverage index="0">
-            <Glyph value="a"/>
-          </InputCoverage>
-          <!-- LookAheadGlyphCount=1 -->
-          <LookAheadCoverage index="0">
-            <Glyph value="b"/>
-          </LookAheadCoverage>
-          <!-- PosCount=2 -->
-          <PosLookupRecord index="0">
-            <SequenceIndex value="0"/>
-            <LookupListIndex value="0"/>
-          </PosLookupRecord>
-          <PosLookupRecord index="1">
-            <SequenceIndex value="0"/>
-            <LookupListIndex value="1"/>
-          </PosLookupRecord>
-        </ChainContextPos>
-      </Lookup>
-    </LookupList>
-  </GPOS>
-
-</ttFont>
diff --git a/Tests/feaLib/data/PairPosSubtable.ttx b/Tests/feaLib/data/PairPosSubtable.ttx
index 2d78f64..4b76f99 100644
--- a/Tests/feaLib/data/PairPosSubtable.ttx
+++ b/Tests/feaLib/data/PairPosSubtable.ttx
@@ -76,7 +76,6 @@
           <!-- Class2Count=2 -->
           <Class1Record index="0">
             <Class2Record index="0">
-              <Value1 XAdvance="0"/>
             </Class2Record>
             <Class2Record index="1">
               <Value1 XAdvance="-12"/>
@@ -106,10 +105,8 @@
           <!-- Class2Count=3 -->
           <Class1Record index="0">
             <Class2Record index="0">
-              <Value1 XAdvance="0"/>
             </Class2Record>
             <Class2Record index="1">
-              <Value1 XAdvance="0"/>
             </Class2Record>
             <Class2Record index="2">
               <Value1 XAdvance="-20"/>
@@ -117,13 +114,11 @@
           </Class1Record>
           <Class1Record index="1">
             <Class2Record index="0">
-              <Value1 XAdvance="0"/>
             </Class2Record>
             <Class2Record index="1">
               <Value1 XAdvance="-10"/>
             </Class2Record>
             <Class2Record index="2">
-              <Value1 XAdvance="0"/>
             </Class2Record>
           </Class1Record>
         </PairPos>
diff --git a/Tests/feaLib/data/STAT_bad.fea b/Tests/feaLib/data/STAT_bad.fea
deleted file mode 100644
index 8ec887f..0000000
--- a/Tests/feaLib/data/STAT_bad.fea
+++ /dev/null
@@ -1,96 +0,0 @@
-# bad fea file: Testing DesignAxis tag with incorrect label
-table name {
-	nameid 25 "TestFont";
-} name;
-
-
-table STAT {
-
-   ElidedFallbackName { name "Roman"; };
-
-   DesignAxis opsz 0 { badtag "Optical Size"; };  #'badtag' instead of 'name' is incorrect
-   DesignAxis wdth 1 { name "Width"; };
-   DesignAxis wght 2 { name "Weight"; };
-   DesignAxis ital 3 { name "Italic"; };
-
-   AxisValue {
-      location opsz 8 5 9;
-      location wdth 300 350 450;
-      name "Caption";
-   };
-
-   AxisValue {
-      location opsz 11 9 12;
-      name "Text";
-      flag OlderSiblingFontAttribute ElidableAxisValueName ;
-   };
-
-   AxisValue {
-      location opsz 16.7 12 24;
-      name "Subhead";
-   };
-
-   AxisValue {
-      location opsz 72 24 72;
-      name "Display";
-   };
-
-   AxisValue {
-      location wdth 80 80 89;
-      name "Condensed";
-   };
-
-   AxisValue {
-      location wdth 90 90 96;
-      name "Semicondensed";
-   };
-
-   AxisValue {
-      location wdth 100 97 101;
-      name "Normal";
-      flag ElidableAxisValueName;
-   };
-
-   AxisValue {
-      location wdth 125 102 125;
-      name "Extended";
-   };
-
-   AxisValue {
-      location wght 300 300 349;
-      name "Light";
-   };
-
-   AxisValue {
-      location wght 400 350 449;
-      name "Regular";
-      flag ElidableAxisValueName;
-   };
-
-   AxisValue {
-      location wght 500 450 549;
-      name "Medium";
-   };
-
-   AxisValue {
-      location wght 600 550 649;
-      name "Semibold";
-   };
-
-   AxisValue {
-      location wght 700 650 749;
-      name "Bold";
-   };
-
-   AxisValue {
-      location wght 900 750 900;
-      name "Black";
-   };
-
-   AxisValue {
-      location ital 0;
-      name "Roman";
-      flag ElidableAxisValueName;
-   };
-
-} STAT;
diff --git a/Tests/feaLib/data/STAT_test.fea b/Tests/feaLib/data/STAT_test.fea
deleted file mode 100644
index 0103637..0000000
--- a/Tests/feaLib/data/STAT_test.fea
+++ /dev/null
@@ -1,109 +0,0 @@
-table name {
-	nameid 25 "TestFont";
-} name;
-
-
-table STAT {
-
-    ElidedFallbackName {
-        name "Roman";
-        name 3 1 1041 "ローマン";
-    };
-
-    DesignAxis opsz 0 {
-        name "Optical Size";
-    };
-
-    DesignAxis wdth 1 {
-        name "Width";
-    };
-
-    DesignAxis wght 2 {
-        name "Weight";
-    };
-
-    DesignAxis ital 3 {
-        name "Italic";
-    };  # here comment
-
-    AxisValue {
-        location opsz 8;  # comment here
-        location wdth 400; # another comment
-        name "Caption"; # more comments
-    };
-
-    AxisValue {
-        location opsz 11 9 12;
-        name "Text";
-        flag OlderSiblingFontAttribute ElidableAxisValueName;
-    };
-
-    AxisValue {
-        location opsz 16.7 12 24;
-        name "Subhead";
-    };
-
-    AxisValue {
-        location opsz 72 24 72;
-        name "Display";
-    };
-
-    AxisValue {
-        location wdth 80 80 89;
-        name "Condensed";
-    };
-
-    AxisValue {
-        location wdth 90 90 96;
-        name "Semicondensed";
-    };
-
-    AxisValue {
-        location wdth 100 97 101;
-        name "Normal";
-        flag ElidableAxisValueName;
-    };
-
-    AxisValue {
-        location wdth 125 102 125;
-        name "Extended";
-    };
-
-    AxisValue {
-        location wght 300 300 349;
-        name "Light";
-    };
-
-    AxisValue {
-        location wght 400 350 449;
-        name "Regular";
-        flag ElidableAxisValueName;
-    };
-
-    AxisValue {
-        location wght 500 450 549;
-        name "Medium";
-    };
-
-    AxisValue {
-        location wght 600 550 649;
-        name "Semibold";
-    };
-
-    AxisValue {
-        location wght 700 650 749;
-        name "Bold";
-    };
-
-    AxisValue {
-        location wght 900 750 900;
-        name "Black";
-    };
-
-    AxisValue {
-        location ital 0;
-        name "Roman";
-        flag ElidableAxisValueName; # flag comment
-    };
-
-} STAT;
diff --git a/Tests/feaLib/data/STAT_test.ttx b/Tests/feaLib/data/STAT_test.ttx
deleted file mode 100644
index d1b2b69..0000000
--- a/Tests/feaLib/data/STAT_test.ttx
+++ /dev/null
@@ -1,228 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.20">
-
-  <name>
-    <namerecord nameID="25" platformID="3" platEncID="1" langID="0x409">
-      TestFont
-    </namerecord>
-    <namerecord nameID="256" platformID="3" platEncID="1" langID="0x409">
-      Roman
-    </namerecord>
-    <namerecord nameID="256" platformID="3" platEncID="1" langID="0x411">
-      ローマン
-    </namerecord>
-    <namerecord nameID="257" platformID="3" platEncID="1" langID="0x409">
-      Optical Size
-    </namerecord>
-    <namerecord nameID="258" platformID="3" platEncID="1" langID="0x409">
-      Text
-    </namerecord>
-    <namerecord nameID="259" platformID="3" platEncID="1" langID="0x409">
-      Subhead
-    </namerecord>
-    <namerecord nameID="260" platformID="3" platEncID="1" langID="0x409">
-      Display
-    </namerecord>
-    <namerecord nameID="261" platformID="3" platEncID="1" langID="0x409">
-      Width
-    </namerecord>
-    <namerecord nameID="262" platformID="3" platEncID="1" langID="0x409">
-      Condensed
-    </namerecord>
-    <namerecord nameID="263" platformID="3" platEncID="1" langID="0x409">
-      Semicondensed
-    </namerecord>
-    <namerecord nameID="264" platformID="3" platEncID="1" langID="0x409">
-      Normal
-    </namerecord>
-    <namerecord nameID="265" platformID="3" platEncID="1" langID="0x409">
-      Extended
-    </namerecord>
-    <namerecord nameID="266" platformID="3" platEncID="1" langID="0x409">
-      Weight
-    </namerecord>
-    <namerecord nameID="267" platformID="3" platEncID="1" langID="0x409">
-      Light
-    </namerecord>
-    <namerecord nameID="268" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="269" platformID="3" platEncID="1" langID="0x409">
-      Medium
-    </namerecord>
-    <namerecord nameID="270" platformID="3" platEncID="1" langID="0x409">
-      Semibold
-    </namerecord>
-    <namerecord nameID="271" platformID="3" platEncID="1" langID="0x409">
-      Bold
-    </namerecord>
-    <namerecord nameID="272" platformID="3" platEncID="1" langID="0x409">
-      Black
-    </namerecord>
-    <namerecord nameID="273" platformID="3" platEncID="1" langID="0x409">
-      Italic
-    </namerecord>
-    <namerecord nameID="274" platformID="3" platEncID="1" langID="0x409">
-      Roman
-    </namerecord>
-    <namerecord nameID="275" platformID="3" platEncID="1" langID="0x409">
-      Caption
-    </namerecord>
-  </name>
-
-  <STAT>
-    <Version value="0x00010002"/>
-    <DesignAxisRecordSize value="8"/>
-    <!-- DesignAxisCount=4 -->
-    <DesignAxisRecord>
-      <Axis index="0">
-        <AxisTag value="opsz"/>
-        <AxisNameID value="257"/>  <!-- Optical Size -->
-        <AxisOrdering value="0"/>
-      </Axis>
-      <Axis index="1">
-        <AxisTag value="wdth"/>
-        <AxisNameID value="261"/>  <!-- Width -->
-        <AxisOrdering value="1"/>
-      </Axis>
-      <Axis index="2">
-        <AxisTag value="wght"/>
-        <AxisNameID value="266"/>  <!-- Weight -->
-        <AxisOrdering value="2"/>
-      </Axis>
-      <Axis index="3">
-        <AxisTag value="ital"/>
-        <AxisNameID value="273"/>  <!-- Italic -->
-        <AxisOrdering value="3"/>
-      </Axis>
-    </DesignAxisRecord>
-    <!-- AxisValueCount=15 -->
-    <AxisValueArray>
-      <AxisValue index="0" Format="4">
-        <!-- AxisCount=2 -->
-        <Flags value="0"/>
-        <ValueNameID value="275"/>  <!-- Caption -->
-        <AxisValueRecord index="0">
-          <AxisIndex value="0"/>
-          <Value value="8.0"/>
-        </AxisValueRecord>
-        <AxisValueRecord index="1">
-          <AxisIndex value="1"/>
-          <Value value="400.0"/>
-        </AxisValueRecord>
-      </AxisValue>
-      <AxisValue index="1" Format="2">
-        <AxisIndex value="0"/>
-        <Flags value="3"/>  <!-- OlderSiblingFontAttribute ElidableAxisValueName -->
-        <ValueNameID value="258"/>  <!-- Text -->
-        <NominalValue value="11.0"/>
-        <RangeMinValue value="9.0"/>
-        <RangeMaxValue value="12.0"/>
-      </AxisValue>
-      <AxisValue index="2" Format="2">
-        <AxisIndex value="0"/>
-        <Flags value="0"/>
-        <ValueNameID value="259"/>  <!-- Subhead -->
-        <NominalValue value="16.7"/>
-        <RangeMinValue value="12.0"/>
-        <RangeMaxValue value="24.0"/>
-      </AxisValue>
-      <AxisValue index="3" Format="2">
-        <AxisIndex value="0"/>
-        <Flags value="0"/>
-        <ValueNameID value="260"/>  <!-- Display -->
-        <NominalValue value="72.0"/>
-        <RangeMinValue value="24.0"/>
-        <RangeMaxValue value="72.0"/>
-      </AxisValue>
-      <AxisValue index="4" Format="2">
-        <AxisIndex value="1"/>
-        <Flags value="0"/>
-        <ValueNameID value="262"/>  <!-- Condensed -->
-        <NominalValue value="80.0"/>
-        <RangeMinValue value="80.0"/>
-        <RangeMaxValue value="89.0"/>
-      </AxisValue>
-      <AxisValue index="5" Format="2">
-        <AxisIndex value="1"/>
-        <Flags value="0"/>
-        <ValueNameID value="263"/>  <!-- Semicondensed -->
-        <NominalValue value="90.0"/>
-        <RangeMinValue value="90.0"/>
-        <RangeMaxValue value="96.0"/>
-      </AxisValue>
-      <AxisValue index="6" Format="2">
-        <AxisIndex value="1"/>
-        <Flags value="2"/>  <!-- ElidableAxisValueName -->
-        <ValueNameID value="264"/>  <!-- Normal -->
-        <NominalValue value="100.0"/>
-        <RangeMinValue value="97.0"/>
-        <RangeMaxValue value="101.0"/>
-      </AxisValue>
-      <AxisValue index="7" Format="2">
-        <AxisIndex value="1"/>
-        <Flags value="0"/>
-        <ValueNameID value="265"/>  <!-- Extended -->
-        <NominalValue value="125.0"/>
-        <RangeMinValue value="102.0"/>
-        <RangeMaxValue value="125.0"/>
-      </AxisValue>
-      <AxisValue index="8" Format="2">
-        <AxisIndex value="2"/>
-        <Flags value="0"/>
-        <ValueNameID value="267"/>  <!-- Light -->
-        <NominalValue value="300.0"/>
-        <RangeMinValue value="300.0"/>
-        <RangeMaxValue value="349.0"/>
-      </AxisValue>
-      <AxisValue index="9" Format="2">
-        <AxisIndex value="2"/>
-        <Flags value="2"/>  <!-- ElidableAxisValueName -->
-        <ValueNameID value="268"/>  <!-- Regular -->
-        <NominalValue value="400.0"/>
-        <RangeMinValue value="350.0"/>
-        <RangeMaxValue value="449.0"/>
-      </AxisValue>
-      <AxisValue index="10" Format="2">
-        <AxisIndex value="2"/>
-        <Flags value="0"/>
-        <ValueNameID value="269"/>  <!-- Medium -->
-        <NominalValue value="500.0"/>
-        <RangeMinValue value="450.0"/>
-        <RangeMaxValue value="549.0"/>
-      </AxisValue>
-      <AxisValue index="11" Format="2">
-        <AxisIndex value="2"/>
-        <Flags value="0"/>
-        <ValueNameID value="270"/>  <!-- Semibold -->
-        <NominalValue value="600.0"/>
-        <RangeMinValue value="550.0"/>
-        <RangeMaxValue value="649.0"/>
-      </AxisValue>
-      <AxisValue index="12" Format="2">
-        <AxisIndex value="2"/>
-        <Flags value="0"/>
-        <ValueNameID value="271"/>  <!-- Bold -->
-        <NominalValue value="700.0"/>
-        <RangeMinValue value="650.0"/>
-        <RangeMaxValue value="749.0"/>
-      </AxisValue>
-      <AxisValue index="13" Format="2">
-        <AxisIndex value="2"/>
-        <Flags value="0"/>
-        <ValueNameID value="272"/>  <!-- Black -->
-        <NominalValue value="900.0"/>
-        <RangeMinValue value="750.0"/>
-        <RangeMaxValue value="900.0"/>
-      </AxisValue>
-      <AxisValue index="14" Format="1">
-        <AxisIndex value="3"/>
-        <Flags value="2"/>  <!-- ElidableAxisValueName -->
-        <ValueNameID value="274"/>  <!-- Roman -->
-        <Value value="0.0"/>
-      </AxisValue>
-    </AxisValueArray>
-    <ElidedFallbackNameID value="256"/>  <!-- Roman -->
-  </STAT>
-
-</ttFont>
diff --git a/Tests/feaLib/data/STAT_test_elidedFallbackNameID.fea b/Tests/feaLib/data/STAT_test_elidedFallbackNameID.fea
deleted file mode 100644
index 5a14180..0000000
--- a/Tests/feaLib/data/STAT_test_elidedFallbackNameID.fea
+++ /dev/null
@@ -1,84 +0,0 @@
-table name {
-    nameid 25 "TestFont";
-    nameid 256 "Roman";
-} name;
-table STAT {
-    ElidedFallbackNameID 256;
-    DesignAxis opsz 0 {
-        name "Optical Size";
-    };
-    DesignAxis wdth 1 {
-        name "Width";
-    };
-    DesignAxis wght 2 {
-        name "Weight";
-    };
-    DesignAxis ital 3 {
-        name "Italic";
-    };  # here comment
-    AxisValue {
-        location opsz 8;  # comment here
-        location wdth 400; # another comment
-        name "Caption"; # more comments
-    };
-    AxisValue {
-        location opsz 11 9 12;
-        name "Text";
-        flag OlderSiblingFontAttribute ElidableAxisValueName;
-    };
-    AxisValue {
-        location opsz 16.7 12 24;
-        name "Subhead";
-    };
-    AxisValue {
-        location opsz 72 24 72;
-        name "Display";
-    };
-    AxisValue {
-        location wdth 80 80 89;
-        name "Condensed";
-    };
-    AxisValue {
-        location wdth 90 90 96;
-        name "Semicondensed";
-    };
-    AxisValue {
-        location wdth 100 97 101;
-        name "Normal";
-        flag ElidableAxisValueName;
-    };
-    AxisValue {
-        location wdth 125 102 125;
-        name "Extended";
-    };
-    AxisValue {
-        location wght 300 300 349;
-        name "Light";
-    };
-    AxisValue {
-        location wght 400 350 449;
-        name "Regular";
-        flag ElidableAxisValueName;
-    };
-    AxisValue {
-        location wght 500 450 549;
-        name "Medium";
-    };
-    AxisValue {
-        location wght 600 550 649;
-        name "Semibold";
-    };
-    AxisValue {
-        location wght 700 650 749;
-        name "Bold";
-    };
-    AxisValue {
-        location wght 900 750 900;
-        name "Black";
-    };
-    AxisValue {
-        location ital 0;
-        name "Roman";
-        flag ElidableAxisValueName; # flag comment
-    };
-} STAT;
\ No newline at end of file
diff --git a/Tests/feaLib/data/STAT_test_elidedFallbackNameID.ttx b/Tests/feaLib/data/STAT_test_elidedFallbackNameID.ttx
deleted file mode 100644
index 32802e0..0000000
--- a/Tests/feaLib/data/STAT_test_elidedFallbackNameID.ttx
+++ /dev/null
@@ -1,225 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.20">
-
-  <name>
-    <namerecord nameID="25" platformID="3" platEncID="1" langID="0x409">
-      TestFont
-    </namerecord>
-    <namerecord nameID="256" platformID="3" platEncID="1" langID="0x409">
-      Roman
-    </namerecord>
-    <namerecord nameID="257" platformID="3" platEncID="1" langID="0x409">
-      Optical Size
-    </namerecord>
-    <namerecord nameID="258" platformID="3" platEncID="1" langID="0x409">
-      Text
-    </namerecord>
-    <namerecord nameID="259" platformID="3" platEncID="1" langID="0x409">
-      Subhead
-    </namerecord>
-    <namerecord nameID="260" platformID="3" platEncID="1" langID="0x409">
-      Display
-    </namerecord>
-    <namerecord nameID="261" platformID="3" platEncID="1" langID="0x409">
-      Width
-    </namerecord>
-    <namerecord nameID="262" platformID="3" platEncID="1" langID="0x409">
-      Condensed
-    </namerecord>
-    <namerecord nameID="263" platformID="3" platEncID="1" langID="0x409">
-      Semicondensed
-    </namerecord>
-    <namerecord nameID="264" platformID="3" platEncID="1" langID="0x409">
-      Normal
-    </namerecord>
-    <namerecord nameID="265" platformID="3" platEncID="1" langID="0x409">
-      Extended
-    </namerecord>
-    <namerecord nameID="266" platformID="3" platEncID="1" langID="0x409">
-      Weight
-    </namerecord>
-    <namerecord nameID="267" platformID="3" platEncID="1" langID="0x409">
-      Light
-    </namerecord>
-    <namerecord nameID="268" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="269" platformID="3" platEncID="1" langID="0x409">
-      Medium
-    </namerecord>
-    <namerecord nameID="270" platformID="3" platEncID="1" langID="0x409">
-      Semibold
-    </namerecord>
-    <namerecord nameID="271" platformID="3" platEncID="1" langID="0x409">
-      Bold
-    </namerecord>
-    <namerecord nameID="272" platformID="3" platEncID="1" langID="0x409">
-      Black
-    </namerecord>
-    <namerecord nameID="273" platformID="3" platEncID="1" langID="0x409">
-      Italic
-    </namerecord>
-    <namerecord nameID="274" platformID="3" platEncID="1" langID="0x409">
-      Roman
-    </namerecord>
-    <namerecord nameID="275" platformID="3" platEncID="1" langID="0x409">
-      Caption
-    </namerecord>
-  </name>
-
-  <STAT>
-    <Version value="0x00010002"/>
-    <DesignAxisRecordSize value="8"/>
-    <!-- DesignAxisCount=4 -->
-    <DesignAxisRecord>
-      <Axis index="0">
-        <AxisTag value="opsz"/>
-        <AxisNameID value="257"/>  <!-- Optical Size -->
-        <AxisOrdering value="0"/>
-      </Axis>
-      <Axis index="1">
-        <AxisTag value="wdth"/>
-        <AxisNameID value="261"/>  <!-- Width -->
-        <AxisOrdering value="1"/>
-      </Axis>
-      <Axis index="2">
-        <AxisTag value="wght"/>
-        <AxisNameID value="266"/>  <!-- Weight -->
-        <AxisOrdering value="2"/>
-      </Axis>
-      <Axis index="3">
-        <AxisTag value="ital"/>
-        <AxisNameID value="273"/>  <!-- Italic -->
-        <AxisOrdering value="3"/>
-      </Axis>
-    </DesignAxisRecord>
-    <!-- AxisValueCount=15 -->
-    <AxisValueArray>
-      <AxisValue index="0" Format="4">
-        <!-- AxisCount=2 -->
-        <Flags value="0"/>
-        <ValueNameID value="275"/>  <!-- Caption -->
-        <AxisValueRecord index="0">
-          <AxisIndex value="0"/>
-          <Value value="8.0"/>
-        </AxisValueRecord>
-        <AxisValueRecord index="1">
-          <AxisIndex value="1"/>
-          <Value value="400.0"/>
-        </AxisValueRecord>
-      </AxisValue>
-      <AxisValue index="1" Format="2">
-        <AxisIndex value="0"/>
-        <Flags value="3"/>  <!-- OlderSiblingFontAttribute ElidableAxisValueName -->
-        <ValueNameID value="258"/>  <!-- Text -->
-        <NominalValue value="11.0"/>
-        <RangeMinValue value="9.0"/>
-        <RangeMaxValue value="12.0"/>
-      </AxisValue>
-      <AxisValue index="2" Format="2">
-        <AxisIndex value="0"/>
-        <Flags value="0"/>
-        <ValueNameID value="259"/>  <!-- Subhead -->
-        <NominalValue value="16.7"/>
-        <RangeMinValue value="12.0"/>
-        <RangeMaxValue value="24.0"/>
-      </AxisValue>
-      <AxisValue index="3" Format="2">
-        <AxisIndex value="0"/>
-        <Flags value="0"/>
-        <ValueNameID value="260"/>  <!-- Display -->
-        <NominalValue value="72.0"/>
-        <RangeMinValue value="24.0"/>
-        <RangeMaxValue value="72.0"/>
-      </AxisValue>
-      <AxisValue index="4" Format="2">
-        <AxisIndex value="1"/>
-        <Flags value="0"/>
-        <ValueNameID value="262"/>  <!-- Condensed -->
-        <NominalValue value="80.0"/>
-        <RangeMinValue value="80.0"/>
-        <RangeMaxValue value="89.0"/>
-      </AxisValue>
-      <AxisValue index="5" Format="2">
-        <AxisIndex value="1"/>
-        <Flags value="0"/>
-        <ValueNameID value="263"/>  <!-- Semicondensed -->
-        <NominalValue value="90.0"/>
-        <RangeMinValue value="90.0"/>
-        <RangeMaxValue value="96.0"/>
-      </AxisValue>
-      <AxisValue index="6" Format="2">
-        <AxisIndex value="1"/>
-        <Flags value="2"/>  <!-- ElidableAxisValueName -->
-        <ValueNameID value="264"/>  <!-- Normal -->
-        <NominalValue value="100.0"/>
-        <RangeMinValue value="97.0"/>
-        <RangeMaxValue value="101.0"/>
-      </AxisValue>
-      <AxisValue index="7" Format="2">
-        <AxisIndex value="1"/>
-        <Flags value="0"/>
-        <ValueNameID value="265"/>  <!-- Extended -->
-        <NominalValue value="125.0"/>
-        <RangeMinValue value="102.0"/>
-        <RangeMaxValue value="125.0"/>
-      </AxisValue>
-      <AxisValue index="8" Format="2">
-        <AxisIndex value="2"/>
-        <Flags value="0"/>
-        <ValueNameID value="267"/>  <!-- Light -->
-        <NominalValue value="300.0"/>
-        <RangeMinValue value="300.0"/>
-        <RangeMaxValue value="349.0"/>
-      </AxisValue>
-      <AxisValue index="9" Format="2">
-        <AxisIndex value="2"/>
-        <Flags value="2"/>  <!-- ElidableAxisValueName -->
-        <ValueNameID value="268"/>  <!-- Regular -->
-        <NominalValue value="400.0"/>
-        <RangeMinValue value="350.0"/>
-        <RangeMaxValue value="449.0"/>
-      </AxisValue>
-      <AxisValue index="10" Format="2">
-        <AxisIndex value="2"/>
-        <Flags value="0"/>
-        <ValueNameID value="269"/>  <!-- Medium -->
-        <NominalValue value="500.0"/>
-        <RangeMinValue value="450.0"/>
-        <RangeMaxValue value="549.0"/>
-      </AxisValue>
-      <AxisValue index="11" Format="2">
-        <AxisIndex value="2"/>
-        <Flags value="0"/>
-        <ValueNameID value="270"/>  <!-- Semibold -->
-        <NominalValue value="600.0"/>
-        <RangeMinValue value="550.0"/>
-        <RangeMaxValue value="649.0"/>
-      </AxisValue>
-      <AxisValue index="12" Format="2">
-        <AxisIndex value="2"/>
-        <Flags value="0"/>
-        <ValueNameID value="271"/>  <!-- Bold -->
-        <NominalValue value="700.0"/>
-        <RangeMinValue value="650.0"/>
-        <RangeMaxValue value="749.0"/>
-      </AxisValue>
-      <AxisValue index="13" Format="2">
-        <AxisIndex value="2"/>
-        <Flags value="0"/>
-        <ValueNameID value="272"/>  <!-- Black -->
-        <NominalValue value="900.0"/>
-        <RangeMinValue value="750.0"/>
-        <RangeMaxValue value="900.0"/>
-      </AxisValue>
-      <AxisValue index="14" Format="1">
-        <AxisIndex value="3"/>
-        <Flags value="2"/>  <!-- ElidableAxisValueName -->
-        <ValueNameID value="274"/>  <!-- Roman -->
-        <Value value="0.0"/>
-      </AxisValue>
-    </AxisValueArray>
-    <ElidedFallbackNameID value="256"/>  <!-- Roman -->
-  </STAT>
-
-</ttFont>
diff --git a/Tests/feaLib/data/SubstSubtable.fea b/Tests/feaLib/data/SubstSubtable.fea
deleted file mode 100644
index b6e959a..0000000
--- a/Tests/feaLib/data/SubstSubtable.fea
+++ /dev/null
@@ -1,9 +0,0 @@
-feature test {
-    sub G' by G.swash;
-    subtable;
-    sub H' by H.swash;
-    subtable;
-    sub G' by g;
-    subtable;
-    sub H' by H.swash;
-} test;
diff --git a/Tests/feaLib/data/SubstSubtable.ttx b/Tests/feaLib/data/SubstSubtable.ttx
deleted file mode 100644
index 8718f46..0000000
--- a/Tests/feaLib/data/SubstSubtable.ttx
+++ /dev/null
@@ -1,116 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont>
-
-  <GSUB>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=1 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="test"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="0"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=5 -->
-      <Lookup index="0">
-        <LookupType value="5"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=4 -->
-        <ContextSubst index="0" Format="3">
-          <!-- GlyphCount=1 -->
-          <!-- SubstCount=1 -->
-          <Coverage index="0">
-            <Glyph value="G"/>
-          </Coverage>
-          <SubstLookupRecord index="0">
-            <SequenceIndex value="0"/>
-            <LookupListIndex value="1"/>
-          </SubstLookupRecord>
-        </ContextSubst>
-        <ContextSubst index="1" Format="3">
-          <!-- GlyphCount=1 -->
-          <!-- SubstCount=1 -->
-          <Coverage index="0">
-            <Glyph value="H"/>
-          </Coverage>
-          <SubstLookupRecord index="0">
-            <SequenceIndex value="0"/>
-            <LookupListIndex value="2"/>
-          </SubstLookupRecord>
-        </ContextSubst>
-        <ContextSubst index="2" Format="3">
-          <!-- GlyphCount=1 -->
-          <!-- SubstCount=1 -->
-          <Coverage index="0">
-            <Glyph value="G"/>
-          </Coverage>
-          <SubstLookupRecord index="0">
-            <SequenceIndex value="0"/>
-            <LookupListIndex value="3"/>
-          </SubstLookupRecord>
-        </ContextSubst>
-        <ContextSubst index="3" Format="3">
-          <!-- GlyphCount=1 -->
-          <!-- SubstCount=1 -->
-          <Coverage index="0">
-            <Glyph value="H"/>
-          </Coverage>
-          <SubstLookupRecord index="0">
-            <SequenceIndex value="0"/>
-            <LookupListIndex value="4"/>
-          </SubstLookupRecord>
-        </ContextSubst>
-      </Lookup>
-      <Lookup index="1">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="G" out="G.swash"/>
-        </SingleSubst>
-      </Lookup>
-      <Lookup index="2">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="H" out="H.swash"/>
-        </SingleSubst>
-      </Lookup>
-      <Lookup index="3">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="G" out="g"/>
-        </SingleSubst>
-      </Lookup>
-      <Lookup index="4">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="H" out="H.swash"/>
-        </SingleSubst>
-      </Lookup>
-    </LookupList>
-  </GSUB>
-
-</ttFont>
diff --git a/Tests/feaLib/data/ZeroValue_ChainSinglePos_horizontal.ttx b/Tests/feaLib/data/ZeroValue_ChainSinglePos_horizontal.ttx
index 98f7aa9..ce76370 100644
--- a/Tests/feaLib/data/ZeroValue_ChainSinglePos_horizontal.ttx
+++ b/Tests/feaLib/data/ZeroValue_ChainSinglePos_horizontal.ttx
@@ -32,39 +32,44 @@
       <Lookup index="0">
         <LookupType value="8"/>
         <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <ChainContextPos index="0" Format="1">
-          <Coverage>
+        <!-- SubTableCount=2 -->
+        <ChainContextPos index="0" Format="3">
+          <!-- BacktrackGlyphCount=1 -->
+          <BacktrackCoverage index="0">
+            <Glyph value="A"/>
+          </BacktrackCoverage>
+          <!-- InputGlyphCount=1 -->
+          <InputCoverage index="0">
             <Glyph value="G"/>
-          </Coverage>
-          <!-- ChainPosRuleSetCount=1 -->
-          <ChainPosRuleSet index="0">
-            <!-- ChainPosRuleCount=2 -->
-            <ChainPosRule index="0">
-              <!-- BacktrackGlyphCount=1 -->
-              <Backtrack index="0" value="A"/>
-              <!-- InputGlyphCount=1 -->
-              <!-- LookAheadGlyphCount=1 -->
-              <LookAhead index="0" value="A"/>
-              <!-- PosCount=1 -->
-              <PosLookupRecord index="0">
-                <SequenceIndex value="0"/>
-                <LookupListIndex value="1"/>
-              </PosLookupRecord>
-            </ChainPosRule>
-            <ChainPosRule index="1">
-              <!-- BacktrackGlyphCount=1 -->
-              <Backtrack index="0" value="B"/>
-              <!-- InputGlyphCount=1 -->
-              <!-- LookAheadGlyphCount=1 -->
-              <LookAhead index="0" value="B"/>
-              <!-- PosCount=1 -->
-              <PosLookupRecord index="0">
-                <SequenceIndex value="0"/>
-                <LookupListIndex value="1"/>
-              </PosLookupRecord>
-            </ChainPosRule>
-          </ChainPosRuleSet>
+          </InputCoverage>
+          <!-- LookAheadGlyphCount=1 -->
+          <LookAheadCoverage index="0">
+            <Glyph value="A"/>
+          </LookAheadCoverage>
+          <!-- PosCount=1 -->
+          <PosLookupRecord index="0">
+            <SequenceIndex value="0"/>
+            <LookupListIndex value="1"/>
+          </PosLookupRecord>
+        </ChainContextPos>
+        <ChainContextPos index="1" Format="3">
+          <!-- BacktrackGlyphCount=1 -->
+          <BacktrackCoverage index="0">
+            <Glyph value="B"/>
+          </BacktrackCoverage>
+          <!-- InputGlyphCount=1 -->
+          <InputCoverage index="0">
+            <Glyph value="G"/>
+          </InputCoverage>
+          <!-- LookAheadGlyphCount=1 -->
+          <LookAheadCoverage index="0">
+            <Glyph value="B"/>
+          </LookAheadCoverage>
+          <!-- PosCount=1 -->
+          <PosLookupRecord index="0">
+            <SequenceIndex value="0"/>
+            <LookupListIndex value="1"/>
+          </PosLookupRecord>
         </ChainContextPos>
       </Lookup>
       <Lookup index="1">
diff --git a/Tests/feaLib/data/ZeroValue_ChainSinglePos_vertical.ttx b/Tests/feaLib/data/ZeroValue_ChainSinglePos_vertical.ttx
index 973cb4f..e1cb5d6 100644
--- a/Tests/feaLib/data/ZeroValue_ChainSinglePos_vertical.ttx
+++ b/Tests/feaLib/data/ZeroValue_ChainSinglePos_vertical.ttx
@@ -32,39 +32,44 @@
       <Lookup index="0">
         <LookupType value="8"/>
         <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <ChainContextPos index="0" Format="1">
-          <Coverage>
+        <!-- SubTableCount=2 -->
+        <ChainContextPos index="0" Format="3">
+          <!-- BacktrackGlyphCount=1 -->
+          <BacktrackCoverage index="0">
+            <Glyph value="A"/>
+          </BacktrackCoverage>
+          <!-- InputGlyphCount=1 -->
+          <InputCoverage index="0">
             <Glyph value="G"/>
-          </Coverage>
-          <!-- ChainPosRuleSetCount=1 -->
-          <ChainPosRuleSet index="0">
-            <!-- ChainPosRuleCount=2 -->
-            <ChainPosRule index="0">
-              <!-- BacktrackGlyphCount=1 -->
-              <Backtrack index="0" value="A"/>
-              <!-- InputGlyphCount=1 -->
-              <!-- LookAheadGlyphCount=1 -->
-              <LookAhead index="0" value="A"/>
-              <!-- PosCount=1 -->
-              <PosLookupRecord index="0">
-                <SequenceIndex value="0"/>
-                <LookupListIndex value="1"/>
-              </PosLookupRecord>
-            </ChainPosRule>
-            <ChainPosRule index="1">
-              <!-- BacktrackGlyphCount=1 -->
-              <Backtrack index="0" value="B"/>
-              <!-- InputGlyphCount=1 -->
-              <!-- LookAheadGlyphCount=1 -->
-              <LookAhead index="0" value="B"/>
-              <!-- PosCount=1 -->
-              <PosLookupRecord index="0">
-                <SequenceIndex value="0"/>
-                <LookupListIndex value="1"/>
-              </PosLookupRecord>
-            </ChainPosRule>
-          </ChainPosRuleSet>
+          </InputCoverage>
+          <!-- LookAheadGlyphCount=1 -->
+          <LookAheadCoverage index="0">
+            <Glyph value="A"/>
+          </LookAheadCoverage>
+          <!-- PosCount=1 -->
+          <PosLookupRecord index="0">
+            <SequenceIndex value="0"/>
+            <LookupListIndex value="1"/>
+          </PosLookupRecord>
+        </ChainContextPos>
+        <ChainContextPos index="1" Format="3">
+          <!-- BacktrackGlyphCount=1 -->
+          <BacktrackCoverage index="0">
+            <Glyph value="B"/>
+          </BacktrackCoverage>
+          <!-- InputGlyphCount=1 -->
+          <InputCoverage index="0">
+            <Glyph value="G"/>
+          </InputCoverage>
+          <!-- LookAheadGlyphCount=1 -->
+          <LookAheadCoverage index="0">
+            <Glyph value="B"/>
+          </LookAheadCoverage>
+          <!-- PosCount=1 -->
+          <PosLookupRecord index="0">
+            <SequenceIndex value="0"/>
+            <LookupListIndex value="1"/>
+          </PosLookupRecord>
         </ChainContextPos>
       </Lookup>
       <Lookup index="1">
diff --git a/Tests/feaLib/data/aalt_chain_contextual_subst.fea b/Tests/feaLib/data/aalt_chain_contextual_subst.fea
deleted file mode 100644
index 677c230..0000000
--- a/Tests/feaLib/data/aalt_chain_contextual_subst.fea
+++ /dev/null
@@ -1,20 +0,0 @@
-# https://github.com/googlefonts/fontmake/issues/648
-
-lookup CNTXT_LIGS {
-    sub f i by f_i;
-    sub c t by c_t;
-} CNTXT_LIGS;
-
-lookup CNTXT_SUB {
-    sub n by n.end;
-    sub s by s.end;
-} CNTXT_SUB;
-
-feature calt {
-    sub [a e i o u] f' lookup CNTXT_LIGS i' n' lookup CNTXT_SUB;
-    sub [a e i o u] c' lookup CNTXT_LIGS t' s' lookup CNTXT_SUB;
-} calt;
-
-feature aalt {
-    feature calt;
-} aalt;
diff --git a/Tests/feaLib/data/aalt_chain_contextual_subst.ttx b/Tests/feaLib/data/aalt_chain_contextual_subst.ttx
deleted file mode 100644
index 256a9c7..0000000
--- a/Tests/feaLib/data/aalt_chain_contextual_subst.ttx
+++ /dev/null
@@ -1,139 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont>
-
-  <GSUB>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=2 -->
-            <FeatureIndex index="0" value="0"/>
-            <FeatureIndex index="1" value="1"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=2 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="aalt"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="0"/>
-        </Feature>
-      </FeatureRecord>
-      <FeatureRecord index="1">
-        <FeatureTag value="calt"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="3"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=4 -->
-      <Lookup index="0">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="n" out="n.end"/>
-          <Substitution in="s" out="s.end"/>
-        </SingleSubst>
-      </Lookup>
-      <Lookup index="1">
-        <LookupType value="4"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
-          <LigatureSet glyph="c">
-            <Ligature components="t" glyph="c_t"/>
-          </LigatureSet>
-          <LigatureSet glyph="f">
-            <Ligature components="i" glyph="f_i"/>
-          </LigatureSet>
-        </LigatureSubst>
-      </Lookup>
-      <Lookup index="2">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="n" out="n.end"/>
-          <Substitution in="s" out="s.end"/>
-        </SingleSubst>
-      </Lookup>
-      <Lookup index="3">
-        <LookupType value="6"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=2 -->
-        <ChainContextSubst index="0" Format="3">
-          <!-- BacktrackGlyphCount=1 -->
-          <BacktrackCoverage index="0">
-            <Glyph value="a"/>
-            <Glyph value="e"/>
-            <Glyph value="i"/>
-            <Glyph value="o"/>
-            <Glyph value="u"/>
-          </BacktrackCoverage>
-          <!-- InputGlyphCount=3 -->
-          <InputCoverage index="0">
-            <Glyph value="f"/>
-          </InputCoverage>
-          <InputCoverage index="1">
-            <Glyph value="i"/>
-          </InputCoverage>
-          <InputCoverage index="2">
-            <Glyph value="n"/>
-          </InputCoverage>
-          <!-- LookAheadGlyphCount=0 -->
-          <!-- SubstCount=2 -->
-          <SubstLookupRecord index="0">
-            <SequenceIndex value="0"/>
-            <LookupListIndex value="1"/>
-          </SubstLookupRecord>
-          <SubstLookupRecord index="1">
-            <SequenceIndex value="2"/>
-            <LookupListIndex value="2"/>
-          </SubstLookupRecord>
-        </ChainContextSubst>
-        <ChainContextSubst index="1" Format="3">
-          <!-- BacktrackGlyphCount=1 -->
-          <BacktrackCoverage index="0">
-            <Glyph value="a"/>
-            <Glyph value="e"/>
-            <Glyph value="i"/>
-            <Glyph value="o"/>
-            <Glyph value="u"/>
-          </BacktrackCoverage>
-          <!-- InputGlyphCount=3 -->
-          <InputCoverage index="0">
-            <Glyph value="c"/>
-          </InputCoverage>
-          <InputCoverage index="1">
-            <Glyph value="t"/>
-          </InputCoverage>
-          <InputCoverage index="2">
-            <Glyph value="s"/>
-          </InputCoverage>
-          <!-- LookAheadGlyphCount=0 -->
-          <!-- SubstCount=2 -->
-          <SubstLookupRecord index="0">
-            <SequenceIndex value="0"/>
-            <LookupListIndex value="1"/>
-          </SubstLookupRecord>
-          <SubstLookupRecord index="1">
-            <SequenceIndex value="2"/>
-            <LookupListIndex value="2"/>
-          </SubstLookupRecord>
-        </ChainContextSubst>
-      </Lookup>
-    </LookupList>
-  </GSUB>
-
-</ttFont>
diff --git a/Tests/feaLib/data/bug453.fea b/Tests/feaLib/data/bug453.fea
index ed0e6f9..486632e 100644
--- a/Tests/feaLib/data/bug453.fea
+++ b/Tests/feaLib/data/bug453.fea
@@ -2,12 +2,10 @@
 feature mark {
     lookup mark1 {
         markClass [acute] <anchor 150 -10> @TOP_MARKS;
-        pos base [e]
-            <anchor 250 450> mark @TOP_MARKS;
+        pos base [e] <anchor 250 450> mark @TOP_MARKS;
     } mark1;
     lookup mark2 {
         markClass [acute] <anchor 150 -20> @TOP_MARKS_2;
-        pos base [e]
-            <anchor 250 450> mark @TOP_MARKS_2;
+        pos base [e] <anchor 250 450> mark @TOP_MARKS_2;
     } mark2;
 } mark;
diff --git a/Tests/feaLib/data/bug506.ttx b/Tests/feaLib/data/bug506.ttx
index 4daba45..9aff913 100644
--- a/Tests/feaLib/data/bug506.ttx
+++ b/Tests/feaLib/data/bug506.ttx
@@ -30,23 +30,25 @@
     <LookupList>
       <!-- LookupCount=2 -->
       <Lookup index="0">
-        <LookupType value="5"/>
+        <LookupType value="6"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <ContextSubst index="0" Format="3">
-          <!-- GlyphCount=2 -->
-          <!-- SubstCount=1 -->
-          <Coverage index="0">
+        <ChainContextSubst index="0" Format="3">
+          <!-- BacktrackGlyphCount=0 -->
+          <!-- InputGlyphCount=2 -->
+          <InputCoverage index="0">
             <Glyph value="f"/>
-          </Coverage>
-          <Coverage index="1">
+          </InputCoverage>
+          <InputCoverage index="1">
             <Glyph value="i"/>
-          </Coverage>
+          </InputCoverage>
+          <!-- LookAheadGlyphCount=0 -->
+          <!-- SubstCount=1 -->
           <SubstLookupRecord index="0">
             <SequenceIndex value="0"/>
             <LookupListIndex value="1"/>
           </SubstLookupRecord>
-        </ContextSubst>
+        </ChainContextSubst>
       </Lookup>
       <Lookup index="1">
         <LookupType value="4"/>
diff --git a/Tests/feaLib/data/bug509.ttx b/Tests/feaLib/data/bug509.ttx
index 52fba20..e5a36af 100644
--- a/Tests/feaLib/data/bug509.ttx
+++ b/Tests/feaLib/data/bug509.ttx
@@ -30,29 +30,33 @@
     <LookupList>
       <!-- LookupCount=2 -->
       <Lookup index="0">
-        <LookupType value="5"/>
+        <LookupType value="6"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=2 -->
-        <ContextSubst index="0" Format="3">
-          <!-- GlyphCount=1 -->
-          <!-- SubstCount=0 -->
-          <Coverage index="0">
+        <ChainContextSubst index="0" Format="3">
+          <!-- BacktrackGlyphCount=0 -->
+          <!-- InputGlyphCount=1 -->
+          <InputCoverage index="0">
             <Glyph value="A"/>
-          </Coverage>
-        </ContextSubst>
-        <ContextSubst index="1" Format="3">
-          <!-- GlyphCount=1 -->
-          <!-- SubstCount=1 -->
-          <Coverage index="0">
+          </InputCoverage>
+          <!-- LookAheadGlyphCount=0 -->
+          <!-- SubstCount=0 -->
+        </ChainContextSubst>
+        <ChainContextSubst index="1" Format="3">
+          <!-- BacktrackGlyphCount=0 -->
+          <!-- InputGlyphCount=1 -->
+          <InputCoverage index="0">
             <Glyph value="A"/>
             <Glyph value="A.sc"/>
             <Glyph value="A.alt1"/>
-          </Coverage>
+          </InputCoverage>
+          <!-- LookAheadGlyphCount=0 -->
+          <!-- SubstCount=1 -->
           <SubstLookupRecord index="0">
             <SequenceIndex value="0"/>
             <LookupListIndex value="1"/>
           </SubstLookupRecord>
-        </ContextSubst>
+        </ChainContextSubst>
       </Lookup>
       <Lookup index="1">
         <LookupType value="1"/>
diff --git a/Tests/feaLib/data/bug512.ttx b/Tests/feaLib/data/bug512.ttx
index 693ebeb..1dfe63f 100644
--- a/Tests/feaLib/data/bug512.ttx
+++ b/Tests/feaLib/data/bug512.ttx
@@ -30,54 +30,61 @@
     <LookupList>
       <!-- LookupCount=3 -->
       <Lookup index="0">
-        <LookupType value="5"/>
+        <LookupType value="6"/>
         <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <ContextSubst index="0" Format="1">
-          <Coverage>
+        <!-- SubTableCount=4 -->
+        <ChainContextSubst index="0" Format="3">
+          <!-- BacktrackGlyphCount=0 -->
+          <!-- InputGlyphCount=1 -->
+          <InputCoverage index="0">
             <Glyph value="G"/>
+          </InputCoverage>
+          <!-- LookAheadGlyphCount=0 -->
+          <!-- SubstCount=1 -->
+          <SubstLookupRecord index="0">
+            <SequenceIndex value="0"/>
+            <LookupListIndex value="1"/>
+          </SubstLookupRecord>
+        </ChainContextSubst>
+        <ChainContextSubst index="1" Format="3">
+          <!-- BacktrackGlyphCount=0 -->
+          <!-- InputGlyphCount=1 -->
+          <InputCoverage index="0">
             <Glyph value="H"/>
-          </Coverage>
-          <!-- SubRuleSetCount=2 -->
-          <SubRuleSet index="0">
-            <!-- SubRuleCount=2 -->
-            <SubRule index="0">
-              <!-- GlyphCount=1 -->
-              <!-- SubstCount=1 -->
-              <SubstLookupRecord index="0">
-                <SequenceIndex value="0"/>
-                <LookupListIndex value="1"/>
-              </SubstLookupRecord>
-            </SubRule>
-            <SubRule index="1">
-              <!-- GlyphCount=1 -->
-              <!-- SubstCount=1 -->
-              <SubstLookupRecord index="0">
-                <SequenceIndex value="0"/>
-                <LookupListIndex value="2"/>
-              </SubstLookupRecord>
-            </SubRule>
-          </SubRuleSet>
-          <SubRuleSet index="1">
-            <!-- SubRuleCount=2 -->
-            <SubRule index="0">
-              <!-- GlyphCount=1 -->
-              <!-- SubstCount=1 -->
-              <SubstLookupRecord index="0">
-                <SequenceIndex value="0"/>
-                <LookupListIndex value="1"/>
-              </SubstLookupRecord>
-            </SubRule>
-            <SubRule index="1">
-              <!-- GlyphCount=1 -->
-              <!-- SubstCount=1 -->
-              <SubstLookupRecord index="0">
-                <SequenceIndex value="0"/>
-                <LookupListIndex value="2"/>
-              </SubstLookupRecord>
-            </SubRule>
-          </SubRuleSet>
-        </ContextSubst>
+          </InputCoverage>
+          <!-- LookAheadGlyphCount=0 -->
+          <!-- SubstCount=1 -->
+          <SubstLookupRecord index="0">
+            <SequenceIndex value="0"/>
+            <LookupListIndex value="1"/>
+          </SubstLookupRecord>
+        </ChainContextSubst>
+        <ChainContextSubst index="2" Format="3">
+          <!-- BacktrackGlyphCount=0 -->
+          <!-- InputGlyphCount=1 -->
+          <InputCoverage index="0">
+            <Glyph value="G"/>
+          </InputCoverage>
+          <!-- LookAheadGlyphCount=0 -->
+          <!-- SubstCount=1 -->
+          <SubstLookupRecord index="0">
+            <SequenceIndex value="0"/>
+            <LookupListIndex value="2"/>
+          </SubstLookupRecord>
+        </ChainContextSubst>
+        <ChainContextSubst index="3" Format="3">
+          <!-- BacktrackGlyphCount=0 -->
+          <!-- InputGlyphCount=1 -->
+          <InputCoverage index="0">
+            <Glyph value="H"/>
+          </InputCoverage>
+          <!-- LookAheadGlyphCount=0 -->
+          <!-- SubstCount=1 -->
+          <SubstLookupRecord index="0">
+            <SequenceIndex value="0"/>
+            <LookupListIndex value="2"/>
+          </SubstLookupRecord>
+        </ChainContextSubst>
       </Lookup>
       <Lookup index="1">
         <LookupType value="1"/>
diff --git a/Tests/feaLib/data/bug514.fea b/Tests/feaLib/data/bug514.fea
index 1ef5af6..26da865 100644
--- a/Tests/feaLib/data/bug514.fea
+++ b/Tests/feaLib/data/bug514.fea
@@ -5,7 +5,7 @@
 # makeotf produces {A:-40, B:-40, C:-40} and {A:-111, B:-40} which
 # is redundant. https://github.com/adobe-type-tools/afdko/issues/169
 feature test {
-    pos X [A - B]' -40 B' -40 A' -40 Y;
+    pos X [A-B]' -40 B' -40 A' -40 Y;
     pos X A' -111 Y;
-    pos X B' -40 A' -111 [A - C]' -40 Y;
+    pos X B' -40 A' -111 [A-C]' -40 Y;
 } test;
diff --git a/Tests/feaLib/data/bug633.ttx b/Tests/feaLib/data/bug633.ttx
index 075c177..b119ebb 100644
--- a/Tests/feaLib/data/bug633.ttx
+++ b/Tests/feaLib/data/bug633.ttx
@@ -52,7 +52,6 @@
           <!-- Class2Count=3 -->
           <Class1Record index="0">
             <Class2Record index="0">
-              <Value1 XAdvance="0"/>
             </Class2Record>
             <Class2Record index="1">
               <Value1 XAdvance="0"/>
diff --git a/Tests/feaLib/data/cid_range.fea b/Tests/feaLib/data/cid_range.fea
deleted file mode 100644
index 7a17aed..0000000
--- a/Tests/feaLib/data/cid_range.fea
+++ /dev/null
@@ -1,6 +0,0 @@
-# A CID range can be valid even if it is invalid as a glyph name range.
-# For example, [cid00800 - cid01001] is invalid.
-
-feature zero {
-  sub [\800 - \1001] by zero;
-} zero;
diff --git a/Tests/feaLib/data/cid_range.ttx b/Tests/feaLib/data/cid_range.ttx
deleted file mode 100644
index 48b502b..0000000
--- a/Tests/feaLib/data/cid_range.ttx
+++ /dev/null
@@ -1,244 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont>
-
-  <GSUB>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=1 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="zero"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="0"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=1 -->
-      <Lookup index="0">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="cid00800" out="zero"/>
-          <Substitution in="cid00801" out="zero"/>
-          <Substitution in="cid00802" out="zero"/>
-          <Substitution in="cid00803" out="zero"/>
-          <Substitution in="cid00804" out="zero"/>
-          <Substitution in="cid00805" out="zero"/>
-          <Substitution in="cid00806" out="zero"/>
-          <Substitution in="cid00807" out="zero"/>
-          <Substitution in="cid00808" out="zero"/>
-          <Substitution in="cid00809" out="zero"/>
-          <Substitution in="cid00810" out="zero"/>
-          <Substitution in="cid00811" out="zero"/>
-          <Substitution in="cid00812" out="zero"/>
-          <Substitution in="cid00813" out="zero"/>
-          <Substitution in="cid00814" out="zero"/>
-          <Substitution in="cid00815" out="zero"/>
-          <Substitution in="cid00816" out="zero"/>
-          <Substitution in="cid00817" out="zero"/>
-          <Substitution in="cid00818" out="zero"/>
-          <Substitution in="cid00819" out="zero"/>
-          <Substitution in="cid00820" out="zero"/>
-          <Substitution in="cid00821" out="zero"/>
-          <Substitution in="cid00822" out="zero"/>
-          <Substitution in="cid00823" out="zero"/>
-          <Substitution in="cid00824" out="zero"/>
-          <Substitution in="cid00825" out="zero"/>
-          <Substitution in="cid00826" out="zero"/>
-          <Substitution in="cid00827" out="zero"/>
-          <Substitution in="cid00828" out="zero"/>
-          <Substitution in="cid00829" out="zero"/>
-          <Substitution in="cid00830" out="zero"/>
-          <Substitution in="cid00831" out="zero"/>
-          <Substitution in="cid00832" out="zero"/>
-          <Substitution in="cid00833" out="zero"/>
-          <Substitution in="cid00834" out="zero"/>
-          <Substitution in="cid00835" out="zero"/>
-          <Substitution in="cid00836" out="zero"/>
-          <Substitution in="cid00837" out="zero"/>
-          <Substitution in="cid00838" out="zero"/>
-          <Substitution in="cid00839" out="zero"/>
-          <Substitution in="cid00840" out="zero"/>
-          <Substitution in="cid00841" out="zero"/>
-          <Substitution in="cid00842" out="zero"/>
-          <Substitution in="cid00843" out="zero"/>
-          <Substitution in="cid00844" out="zero"/>
-          <Substitution in="cid00845" out="zero"/>
-          <Substitution in="cid00846" out="zero"/>
-          <Substitution in="cid00847" out="zero"/>
-          <Substitution in="cid00848" out="zero"/>
-          <Substitution in="cid00849" out="zero"/>
-          <Substitution in="cid00850" out="zero"/>
-          <Substitution in="cid00851" out="zero"/>
-          <Substitution in="cid00852" out="zero"/>
-          <Substitution in="cid00853" out="zero"/>
-          <Substitution in="cid00854" out="zero"/>
-          <Substitution in="cid00855" out="zero"/>
-          <Substitution in="cid00856" out="zero"/>
-          <Substitution in="cid00857" out="zero"/>
-          <Substitution in="cid00858" out="zero"/>
-          <Substitution in="cid00859" out="zero"/>
-          <Substitution in="cid00860" out="zero"/>
-          <Substitution in="cid00861" out="zero"/>
-          <Substitution in="cid00862" out="zero"/>
-          <Substitution in="cid00863" out="zero"/>
-          <Substitution in="cid00864" out="zero"/>
-          <Substitution in="cid00865" out="zero"/>
-          <Substitution in="cid00866" out="zero"/>
-          <Substitution in="cid00867" out="zero"/>
-          <Substitution in="cid00868" out="zero"/>
-          <Substitution in="cid00869" out="zero"/>
-          <Substitution in="cid00870" out="zero"/>
-          <Substitution in="cid00871" out="zero"/>
-          <Substitution in="cid00872" out="zero"/>
-          <Substitution in="cid00873" out="zero"/>
-          <Substitution in="cid00874" out="zero"/>
-          <Substitution in="cid00875" out="zero"/>
-          <Substitution in="cid00876" out="zero"/>
-          <Substitution in="cid00877" out="zero"/>
-          <Substitution in="cid00878" out="zero"/>
-          <Substitution in="cid00879" out="zero"/>
-          <Substitution in="cid00880" out="zero"/>
-          <Substitution in="cid00881" out="zero"/>
-          <Substitution in="cid00882" out="zero"/>
-          <Substitution in="cid00883" out="zero"/>
-          <Substitution in="cid00884" out="zero"/>
-          <Substitution in="cid00885" out="zero"/>
-          <Substitution in="cid00886" out="zero"/>
-          <Substitution in="cid00887" out="zero"/>
-          <Substitution in="cid00888" out="zero"/>
-          <Substitution in="cid00889" out="zero"/>
-          <Substitution in="cid00890" out="zero"/>
-          <Substitution in="cid00891" out="zero"/>
-          <Substitution in="cid00892" out="zero"/>
-          <Substitution in="cid00893" out="zero"/>
-          <Substitution in="cid00894" out="zero"/>
-          <Substitution in="cid00895" out="zero"/>
-          <Substitution in="cid00896" out="zero"/>
-          <Substitution in="cid00897" out="zero"/>
-          <Substitution in="cid00898" out="zero"/>
-          <Substitution in="cid00899" out="zero"/>
-          <Substitution in="cid00900" out="zero"/>
-          <Substitution in="cid00901" out="zero"/>
-          <Substitution in="cid00902" out="zero"/>
-          <Substitution in="cid00903" out="zero"/>
-          <Substitution in="cid00904" out="zero"/>
-          <Substitution in="cid00905" out="zero"/>
-          <Substitution in="cid00906" out="zero"/>
-          <Substitution in="cid00907" out="zero"/>
-          <Substitution in="cid00908" out="zero"/>
-          <Substitution in="cid00909" out="zero"/>
-          <Substitution in="cid00910" out="zero"/>
-          <Substitution in="cid00911" out="zero"/>
-          <Substitution in="cid00912" out="zero"/>
-          <Substitution in="cid00913" out="zero"/>
-          <Substitution in="cid00914" out="zero"/>
-          <Substitution in="cid00915" out="zero"/>
-          <Substitution in="cid00916" out="zero"/>
-          <Substitution in="cid00917" out="zero"/>
-          <Substitution in="cid00918" out="zero"/>
-          <Substitution in="cid00919" out="zero"/>
-          <Substitution in="cid00920" out="zero"/>
-          <Substitution in="cid00921" out="zero"/>
-          <Substitution in="cid00922" out="zero"/>
-          <Substitution in="cid00923" out="zero"/>
-          <Substitution in="cid00924" out="zero"/>
-          <Substitution in="cid00925" out="zero"/>
-          <Substitution in="cid00926" out="zero"/>
-          <Substitution in="cid00927" out="zero"/>
-          <Substitution in="cid00928" out="zero"/>
-          <Substitution in="cid00929" out="zero"/>
-          <Substitution in="cid00930" out="zero"/>
-          <Substitution in="cid00931" out="zero"/>
-          <Substitution in="cid00932" out="zero"/>
-          <Substitution in="cid00933" out="zero"/>
-          <Substitution in="cid00934" out="zero"/>
-          <Substitution in="cid00935" out="zero"/>
-          <Substitution in="cid00936" out="zero"/>
-          <Substitution in="cid00937" out="zero"/>
-          <Substitution in="cid00938" out="zero"/>
-          <Substitution in="cid00939" out="zero"/>
-          <Substitution in="cid00940" out="zero"/>
-          <Substitution in="cid00941" out="zero"/>
-          <Substitution in="cid00942" out="zero"/>
-          <Substitution in="cid00943" out="zero"/>
-          <Substitution in="cid00944" out="zero"/>
-          <Substitution in="cid00945" out="zero"/>
-          <Substitution in="cid00946" out="zero"/>
-          <Substitution in="cid00947" out="zero"/>
-          <Substitution in="cid00948" out="zero"/>
-          <Substitution in="cid00949" out="zero"/>
-          <Substitution in="cid00950" out="zero"/>
-          <Substitution in="cid00951" out="zero"/>
-          <Substitution in="cid00952" out="zero"/>
-          <Substitution in="cid00953" out="zero"/>
-          <Substitution in="cid00954" out="zero"/>
-          <Substitution in="cid00955" out="zero"/>
-          <Substitution in="cid00956" out="zero"/>
-          <Substitution in="cid00957" out="zero"/>
-          <Substitution in="cid00958" out="zero"/>
-          <Substitution in="cid00959" out="zero"/>
-          <Substitution in="cid00960" out="zero"/>
-          <Substitution in="cid00961" out="zero"/>
-          <Substitution in="cid00962" out="zero"/>
-          <Substitution in="cid00963" out="zero"/>
-          <Substitution in="cid00964" out="zero"/>
-          <Substitution in="cid00965" out="zero"/>
-          <Substitution in="cid00966" out="zero"/>
-          <Substitution in="cid00967" out="zero"/>
-          <Substitution in="cid00968" out="zero"/>
-          <Substitution in="cid00969" out="zero"/>
-          <Substitution in="cid00970" out="zero"/>
-          <Substitution in="cid00971" out="zero"/>
-          <Substitution in="cid00972" out="zero"/>
-          <Substitution in="cid00973" out="zero"/>
-          <Substitution in="cid00974" out="zero"/>
-          <Substitution in="cid00975" out="zero"/>
-          <Substitution in="cid00976" out="zero"/>
-          <Substitution in="cid00977" out="zero"/>
-          <Substitution in="cid00978" out="zero"/>
-          <Substitution in="cid00979" out="zero"/>
-          <Substitution in="cid00980" out="zero"/>
-          <Substitution in="cid00981" out="zero"/>
-          <Substitution in="cid00982" out="zero"/>
-          <Substitution in="cid00983" out="zero"/>
-          <Substitution in="cid00984" out="zero"/>
-          <Substitution in="cid00985" out="zero"/>
-          <Substitution in="cid00986" out="zero"/>
-          <Substitution in="cid00987" out="zero"/>
-          <Substitution in="cid00988" out="zero"/>
-          <Substitution in="cid00989" out="zero"/>
-          <Substitution in="cid00990" out="zero"/>
-          <Substitution in="cid00991" out="zero"/>
-          <Substitution in="cid00992" out="zero"/>
-          <Substitution in="cid00993" out="zero"/>
-          <Substitution in="cid00994" out="zero"/>
-          <Substitution in="cid00995" out="zero"/>
-          <Substitution in="cid00996" out="zero"/>
-          <Substitution in="cid00997" out="zero"/>
-          <Substitution in="cid00998" out="zero"/>
-          <Substitution in="cid00999" out="zero"/>
-          <Substitution in="cid01000" out="zero"/>
-          <Substitution in="cid01001" out="zero"/>
-        </SingleSubst>
-      </Lookup>
-    </LookupList>
-  </GSUB>
-
-</ttFont>
diff --git a/Tests/feaLib/data/delete_glyph.fea b/Tests/feaLib/data/delete_glyph.fea
deleted file mode 100644
index 36e0f0f..0000000
--- a/Tests/feaLib/data/delete_glyph.fea
+++ /dev/null
@@ -1,3 +0,0 @@
-feature test {
-	sub a by NULL;
-} test;
diff --git a/Tests/feaLib/data/delete_glyph.ttx b/Tests/feaLib/data/delete_glyph.ttx
deleted file mode 100644
index 777f6e3..0000000
--- a/Tests/feaLib/data/delete_glyph.ttx
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont>
-
-  <GSUB>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=1 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="test"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="0"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=1 -->
-      <Lookup index="0">
-        <LookupType value="2"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
-          <Substitution in="a" out=""/>
-        </MultipleSubst>
-      </Lookup>
-    </LookupList>
-  </GSUB>
-
-</ttFont>
diff --git a/Tests/feaLib/data/include/test.fea b/Tests/feaLib/data/include/test.fea
deleted file mode 100644
index 5eb5f68..0000000
--- a/Tests/feaLib/data/include/test.fea
+++ /dev/null
@@ -1 +0,0 @@
-include(../test.fea)
\ No newline at end of file
diff --git a/Tests/feaLib/data/include/test.ufo/features.fea b/Tests/feaLib/data/include/test.ufo/features.fea
deleted file mode 100644
index 41ccce3..0000000
--- a/Tests/feaLib/data/include/test.ufo/features.fea
+++ /dev/null
@@ -1 +0,0 @@
-include(test.fea)
diff --git a/Tests/feaLib/data/language_required.fea b/Tests/feaLib/data/language_required.fea
index 687c48a..4005a78 100644
--- a/Tests/feaLib/data/language_required.fea
+++ b/Tests/feaLib/data/language_required.fea
@@ -18,5 +18,5 @@
 } liga;
 
 feature scmp {
-  sub [a - z] by [A.sc - Z.sc];
+  sub [a-z] by [A.sc-Z.sc];
 } scmp;
diff --git a/Tests/feaLib/data/lookup-debug.ttx b/Tests/feaLib/data/lookup-debug.ttx
deleted file mode 100644
index f869617..0000000
--- a/Tests/feaLib/data/lookup-debug.ttx
+++ /dev/null
@@ -1,80 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont>
-
-  <GSUB>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=4 -->
-            <FeatureIndex index="0" value="0"/>
-            <FeatureIndex index="1" value="1"/>
-            <FeatureIndex index="2" value="2"/>
-            <FeatureIndex index="3" value="3"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=4 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="tst1"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="0"/>
-        </Feature>
-      </FeatureRecord>
-      <FeatureRecord index="1">
-        <FeatureTag value="tst2"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="0"/>
-        </Feature>
-      </FeatureRecord>
-      <FeatureRecord index="2">
-        <FeatureTag value="tst3"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="1"/>
-        </Feature>
-      </FeatureRecord>
-      <FeatureRecord index="3">
-        <FeatureTag value="tst4"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="1"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=2 -->
-      <!-- SomeLookup: __PATH__:4:5 in tst2 (DFLT/dflt) -->
-      <Lookup index="0">
-        <LookupType value="4"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
-          <LigatureSet glyph="f">
-            <Ligature components="f,i" glyph="f_f_i"/>
-            <Ligature components="i" glyph="f_i"/>
-          </LigatureSet>
-        </LigatureSubst>
-      </Lookup>
-      <!-- EmbeddedLookup: __PATH__:18:9 in tst4 (DFLT/dflt) -->
-      <Lookup index="1">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="A" out="A.sc"/>
-        </SingleSubst>
-      </Lookup>
-    </LookupList>
-  </GSUB>
-
-</ttFont>
diff --git a/Tests/feaLib/data/lookupflag.fea b/Tests/feaLib/data/lookupflag.fea
index 0210ab4..651dcd0 100644
--- a/Tests/feaLib/data/lookupflag.fea
+++ b/Tests/feaLib/data/lookupflag.fea
@@ -95,65 +95,3 @@
     lookup M;
     lookup N;
 } test;
-
-feature test {
-    lookupflag IgnoreMarks;
-    lookup O {
-        pos one 1;
-    } O;
-    lookup P {
-       pos one 1;
-    } P;
-} test;
-
-feature test {
-    lookup Q {
-         pos one 1;
-    } Q;
-    lookup R {
-         pos one 1;
-    } R;
-} test;
-
-feature test {
-    lookup S {
-        lookupflag IgnoreMarks;
-        pos one 1;
-    } S;
-    lookup T {
-        pos one 1;
-    } T;
-} test;
-
-feature test {
-    lookup U {
-        pos one 1;
-    } U;
-    lookup V {
-        lookupflag IgnoreMarks;
-        pos one 1;
-    } V;
-} test;
-
-feature test {
-    lookup W {
-        lookupflag IgnoreMarks;
-        script latn;
-        pos one 1;
-    } W;
-    lookup X {
-        lookupflag IgnoreMarks;
-        script latn;
-        pos two 2;
-    } X;
-} test;
-
-lookup Y {
-    lookupflag UseMarkFilteringSet [acute grave macron];
-    pos Y 1;
-} Y;
-
-lookup Z {
-    lookupflag MarkAttachmentType [acute grave macron];
-    pos Z 1;
-} Z;
diff --git a/Tests/feaLib/data/lookupflag.ttx b/Tests/feaLib/data/lookupflag.ttx
index 16ea751..bb05b9a 100644
--- a/Tests/feaLib/data/lookupflag.ttx
+++ b/Tests/feaLib/data/lookupflag.ttx
@@ -43,7 +43,7 @@
   <GPOS>
     <Version value="0x00010000"/>
     <ScriptList>
-      <!-- ScriptCount=2 -->
+      <!-- ScriptCount=1 -->
       <ScriptRecord index="0">
         <ScriptTag value="DFLT"/>
         <Script>
@@ -55,24 +55,13 @@
           <!-- LangSysCount=0 -->
         </Script>
       </ScriptRecord>
-      <ScriptRecord index="1">
-        <ScriptTag value="latn"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="1"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
     </ScriptList>
     <FeatureList>
-      <!-- FeatureCount=2 -->
+      <!-- FeatureCount=1 -->
       <FeatureRecord index="0">
         <FeatureTag value="test"/>
         <Feature>
-          <!-- LookupCount=22 -->
+          <!-- LookupCount=14 -->
           <LookupListIndex index="0" value="0"/>
           <LookupListIndex index="1" value="1"/>
           <LookupListIndex index="2" value="2"/>
@@ -87,30 +76,14 @@
           <LookupListIndex index="11" value="11"/>
           <LookupListIndex index="12" value="12"/>
           <LookupListIndex index="13" value="13"/>
-          <LookupListIndex index="14" value="14"/>
-          <LookupListIndex index="15" value="15"/>
-          <LookupListIndex index="16" value="16"/>
-          <LookupListIndex index="17" value="17"/>
-          <LookupListIndex index="18" value="18"/>
-          <LookupListIndex index="19" value="19"/>
-          <LookupListIndex index="20" value="20"/>
-          <LookupListIndex index="21" value="21"/>
-        </Feature>
-      </FeatureRecord>
-      <FeatureRecord index="1">
-        <FeatureTag value="test"/>
-        <Feature>
-          <!-- LookupCount=2 -->
-          <LookupListIndex index="0" value="22"/>
-          <LookupListIndex index="1" value="23"/>
         </Feature>
       </FeatureRecord>
     </FeatureList>
     <LookupList>
-      <!-- LookupCount=26 -->
+      <!-- LookupCount=14 -->
       <Lookup index="0">
         <LookupType value="1"/>
-        <LookupFlag value="1"/><!-- rightToLeft -->
+        <LookupFlag value="1"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
           <Coverage>
@@ -122,7 +95,7 @@
       </Lookup>
       <Lookup index="1">
         <LookupType value="1"/>
-        <LookupFlag value="2"/><!-- ignoreBaseGlyphs -->
+        <LookupFlag value="2"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
           <Coverage>
@@ -134,7 +107,7 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="1"/>
-        <LookupFlag value="4"/><!-- ignoreLigatures -->
+        <LookupFlag value="4"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
           <Coverage>
@@ -146,7 +119,7 @@
       </Lookup>
       <Lookup index="3">
         <LookupType value="1"/>
-        <LookupFlag value="7"/><!-- rightToLeft ignoreBaseGlyphs ignoreLigatures -->
+        <LookupFlag value="7"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
           <Coverage>
@@ -158,7 +131,7 @@
       </Lookup>
       <Lookup index="4">
         <LookupType value="1"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
           <Coverage>
@@ -170,7 +143,7 @@
       </Lookup>
       <Lookup index="5">
         <LookupType value="1"/>
-        <LookupFlag value="256"/><!-- markAttachmentType[1] -->
+        <LookupFlag value="256"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
           <Coverage>
@@ -182,7 +155,7 @@
       </Lookup>
       <Lookup index="6">
         <LookupType value="1"/>
-        <LookupFlag value="512"/><!-- markAttachmentType[2] -->
+        <LookupFlag value="512"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
           <Coverage>
@@ -194,7 +167,7 @@
       </Lookup>
       <Lookup index="7">
         <LookupType value="1"/>
-        <LookupFlag value="260"/><!-- ignoreLigatures markAttachmentType[1] -->
+        <LookupFlag value="260"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
           <Coverage>
@@ -206,7 +179,7 @@
       </Lookup>
       <Lookup index="8">
         <LookupType value="1"/>
-        <LookupFlag value="16"/><!-- useMarkFilteringSet -->
+        <LookupFlag value="16"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
           <Coverage>
@@ -219,7 +192,7 @@
       </Lookup>
       <Lookup index="9">
         <LookupType value="1"/>
-        <LookupFlag value="16"/><!-- useMarkFilteringSet -->
+        <LookupFlag value="16"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
           <Coverage>
@@ -232,7 +205,7 @@
       </Lookup>
       <Lookup index="10">
         <LookupType value="1"/>
-        <LookupFlag value="20"/><!-- ignoreLigatures useMarkFilteringSet -->
+        <LookupFlag value="20"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
           <Coverage>
@@ -257,7 +230,7 @@
       </Lookup>
       <Lookup index="12">
         <LookupType value="1"/>
-        <LookupFlag value="16"/><!-- useMarkFilteringSet -->
+        <LookupFlag value="16"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
           <Coverage>
@@ -270,7 +243,7 @@
       </Lookup>
       <Lookup index="13">
         <LookupType value="1"/>
-        <LookupFlag value="768"/><!-- markAttachmentType[3] -->
+        <LookupFlag value="768"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
           <Coverage>
@@ -280,151 +253,6 @@
           <Value XAdvance="1"/>
         </SinglePos>
       </Lookup>
-      <Lookup index="14">
-        <LookupType value="1"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
-        <!-- SubTableCount=1 -->
-        <SinglePos index="0" Format="1">
-          <Coverage>
-            <Glyph value="one"/>
-          </Coverage>
-          <ValueFormat value="4"/>
-          <Value XAdvance="1"/>
-        </SinglePos>
-      </Lookup>
-      <Lookup index="15">
-        <LookupType value="1"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
-        <!-- SubTableCount=1 -->
-        <SinglePos index="0" Format="1">
-          <Coverage>
-            <Glyph value="one"/>
-          </Coverage>
-          <ValueFormat value="4"/>
-          <Value XAdvance="1"/>
-        </SinglePos>
-      </Lookup>
-      <Lookup index="16">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SinglePos index="0" Format="1">
-          <Coverage>
-            <Glyph value="one"/>
-          </Coverage>
-          <ValueFormat value="4"/>
-          <Value XAdvance="1"/>
-        </SinglePos>
-      </Lookup>
-      <Lookup index="17">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SinglePos index="0" Format="1">
-          <Coverage>
-            <Glyph value="one"/>
-          </Coverage>
-          <ValueFormat value="4"/>
-          <Value XAdvance="1"/>
-        </SinglePos>
-      </Lookup>
-      <Lookup index="18">
-        <LookupType value="1"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
-        <!-- SubTableCount=1 -->
-        <SinglePos index="0" Format="1">
-          <Coverage>
-            <Glyph value="one"/>
-          </Coverage>
-          <ValueFormat value="4"/>
-          <Value XAdvance="1"/>
-        </SinglePos>
-      </Lookup>
-      <Lookup index="19">
-        <LookupType value="1"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
-        <!-- SubTableCount=1 -->
-        <SinglePos index="0" Format="1">
-          <Coverage>
-            <Glyph value="one"/>
-          </Coverage>
-          <ValueFormat value="4"/>
-          <Value XAdvance="1"/>
-        </SinglePos>
-      </Lookup>
-      <Lookup index="20">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SinglePos index="0" Format="1">
-          <Coverage>
-            <Glyph value="one"/>
-          </Coverage>
-          <ValueFormat value="4"/>
-          <Value XAdvance="1"/>
-        </SinglePos>
-      </Lookup>
-      <Lookup index="21">
-        <LookupType value="1"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
-        <!-- SubTableCount=1 -->
-        <SinglePos index="0" Format="1">
-          <Coverage>
-            <Glyph value="one"/>
-          </Coverage>
-          <ValueFormat value="4"/>
-          <Value XAdvance="1"/>
-        </SinglePos>
-      </Lookup>
-      <Lookup index="22">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SinglePos index="0" Format="1">
-          <Coverage>
-            <Glyph value="one"/>
-          </Coverage>
-          <ValueFormat value="4"/>
-          <Value XAdvance="1"/>
-        </SinglePos>
-      </Lookup>
-      <Lookup index="23">
-        <LookupType value="1"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
-        <!-- SubTableCount=1 -->
-        <SinglePos index="0" Format="1">
-          <Coverage>
-            <Glyph value="two"/>
-          </Coverage>
-          <ValueFormat value="4"/>
-          <Value XAdvance="2"/>
-        </SinglePos>
-      </Lookup>
-      <Lookup index="24">
-        <LookupType value="1"/>
-        <LookupFlag value="16"/><!-- useMarkFilteringSet -->
-        <!-- SubTableCount=1 -->
-        <SinglePos index="0" Format="1">
-          <Coverage>
-            <Glyph value="Y"/>
-          </Coverage>
-          <ValueFormat value="4"/>
-          <Value XAdvance="1"/>
-        </SinglePos>
-        <MarkFilteringSet value="0"/>
-      </Lookup>
-      <Lookup index="25">
-        <LookupType value="1"/>
-        <LookupFlag value="256"/><!-- markAttachmentType[1] -->
-        <!-- SubTableCount=1 -->
-        <SinglePos index="0" Format="1">
-          <Coverage>
-            <Glyph value="Z"/>
-          </Coverage>
-          <ValueFormat value="4"/>
-          <Value XAdvance="1"/>
-        </SinglePos>
-      </Lookup>
     </LookupList>
   </GPOS>
 
diff --git a/Tests/feaLib/data/size2.ttx b/Tests/feaLib/data/size2.ttx
index 1a12ddf..a822af3 100644
--- a/Tests/feaLib/data/size2.ttx
+++ b/Tests/feaLib/data/size2.ttx
@@ -26,8 +26,8 @@
             <DesignSize value="10.0"/>
             <SubfamilyID value="0"/>
             <SubfamilyNameID value="0"/>
-            <RangeStart value="0.0"/>
-            <RangeEnd value="0.0"/>
+            <RangeStart value="0"/>
+            <RangeEnd value="0"/>
           </FeatureParamsSize>
           <!-- LookupCount=0 -->
         </Feature>
diff --git a/Tests/feaLib/data/spec4h1.fea b/Tests/feaLib/data/spec4h1.fea
index a3d2494..b43e13b 100644
--- a/Tests/feaLib/data/spec4h1.fea
+++ b/Tests/feaLib/data/spec4h1.fea
@@ -8,7 +8,7 @@
 languagesystem cyrl dflt;
 
 feature smcp {
-    sub [a - z] by [A.sc - Z.sc];
+    sub [a-z] by [A.sc-Z.sc];
 
     # Since all the rules in this feature are of the same type, they
     # will be grouped in a single lookup.  Since no script or language
diff --git a/Tests/feaLib/data/spec5f_ii_2.fea b/Tests/feaLib/data/spec5f_ii_2.fea
index 916f797..b20a74c 100644
--- a/Tests/feaLib/data/spec5f_ii_2.fea
+++ b/Tests/feaLib/data/spec5f_ii_2.fea
@@ -3,7 +3,7 @@
 # http://www.adobe.com/devnet/opentype/afdko/topic_feature_file_syntax.html
 
 feature test {
-    @LETTER = [a - z];
+    @LETTER = [a-z];
     ignore sub @LETTER f' i';
     sub f' i' by f_i.begin;
 } test;
diff --git a/Tests/feaLib/data/spec5f_ii_3.fea b/Tests/feaLib/data/spec5f_ii_3.fea
index af06770..5fd1991 100644
--- a/Tests/feaLib/data/spec5f_ii_3.fea
+++ b/Tests/feaLib/data/spec5f_ii_3.fea
@@ -3,7 +3,7 @@
 # http://www.adobe.com/devnet/opentype/afdko/topic_feature_file_syntax.html
 
 feature test {
-    @LETTER = [a - z];
+    @LETTER = [a-z];
     ignore sub @LETTER a' n' d', a' n' d' @LETTER;
     sub a' n' d' by a_n_d;
 } test;
diff --git a/Tests/feaLib/data/spec5f_ii_3.ttx b/Tests/feaLib/data/spec5f_ii_3.ttx
index a94efce..a550f0b 100644
--- a/Tests/feaLib/data/spec5f_ii_3.ttx
+++ b/Tests/feaLib/data/spec5f_ii_3.ttx
@@ -32,115 +32,111 @@
       <Lookup index="0">
         <LookupType value="6"/>
         <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <ChainContextSubst index="0" Format="2">
-          <Coverage>
+        <!-- SubTableCount=3 -->
+        <ChainContextSubst index="0" Format="3">
+          <!-- BacktrackGlyphCount=1 -->
+          <BacktrackCoverage index="0">
             <Glyph value="a"/>
-          </Coverage>
-          <BacktrackClassDef>
-            <ClassDef glyph="a" class="1"/>
-            <ClassDef glyph="b" class="1"/>
-            <ClassDef glyph="c" class="1"/>
-            <ClassDef glyph="d" class="1"/>
-            <ClassDef glyph="e" class="1"/>
-            <ClassDef glyph="f" class="1"/>
-            <ClassDef glyph="g" class="1"/>
-            <ClassDef glyph="h" class="1"/>
-            <ClassDef glyph="i" class="1"/>
-            <ClassDef glyph="j" class="1"/>
-            <ClassDef glyph="k" class="1"/>
-            <ClassDef glyph="l" class="1"/>
-            <ClassDef glyph="m" class="1"/>
-            <ClassDef glyph="n" class="1"/>
-            <ClassDef glyph="o" class="1"/>
-            <ClassDef glyph="p" class="1"/>
-            <ClassDef glyph="q" class="1"/>
-            <ClassDef glyph="r" class="1"/>
-            <ClassDef glyph="s" class="1"/>
-            <ClassDef glyph="t" class="1"/>
-            <ClassDef glyph="u" class="1"/>
-            <ClassDef glyph="v" class="1"/>
-            <ClassDef glyph="w" class="1"/>
-            <ClassDef glyph="x" class="1"/>
-            <ClassDef glyph="y" class="1"/>
-            <ClassDef glyph="z" class="1"/>
-          </BacktrackClassDef>
-          <InputClassDef>
-            <ClassDef glyph="a" class="3"/>
-            <ClassDef glyph="d" class="2"/>
-            <ClassDef glyph="n" class="1"/>
-          </InputClassDef>
-          <LookAheadClassDef>
-            <ClassDef glyph="a" class="1"/>
-            <ClassDef glyph="b" class="1"/>
-            <ClassDef glyph="c" class="1"/>
-            <ClassDef glyph="d" class="1"/>
-            <ClassDef glyph="e" class="1"/>
-            <ClassDef glyph="f" class="1"/>
-            <ClassDef glyph="g" class="1"/>
-            <ClassDef glyph="h" class="1"/>
-            <ClassDef glyph="i" class="1"/>
-            <ClassDef glyph="j" class="1"/>
-            <ClassDef glyph="k" class="1"/>
-            <ClassDef glyph="l" class="1"/>
-            <ClassDef glyph="m" class="1"/>
-            <ClassDef glyph="n" class="1"/>
-            <ClassDef glyph="o" class="1"/>
-            <ClassDef glyph="p" class="1"/>
-            <ClassDef glyph="q" class="1"/>
-            <ClassDef glyph="r" class="1"/>
-            <ClassDef glyph="s" class="1"/>
-            <ClassDef glyph="t" class="1"/>
-            <ClassDef glyph="u" class="1"/>
-            <ClassDef glyph="v" class="1"/>
-            <ClassDef glyph="w" class="1"/>
-            <ClassDef glyph="x" class="1"/>
-            <ClassDef glyph="y" class="1"/>
-            <ClassDef glyph="z" class="1"/>
-          </LookAheadClassDef>
-          <!-- ChainSubClassSetCount=4 -->
-          <ChainSubClassSet index="0">
-            <!-- ChainSubClassRuleCount=0 -->
-          </ChainSubClassSet>
-          <ChainSubClassSet index="1">
-            <!-- ChainSubClassRuleCount=0 -->
-          </ChainSubClassSet>
-          <ChainSubClassSet index="2">
-            <!-- ChainSubClassRuleCount=0 -->
-          </ChainSubClassSet>
-          <ChainSubClassSet index="3">
-            <!-- ChainSubClassRuleCount=3 -->
-            <ChainSubClassRule index="0">
-              <!-- BacktrackGlyphCount=1 -->
-              <Backtrack index="0" value="1"/>
-              <!-- InputGlyphCount=3 -->
-              <Input index="0" value="1"/>
-              <Input index="1" value="2"/>
-              <!-- LookAheadGlyphCount=0 -->
-              <!-- SubstCount=0 -->
-            </ChainSubClassRule>
-            <ChainSubClassRule index="1">
-              <!-- BacktrackGlyphCount=0 -->
-              <!-- InputGlyphCount=3 -->
-              <Input index="0" value="1"/>
-              <Input index="1" value="2"/>
-              <!-- LookAheadGlyphCount=1 -->
-              <LookAhead index="0" value="1"/>
-              <!-- SubstCount=0 -->
-            </ChainSubClassRule>
-            <ChainSubClassRule index="2">
-              <!-- BacktrackGlyphCount=0 -->
-              <!-- InputGlyphCount=3 -->
-              <Input index="0" value="1"/>
-              <Input index="1" value="2"/>
-              <!-- LookAheadGlyphCount=0 -->
-              <!-- SubstCount=1 -->
-              <SubstLookupRecord index="0">
-                <SequenceIndex value="0"/>
-                <LookupListIndex value="1"/>
-              </SubstLookupRecord>
-            </ChainSubClassRule>
-          </ChainSubClassSet>
+            <Glyph value="b"/>
+            <Glyph value="c"/>
+            <Glyph value="d"/>
+            <Glyph value="e"/>
+            <Glyph value="f"/>
+            <Glyph value="g"/>
+            <Glyph value="h"/>
+            <Glyph value="i"/>
+            <Glyph value="j"/>
+            <Glyph value="k"/>
+            <Glyph value="l"/>
+            <Glyph value="m"/>
+            <Glyph value="n"/>
+            <Glyph value="o"/>
+            <Glyph value="p"/>
+            <Glyph value="q"/>
+            <Glyph value="r"/>
+            <Glyph value="s"/>
+            <Glyph value="t"/>
+            <Glyph value="u"/>
+            <Glyph value="v"/>
+            <Glyph value="w"/>
+            <Glyph value="x"/>
+            <Glyph value="y"/>
+            <Glyph value="z"/>
+          </BacktrackCoverage>
+          <!-- InputGlyphCount=3 -->
+          <InputCoverage index="0">
+            <Glyph value="a"/>
+          </InputCoverage>
+          <InputCoverage index="1">
+            <Glyph value="n"/>
+          </InputCoverage>
+          <InputCoverage index="2">
+            <Glyph value="d"/>
+          </InputCoverage>
+          <!-- LookAheadGlyphCount=0 -->
+          <!-- SubstCount=0 -->
+        </ChainContextSubst>
+        <ChainContextSubst index="1" Format="3">
+          <!-- BacktrackGlyphCount=0 -->
+          <!-- InputGlyphCount=3 -->
+          <InputCoverage index="0">
+            <Glyph value="a"/>
+          </InputCoverage>
+          <InputCoverage index="1">
+            <Glyph value="n"/>
+          </InputCoverage>
+          <InputCoverage index="2">
+            <Glyph value="d"/>
+          </InputCoverage>
+          <!-- LookAheadGlyphCount=1 -->
+          <LookAheadCoverage index="0">
+            <Glyph value="a"/>
+            <Glyph value="b"/>
+            <Glyph value="c"/>
+            <Glyph value="d"/>
+            <Glyph value="e"/>
+            <Glyph value="f"/>
+            <Glyph value="g"/>
+            <Glyph value="h"/>
+            <Glyph value="i"/>
+            <Glyph value="j"/>
+            <Glyph value="k"/>
+            <Glyph value="l"/>
+            <Glyph value="m"/>
+            <Glyph value="n"/>
+            <Glyph value="o"/>
+            <Glyph value="p"/>
+            <Glyph value="q"/>
+            <Glyph value="r"/>
+            <Glyph value="s"/>
+            <Glyph value="t"/>
+            <Glyph value="u"/>
+            <Glyph value="v"/>
+            <Glyph value="w"/>
+            <Glyph value="x"/>
+            <Glyph value="y"/>
+            <Glyph value="z"/>
+          </LookAheadCoverage>
+          <!-- SubstCount=0 -->
+        </ChainContextSubst>
+        <ChainContextSubst index="2" Format="3">
+          <!-- BacktrackGlyphCount=0 -->
+          <!-- InputGlyphCount=3 -->
+          <InputCoverage index="0">
+            <Glyph value="a"/>
+          </InputCoverage>
+          <InputCoverage index="1">
+            <Glyph value="n"/>
+          </InputCoverage>
+          <InputCoverage index="2">
+            <Glyph value="d"/>
+          </InputCoverage>
+          <!-- LookAheadGlyphCount=0 -->
+          <!-- SubstCount=1 -->
+          <SubstLookupRecord index="0">
+            <SequenceIndex value="0"/>
+            <LookupListIndex value="1"/>
+          </SubstLookupRecord>
         </ChainContextSubst>
       </Lookup>
       <Lookup index="1">
diff --git a/Tests/feaLib/data/spec5f_ii_4.fea b/Tests/feaLib/data/spec5f_ii_4.fea
index bc6fda4..731a1f6 100644
--- a/Tests/feaLib/data/spec5f_ii_4.fea
+++ b/Tests/feaLib/data/spec5f_ii_4.fea
@@ -2,13 +2,13 @@
 # "Specifying exceptions to the Chain Sub rule"
 # http://www.adobe.com/devnet/opentype/afdko/topic_feature_file_syntax.html
 
-@LETTER = [A - Z a - z];
+@LETTER = [A-Z a-z];
 
 feature cswh {
 
     # --- Glyph classes used in this feature:
-    @BEGINNINGS = [A - N P - Z T_h m];
-    @BEGINNINGS_SWASH = [A.swash - N.swash P.swash - Z.swash T_h.swash m.begin];
+    @BEGINNINGS = [A-N P-Z T_h m];
+    @BEGINNINGS_SWASH = [A.swash-N.swash P.swash-Z.swash T_h.swash m.begin];
     @ENDINGS = [a e z];
     @ENDINGS_SWASH = [a.end e.end z.end];
 
diff --git a/Tests/feaLib/data/spec5fi2.ttx b/Tests/feaLib/data/spec5fi2.ttx
index 6485c34..0842cf9 100644
--- a/Tests/feaLib/data/spec5fi2.ttx
+++ b/Tests/feaLib/data/spec5fi2.ttx
@@ -31,7 +31,7 @@
       <!-- LookupCount=2 -->
       <Lookup index="0">
         <LookupType value="6"/>
-        <LookupFlag value="7"/><!-- rightToLeft ignoreBaseGlyphs ignoreLigatures -->
+        <LookupFlag value="7"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="3">
           <!-- BacktrackGlyphCount=1 -->
@@ -54,7 +54,7 @@
       </Lookup>
       <Lookup index="1">
         <LookupType value="1"/>
-        <LookupFlag value="7"/><!-- rightToLeft ignoreBaseGlyphs ignoreLigatures -->
+        <LookupFlag value="7"/>
         <!-- SubTableCount=1 -->
         <SingleSubst index="0">
           <Substitution in="d" out="d.alt"/>
diff --git a/Tests/feaLib/data/spec5fi3.fea b/Tests/feaLib/data/spec5fi3.fea
index e44a732..e47a6f8 100644
--- a/Tests/feaLib/data/spec5fi3.fea
+++ b/Tests/feaLib/data/spec5fi3.fea
@@ -5,5 +5,5 @@
 languagesystem latn dflt;
 
 feature test {
-    sub [A - Z] [A.sc - Z.sc]' by [a - z];
+    sub [A-Z] [A.sc-Z.sc]' by [a-z];
 } test;
diff --git a/Tests/feaLib/data/spec6b_ii.ttx b/Tests/feaLib/data/spec6b_ii.ttx
index c7b8de8..a7131de 100644
--- a/Tests/feaLib/data/spec6b_ii.ttx
+++ b/Tests/feaLib/data/spec6b_ii.ttx
@@ -91,7 +91,6 @@
           <!-- Class2Count=2 -->
           <Class1Record index="0">
             <Class2Record index="0">
-              <Value1 XAdvance="0"/>
             </Class2Record>
             <Class2Record index="1">
               <Value1 XAdvance="-100"/>
diff --git a/Tests/feaLib/data/spec6d2.fea b/Tests/feaLib/data/spec6d2.fea
index 5c2620d..ead224f 100644
--- a/Tests/feaLib/data/spec6d2.fea
+++ b/Tests/feaLib/data/spec6d2.fea
@@ -9,11 +9,7 @@
 markClass [cedilla] <anchor 300 600> @BOTTOM_MARKS;
 
 feature test {
-    pos base [e o]
-        <anchor 250 450> mark @TOP_MARKS
-        <anchor 250 -12> mark @BOTTOM_MARKS;
-#test-fea2fea: pos base [a u]
-    position base [a u]
-        <anchor 265 450> mark @TOP_MARKS
-        <anchor 250 -10> mark @BOTTOM_MARKS;
+    pos base [e o] <anchor 250 450> mark @TOP_MARKS <anchor 250 -12> mark @BOTTOM_MARKS;
+#test-fea2fea: pos base [a u] <anchor 265 450> mark @TOP_MARKS <anchor 250 -10> mark @BOTTOM_MARKS;
+    position base [a u] <anchor 265 450> mark @TOP_MARKS <anchor 250-10> mark @BOTTOM_MARKS;
 } test;
diff --git a/Tests/feaLib/data/spec6e.fea b/Tests/feaLib/data/spec6e.fea
index 6461223..ed956c8 100644
--- a/Tests/feaLib/data/spec6e.fea
+++ b/Tests/feaLib/data/spec6e.fea
@@ -4,10 +4,7 @@
 markClass kasratan <anchor 346 -98> @BOTTOM_MARKS;
 
 feature test {
-    pos ligature lam_meem_jeem
-            <anchor 625 1800> mark @TOP_MARKS    # mark above lam
-        ligComponent
-            <anchor 376 -368> mark @BOTTOM_MARKS    # mark below meem
-        ligComponent
-            <anchor NULL>;   # jeem has no marks
+    pos ligature lam_meem_jeem <anchor 625 1800> mark @TOP_MARKS    # mark above lam
+        ligComponent <anchor 376 -368> mark @BOTTOM_MARKS    # mark below meem
+        ligComponent <anchor NULL>;   # jeem has no marks
 } test;
diff --git a/Tests/feaLib/data/spec6f.fea b/Tests/feaLib/data/spec6f.fea
index 277bdb4..8d32008 100644
--- a/Tests/feaLib/data/spec6f.fea
+++ b/Tests/feaLib/data/spec6f.fea
@@ -2,6 +2,5 @@
 
 feature test {
     markClass damma <anchor 189 -103> @MARK_CLASS_1;
-    pos mark hamza
-        <anchor 221 301> mark @MARK_CLASS_1;
+    pos mark hamza <anchor 221 301> mark @MARK_CLASS_1;
 } test;
diff --git a/Tests/feaLib/data/spec6h_ii.fea b/Tests/feaLib/data/spec6h_ii.fea
index 690d2a3..36a1f03 100644
--- a/Tests/feaLib/data/spec6h_ii.fea
+++ b/Tests/feaLib/data/spec6h_ii.fea
@@ -12,10 +12,8 @@
 } CNTXT_PAIR_POS;
  
 lookup CNTXT_MARK_TO_BASE {
-    pos base o
-        <anchor 250 450> mark @ALL_MARKS;
-    pos base c
-        <anchor 250 450> mark @ALL_MARKS;
+    pos base o <anchor 250 450> mark @ALL_MARKS;
+    pos base c <anchor 250 450> mark @ALL_MARKS;
 } CNTXT_MARK_TO_BASE;
 
 feature test {
diff --git a/Tests/feaLib/data/spec6h_ii.ttx b/Tests/feaLib/data/spec6h_ii.ttx
index 2f0efc6..e8ec85f 100644
--- a/Tests/feaLib/data/spec6h_ii.ttx
+++ b/Tests/feaLib/data/spec6h_ii.ttx
@@ -112,23 +112,25 @@
         </MarkBasePos>
       </Lookup>
       <Lookup index="2">
-        <LookupType value="7"/>
+        <LookupType value="8"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <ContextPos index="0" Format="3">
-          <!-- GlyphCount=3 -->
-          <!-- PosCount=2 -->
-          <Coverage index="0">
+        <ChainContextPos index="0" Format="3">
+          <!-- BacktrackGlyphCount=0 -->
+          <!-- InputGlyphCount=3 -->
+          <InputCoverage index="0">
             <Glyph value="T"/>
-          </Coverage>
-          <Coverage index="1">
+          </InputCoverage>
+          <InputCoverage index="1">
             <Glyph value="c"/>
             <Glyph value="o"/>
-          </Coverage>
-          <Coverage index="2">
+          </InputCoverage>
+          <InputCoverage index="2">
             <Glyph value="grave"/>
             <Glyph value="acute"/>
-          </Coverage>
+          </InputCoverage>
+          <!-- LookAheadGlyphCount=0 -->
+          <!-- PosCount=2 -->
           <PosLookupRecord index="0">
             <SequenceIndex value="0"/>
             <LookupListIndex value="0"/>
@@ -137,7 +139,7 @@
             <SequenceIndex value="2"/>
             <LookupListIndex value="1"/>
           </PosLookupRecord>
-        </ContextPos>
+        </ChainContextPos>
       </Lookup>
     </LookupList>
   </GPOS>
diff --git a/Tests/feaLib/data/spec6h_iii_3d.ttx b/Tests/feaLib/data/spec6h_iii_3d.ttx
index 2335dd0..a608f0e 100644
--- a/Tests/feaLib/data/spec6h_iii_3d.ttx
+++ b/Tests/feaLib/data/spec6h_iii_3d.ttx
@@ -30,23 +30,25 @@
     <LookupList>
       <!-- LookupCount=2 -->
       <Lookup index="0">
-        <LookupType value="7"/>
+        <LookupType value="8"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <ContextPos index="0" Format="3">
-          <!-- GlyphCount=2 -->
-          <!-- PosCount=1 -->
-          <Coverage index="0">
+        <ChainContextPos index="0" Format="3">
+          <!-- BacktrackGlyphCount=0 -->
+          <!-- InputGlyphCount=2 -->
+          <InputCoverage index="0">
             <Glyph value="L"/>
-          </Coverage>
-          <Coverage index="1">
+          </InputCoverage>
+          <InputCoverage index="1">
             <Glyph value="quoteright"/>
-          </Coverage>
+          </InputCoverage>
+          <!-- LookAheadGlyphCount=0 -->
+          <!-- PosCount=1 -->
           <PosLookupRecord index="0">
             <SequenceIndex value="1"/>
             <LookupListIndex value="1"/>
           </PosLookupRecord>
-        </ContextPos>
+        </ChainContextPos>
       </Lookup>
       <Lookup index="1">
         <LookupType value="1"/>
diff --git a/Tests/feaLib/data/spec8a.fea b/Tests/feaLib/data/spec8a.fea
index 4054821..b4d7dd2 100644
--- a/Tests/feaLib/data/spec8a.fea
+++ b/Tests/feaLib/data/spec8a.fea
@@ -10,7 +10,7 @@
 } aalt;
 
 feature smcp {
-    sub [a - c] by [A.sc - C.sc];
+    sub [a-c] by [A.sc-C.sc];
     sub f i by f_i;  # not considered for aalt
 } smcp;
 
diff --git a/Tests/feaLib/data/test.fea b/Tests/feaLib/data/test.fea
deleted file mode 100644
index c01ade2..0000000
--- a/Tests/feaLib/data/test.fea
+++ /dev/null
@@ -1 +0,0 @@
-# Nothing
diff --git a/Tests/feaLib/error_test.py b/Tests/feaLib/error_test.py
index 2ebb3e4..87cbecb 100644
--- a/Tests/feaLib/error_test.py
+++ b/Tests/feaLib/error_test.py
@@ -1,11 +1,12 @@
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
 from fontTools.feaLib.error import FeatureLibError
-from fontTools.feaLib.location import FeatureLibLocation
 import unittest
 
 
 class FeatureLibErrorTest(unittest.TestCase):
     def test_str(self):
-        err = FeatureLibError("Squeak!", FeatureLibLocation("foo.fea", 23, 42))
+        err = FeatureLibError("Squeak!", ("foo.fea", 23, 42))
         self.assertEqual(str(err), "foo.fea:23:42: Squeak!")
 
     def test_str_nolocation(self):
diff --git a/Tests/feaLib/lexer_test.py b/Tests/feaLib/lexer_test.py
index 24dc5db..1b28fa0 100644
--- a/Tests/feaLib/lexer_test.py
+++ b/Tests/feaLib/lexer_test.py
@@ -1,7 +1,8 @@
-from fontTools.misc.py23 import tobytes
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.feaLib.error import FeatureLibError, IncludedFeaNotFound
 from fontTools.feaLib.lexer import IncludingLexer, Lexer
-from io import StringIO
 import os
 import shutil
 import tempfile
@@ -68,9 +69,8 @@
     def test_number(self):
         self.assertEqual(lex("123 -456"),
                          [(Lexer.NUMBER, 123), (Lexer.NUMBER, -456)])
-        self.assertEqual(lex("0xCAFED00D"), [(Lexer.HEXADECIMAL, 0xCAFED00D)])
-        self.assertEqual(lex("0xcafed00d"), [(Lexer.HEXADECIMAL, 0xCAFED00D)])
-        self.assertEqual(lex("010"), [(Lexer.OCTAL, 0o10)])
+        self.assertEqual(lex("0xCAFED00D"), [(Lexer.NUMBER, 0xCAFED00D)])
+        self.assertEqual(lex("0xcafed00d"), [(Lexer.NUMBER, 0xCAFED00D)])
 
     def test_float(self):
         self.assertEqual(lex("1.23 -4.5"),
@@ -108,7 +108,7 @@
 
     def test_newline(self):
         def lines(s):
-            return [loc.line for (_, _, loc) in Lexer(s, "test.fea")]
+            return [loc[1] for (_, _, loc) in Lexer(s, "test.fea")]
         self.assertEqual(lines("FOO\n\nBAR\nBAZ"), [1, 3, 4])  # Unix
         self.assertEqual(lines("FOO\r\rBAR\rBAZ"), [1, 3, 4])  # Macintosh
         self.assertEqual(lines("FOO\r\n\r\n BAR\r\nBAZ"), [1, 3, 4])  # Windows
@@ -116,7 +116,7 @@
 
     def test_location(self):
         def locs(s):
-            return [str(loc) for (_, _, loc) in Lexer(s, "test.fea")]
+            return ["%s:%d:%d" % loc for (_, _, loc) in Lexer(s, "test.fea")]
         self.assertEqual(locs("a b # Comment\n12 @x"), [
             "test.fea:1:1", "test.fea:1:3", "test.fea:1:5", "test.fea:2:1",
             "test.fea:2:4"
@@ -151,7 +151,7 @@
 
     def test_include(self):
         lexer = IncludingLexer(self.getpath("include/include4.fea"))
-        result = ['%s %s:%d' % (token, os.path.split(loc.file)[1], loc.line)
+        result = ['%s %s:%d' % (token, os.path.split(loc[0])[1], loc[1])
                   for _, token, loc in lexer]
         self.assertEqual(result, [
             "I4a include4.fea:1",
@@ -179,15 +179,13 @@
     def test_include_missing_file(self):
         lexer = IncludingLexer(self.getpath("include/includemissingfile.fea"))
         self.assertRaisesRegex(IncludedFeaNotFound,
-                               "includemissingfile.fea:1:8: The following feature file "
-                               "should be included but cannot be found: "
-                               "missingfile.fea",
+                               "includemissingfile.fea:1:8: missingfile.fea",
                                lambda: list(lexer))
 
     def test_featurefilepath_None(self):
-        lexer = IncludingLexer(StringIO("# foobar"))
+        lexer = IncludingLexer(UnicodeIO("# foobar"))
         self.assertIsNone(lexer.featurefilepath)
-        files = set(loc.file for _, _, loc in lexer)
+        files = set(loc[0] for _, _, loc in lexer)
         self.assertIn("<features>", files)
 
     def test_include_absolute_path(self):
@@ -197,10 +195,10 @@
                     pos A B -40;
                 } kern;
                 """, encoding="utf-8"))
-        including = StringIO("include(%s);" % included.name)
+        including = UnicodeIO("include(%s);" % included.name)
         try:
             lexer = IncludingLexer(including)
-            files = set(loc.file for _, _, loc in lexer)
+            files = set(loc[0] for _, _, loc in lexer)
             self.assertIn(included.name, files)
         finally:
             os.remove(included.name)
@@ -225,8 +223,8 @@
             # itself have a path, because it was initialized from
             # an in-memory stream, so it will use the current working
             # directory to resolve relative include statements
-            lexer = IncludingLexer(StringIO("include(included.fea);"))
-            files = set(os.path.realpath(loc.file) for _, _, loc in lexer)
+            lexer = IncludingLexer(UnicodeIO("include(included.fea);"))
+            files = set(loc[0] for _, _, loc in lexer)
             expected = os.path.realpath(included.name)
             self.assertIn(expected, files)
         finally:
diff --git a/Tests/feaLib/parser_test.py b/Tests/feaLib/parser_test.py
index de2bc3c..9343495 100644
--- a/Tests/feaLib/parser_test.py
+++ b/Tests/feaLib/parser_test.py
@@ -1,8 +1,9 @@
 # -*- coding: utf-8 -*-
-from fontTools.misc.loggingTools import CapturingLogHandler
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
 from fontTools.feaLib.error import FeatureLibError
 from fontTools.feaLib.parser import Parser, SymbolTable
-from io import StringIO
+from fontTools.misc.py23 import *
 import warnings
 import fontTools.feaLib.ast as ast
 import os
@@ -40,14 +41,6 @@
     n.sc o.sc p.sc q.sc r.sc s.sc t.sc u.sc v.sc w.sc x.sc y.sc z.sc
     a.swash b.swash x.swash y.swash z.swash
     foobar foo.09 foo.1234 foo.9876
-    one two five six acute grave dieresis umlaut cedilla ogonek macron
-    a_f_f_i o_f_f_i f_i f_f_i one.fitted one.oldstyle a.1 a.2 a.3 c_t
-    PRE SUF FIX BACK TRACK LOOK AHEAD ampersand ampersand.1 ampersand.2
-    cid00001 cid00002 cid00003 cid00004 cid00005 cid00006 cid00007
-    cid12345 cid78987 cid00999 cid01000 cid01001 cid00998 cid00995
-    cid00111 cid00222
-    comma endash emdash figuredash damma hamza
-    c_d d.alt n.end s.end f_f
 """).split() + ["foo.%d" % i for i in range(1, 200)]
 
 
@@ -63,7 +56,7 @@
         glyphMap = {'a': 0, 'b': 1, 'c': 2}
         with warnings.catch_warnings(record=True) as w:
             warnings.simplefilter("always")
-            parser = Parser(StringIO(), glyphMap=glyphMap)
+            parser = Parser(UnicodeIO(), glyphMap=glyphMap)
 
             self.assertEqual(len(w), 1)
             self.assertEqual(w[-1].category, UserWarning)
@@ -72,11 +65,11 @@
 
             self.assertRaisesRegex(
                 TypeError, "mutually exclusive",
-                Parser, StringIO(), ("a",), glyphMap={"a": 0})
+                Parser, UnicodeIO(), ("a",), glyphMap={"a": 0})
 
             self.assertRaisesRegex(
                 TypeError, "unsupported keyword argument",
-                Parser, StringIO(), foo="bar")
+                Parser, UnicodeIO(), foo="bar")
 
     def test_comments(self):
         doc = self.parse(
@@ -269,12 +262,6 @@
             FeatureLibError, "Font revision numbers must be positive",
             self.parse, "table head {FontRevision -17.2;} head;")
 
-    def test_strict_glyph_name_check(self):
-        self.parse("@bad = [a b ccc];", glyphNames=("a", "b", "ccc"))
-
-        with self.assertRaisesRegex(FeatureLibError, "missing from the glyph set: ccc"):
-            self.parse("@bad = [a b ccc];", glyphNames=("a", "b"))
-
     def test_glyphclass(self):
         [gc] = self.parse("@dash = [endash emdash figuredash];").statements
         self.assertEqual(gc.name, "dash")
@@ -347,19 +334,6 @@
         [gc] = self.parse("@range = [A-foo.sc - C-foo.sc];", gn).statements
         self.assertEqual(gc.glyphSet(), ("A-foo.sc", "B-foo.sc", "C-foo.sc"))
 
-    def test_glyphclass_ambiguous_dash_no_glyph_names(self):
-        # If Parser is initialized without a glyphNames parameter (or with empty one)
-        # it cannot distinguish between a glyph name containing an hyphen, or a
-        # range of glyph names; thus it will interpret them as literal glyph names
-        # while also outputting a logging warning to alert user about the ambiguity.
-        # https://github.com/fonttools/fonttools/issues/1768
-        glyphNames = ()
-        with CapturingLogHandler("fontTools.feaLib.parser", level="WARNING") as caplog:
-            [gc] = self.parse("@class = [A-foo.sc B-foo.sc C D];", glyphNames).statements
-        self.assertEqual(gc.glyphSet(), ("A-foo.sc", "B-foo.sc", "C", "D"))
-        self.assertEqual(len(caplog.records), 2)
-        caplog.assertRegex("Ambiguous glyph name that looks like a range:")
-
     def test_glyphclass_glyph_name_should_win_over_range(self):
         # The OpenType Feature File Specification v1.20 makes it clear
         # that if a dashed name could be interpreted either as a glyph name
@@ -718,18 +692,6 @@
         self.assertEqual(flag.asFea(),
             "lookupflag RightToLeft MarkAttachmentType @TOP_MARKS;")
 
-    def test_lookupflag_format_A_MarkAttachmentType_glyphClass(self):
-        flag = self.parse_lookupflag_(
-            "lookupflag RightToLeft MarkAttachmentType [acute grave macron];")
-        self.assertIsInstance(flag, ast.LookupFlagStatement)
-        self.assertEqual(flag.value, 1)
-        self.assertIsInstance(flag.markAttachment, ast.GlyphClass)
-        self.assertEqual(flag.markAttachment.glyphSet(),
-                         ("acute", "grave", "macron"))
-        self.assertIsNone(flag.markFilteringSet)
-        self.assertEqual(flag.asFea(),
-            "lookupflag RightToLeft MarkAttachmentType [acute grave macron];")
-
     def test_lookupflag_format_A_UseMarkFilteringSet(self):
         flag = self.parse_lookupflag_(
             "@BOTTOM_MARKS = [cedilla ogonek];"
@@ -743,18 +705,6 @@
         self.assertEqual(flag.asFea(),
             "lookupflag IgnoreLigatures UseMarkFilteringSet @BOTTOM_MARKS;")
 
-    def test_lookupflag_format_A_UseMarkFilteringSet_glyphClass(self):
-        flag = self.parse_lookupflag_(
-            "lookupflag UseMarkFilteringSet [cedilla ogonek] IgnoreLigatures;")
-        self.assertIsInstance(flag, ast.LookupFlagStatement)
-        self.assertEqual(flag.value, 4)
-        self.assertIsNone(flag.markAttachment)
-        self.assertIsInstance(flag.markFilteringSet, ast.GlyphClass)
-        self.assertEqual(flag.markFilteringSet.glyphSet(),
-                         ("cedilla", "ogonek"))
-        self.assertEqual(flag.asFea(),
-            "lookupflag IgnoreLigatures UseMarkFilteringSet [cedilla ogonek];")
-
     def test_lookupflag_format_B(self):
         flag = self.parse_lookupflag_("lookupflag 7;")
         self.assertIsInstance(flag, ast.LookupFlagStatement)
@@ -1089,7 +1039,7 @@
         self.assertEqual(glyphstr(pos.prefix), "[A a] [B b]")
         self.assertEqual(glyphstr(pos.glyphs), "I [N n] P")
         self.assertEqual(glyphstr(pos.suffix), "[Y y] [Z z]")
-        self.assertEqual(pos.lookups, [[lookup1], [lookup2], None])
+        self.assertEqual(pos.lookups, [lookup1, lookup2, None])
 
     def test_gpos_type_8_lookup_with_values(self):
         self.assertRaisesRegex(
@@ -1169,36 +1119,6 @@
             FeatureLibError, "Expected platform id 1 or 3",
             self.parse, 'table name { nameid 9 666 "Foo"; } name;')
 
-    def test_nameid_hexadecimal(self):
-        doc = self.parse(
-            r'table name { nameid 0x9 0x3 0x1 0x0409 "Test"; } name;')
-        name = doc.statements[0].statements[0]
-        self.assertEqual(name.nameID, 9)
-        self.assertEqual(name.platformID, 3)
-        self.assertEqual(name.platEncID, 1)
-        self.assertEqual(name.langID, 0x0409)
-
-    def test_nameid_octal(self):
-        doc = self.parse(
-            r'table name { nameid 011 03 012 02011 "Test"; } name;')
-        name = doc.statements[0].statements[0]
-        self.assertEqual(name.nameID, 9)
-        self.assertEqual(name.platformID, 3)
-        self.assertEqual(name.platEncID, 10)
-        self.assertEqual(name.langID, 0o2011)
-
-    def test_cv_hexadecimal(self):
-        doc = self.parse(
-            r'feature cv01 { cvParameters { Character 0x5DDE; }; } cv01;')
-        cv = doc.statements[0].statements[0].statements[0]
-        self.assertEqual(cv.character, 0x5DDE)
-
-    def test_cv_octal(self):
-        doc = self.parse(
-            r'feature cv01 { cvParameters { Character 056736; }; } cv01;')
-        cv = doc.statements[0].statements[0].statements[0]
-        self.assertEqual(cv.character, 0o56736)
-
     def test_rsub_format_a(self):
         doc = self.parse("feature test {rsub a [b B] c' d [e E] by C;} test;")
         rsub = doc.statements[0].statements[0]
@@ -1280,76 +1200,6 @@
             '"dflt" is not a valid script tag; use "DFLT" instead',
             self.parse, "feature test {script dflt;} test;")
 
-    def test_stat_design_axis(self):  # STAT DesignAxis
-        doc = self.parse('table STAT { DesignAxis opsz 0 '
-                         '{name "Optical Size";}; } STAT;')
-        da = doc.statements[0].statements[0]
-        self.assertIsInstance(da, ast.STATDesignAxisStatement)
-        self.assertEqual(da.tag, 'opsz')
-        self.assertEqual(da.axisOrder, 0)
-        self.assertEqual(da.names[0].string, 'Optical Size')
-
-    def test_stat_axis_value_format1(self):  # STAT AxisValue
-        doc = self.parse('table STAT { DesignAxis opsz 0 '
-                         '{name "Optical Size";}; '
-                         'AxisValue {location opsz 8; name "Caption";}; } '
-                         'STAT;')
-        avr = doc.statements[0].statements[1]
-        self.assertIsInstance(avr, ast.STATAxisValueStatement)
-        self.assertEqual(avr.locations[0].tag, 'opsz')
-        self.assertEqual(avr.locations[0].values[0], 8)
-        self.assertEqual(avr.names[0].string, 'Caption')
-
-    def test_stat_axis_value_format2(self):  # STAT AxisValue
-        doc = self.parse('table STAT { DesignAxis opsz 0 '
-                         '{name "Optical Size";}; '
-                         'AxisValue {location opsz 8 6 10; name "Caption";}; } '
-                         'STAT;')
-        avr = doc.statements[0].statements[1]
-        self.assertIsInstance(avr, ast.STATAxisValueStatement)
-        self.assertEqual(avr.locations[0].tag, 'opsz')
-        self.assertEqual(avr.locations[0].values, [8, 6, 10])
-        self.assertEqual(avr.names[0].string, 'Caption')
-
-    def test_stat_axis_value_format2_bad_range(self):  # STAT AxisValue
-        self.assertRaisesRegex(
-            FeatureLibError,
-            'Default value 5 is outside of specified range 6-10.',
-            self.parse, 'table STAT { DesignAxis opsz 0 '
-                        '{name "Optical Size";}; '
-                        'AxisValue {location opsz 5 6 10; name "Caption";}; } '
-                        'STAT;')
-
-    def test_stat_axis_value_format4(self):  # STAT AxisValue
-        self.assertRaisesRegex(
-            FeatureLibError,
-            'Only one value is allowed in a Format 4 Axis Value Record, but 3 were found.',
-            self.parse, 'table STAT { '
-                         'DesignAxis opsz 0 {name "Optical Size";}; '
-                         'DesignAxis wdth 0 {name "Width";}; '
-                         'AxisValue {'
-                         'location opsz 8 6 10; '
-                         'location wdth 400; '
-                         'name "Caption";}; } '
-                         'STAT;')
-
-    def test_stat_elidedfallbackname(self):  # STAT ElidedFallbackName
-        doc = self.parse('table STAT { ElidedFallbackName {name "Roman"; '
-                         'name 3 1 0x0411 "ローマン"; }; '
-                         '} STAT;')
-        nameRecord = doc.statements[0].statements[0]
-        self.assertIsInstance(nameRecord, ast.ElidedFallbackName)
-        self.assertEqual(nameRecord.names[0].string, 'Roman')
-        self.assertEqual(nameRecord.names[1].string, 'ローマン')
-
-    def test_stat_elidedfallbacknameid(self):  # STAT ElidedFallbackNameID
-        doc = self.parse('table name { nameid 278 "Roman"; } name; '
-                         'table STAT { ElidedFallbackNameID 278; '
-                         '} STAT;')
-        nameRecord = doc.statements[0].statements[0]
-        self.assertIsInstance(nameRecord, ast.NameRecord)
-        self.assertEqual(nameRecord.string, 'Roman')
-
     def test_sub_single_format_a(self):  # GSUB LookupType 1
         doc = self.parse("feature smcp {substitute a by a.sc;} smcp;")
         sub = doc.statements[0].statements[0]
@@ -1518,22 +1368,12 @@
                          "  sub f_f   by f f;"
                          "  sub f     by f;"
                          "  sub f_f_i by f f i;"
-                         "  sub [a a.sc] by a;"
-                         "  sub [a a.sc] by [b b.sc];"
                          "} Look;")
         statements = doc.statements[0].statements
         for sub in statements:
             self.assertIsInstance(sub, ast.MultipleSubstStatement)
         self.assertEqual(statements[1].glyph, "f")
         self.assertEqual(statements[1].replacement, ["f"])
-        self.assertEqual(statements[3].glyph, "a")
-        self.assertEqual(statements[3].replacement, ["a"])
-        self.assertEqual(statements[4].glyph, "a.sc")
-        self.assertEqual(statements[4].replacement, ["a"])
-        self.assertEqual(statements[5].glyph, "a")
-        self.assertEqual(statements[5].replacement, ["b"])
-        self.assertEqual(statements[6].glyph, "a.sc")
-        self.assertEqual(statements[6].replacement, ["b.sc"])
 
     def test_substitute_from(self):  # GSUB LookupType 3
         doc = self.parse("feature test {"
@@ -1602,21 +1442,14 @@
     def test_substitute_lookups(self):  # GSUB LookupType 6
         doc = Parser(self.getpath("spec5fi1.fea"), GLYPHNAMES).parse()
         [_, _, _, langsys, ligs, sub, feature] = doc.statements
-        self.assertEqual(feature.statements[0].lookups, [[ligs], None, [sub]])
-        self.assertEqual(feature.statements[1].lookups, [[ligs], None, [sub]])
+        self.assertEqual(feature.statements[0].lookups, [ligs, None, sub])
+        self.assertEqual(feature.statements[1].lookups, [ligs, None, sub])
 
     def test_substitute_missing_by(self):
         self.assertRaisesRegex(
             FeatureLibError,
             'Expected "by", "from" or explicit lookup references',
             self.parse, "feature liga {substitute f f i;} liga;")
-    
-    def test_substitute_invalid_statement(self):
-        self.assertRaisesRegex(
-            FeatureLibError,
-            "Invalid substitution statement",
-            Parser(self.getpath("GSUB_error.fea"), GLYPHNAMES).parse
-        )
 
     def test_subtable(self):
         doc = self.parse("feature test {subtable;} test;")
@@ -1834,14 +1667,8 @@
             doc = self.parse("table %s { ;;; } %s;" % (table, table))
             self.assertEqual(doc.statements[0].statements, [])
 
-    def test_ufo_features_parse_include_dir(self):
-        fea_path = self.getpath("include/test.ufo/features.fea")
-        include_dir = os.path.dirname(os.path.dirname(fea_path))
-        doc = Parser(fea_path, includeDir=include_dir).parse()
-        assert len(doc.statements) == 1 and doc.statements[0].text == "# Nothing"
-
     def parse(self, text, glyphNames=GLYPHNAMES, followIncludes=True):
-        featurefile = StringIO(text)
+        featurefile = UnicodeIO(text)
         p = Parser(featurefile, glyphNames, followIncludes=followIncludes)
         return p.parse()
 
diff --git a/Tests/fontBuilder/data/test.otf.ttx b/Tests/fontBuilder/data/test.otf.ttx
index 7924ef5..8fdd38f 100644
--- a/Tests/fontBuilder/data/test.otf.ttx
+++ b/Tests/fontBuilder/data/test.otf.ttx
@@ -266,7 +266,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
           </Coverage>
           <ValueFormat1 value="4"/>
diff --git a/Tests/fontBuilder/data/test.ttf.ttx b/Tests/fontBuilder/data/test.ttf.ttx
index 8c3f00e..584815e 100644
--- a/Tests/fontBuilder/data/test.ttf.ttx
+++ b/Tests/fontBuilder/data/test.ttf.ttx
@@ -289,7 +289,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="A" out="a"/>
         </SingleSubst>
       </Lookup>
diff --git a/Tests/fontBuilder/data/test_var.otf.ttx b/Tests/fontBuilder/data/test_var.otf.ttx
index ff14868..e00d33c 100644
--- a/Tests/fontBuilder/data/test_var.otf.ttx
+++ b/Tests/fontBuilder/data/test_var.otf.ttx
@@ -19,10 +19,10 @@
     <unitsPerEm value="1000"/>
     <created value="Wed Mar 27 00:23:21 2019"/>
     <modified value="Wed Mar 27 00:23:21 2019"/>
-    <xMin value="100"/>
-    <yMin value="100"/>
-    <xMax value="600"/>
-    <yMax value="1000"/>
+    <xMin value="0"/>
+    <yMin value="0"/>
+    <xMax value="0"/>
+    <yMax value="0"/>
     <macStyle value="00000000 00000000"/>
     <lowestRecPPEM value="3"/>
     <fontDirectionHint value="2"/>
@@ -35,10 +35,10 @@
     <ascent value="824"/>
     <descent value="200"/>
     <lineGap value="0"/>
-    <advanceWidthMax value="600"/>
+    <advanceWidthMax value="0"/>
     <minLeftSideBearing value="0"/>
-    <minRightSideBearing value="200"/>
-    <xMaxExtent value="400"/>
+    <minRightSideBearing value="0"/>
+    <xMaxExtent value="0"/>
     <caretSlopeRise value="1"/>
     <caretSlopeRun value="0"/>
     <caretOffset value="0"/>
@@ -141,6 +141,9 @@
       Test Axis
     </namerecord>
     <namerecord nameID="257" platformID="1" platEncID="0" langID="0x0" unicode="True">
+      TotallyNormal
+    </namerecord>
+    <namerecord nameID="258" platformID="1" platEncID="0" langID="0x0" unicode="True">
       TotallyTested
     </namerecord>
     <namerecord nameID="1" platformID="1" platEncID="0" langID="0x4" unicode="True">
@@ -162,6 +165,9 @@
       Test Axis
     </namerecord>
     <namerecord nameID="257" platformID="3" platEncID="1" langID="0x409">
+      TotallyNormal
+    </namerecord>
+    <namerecord nameID="258" platformID="3" platEncID="1" langID="0x409">
       TotallyTested
     </namerecord>
     <namerecord nameID="1" platformID="3" platEncID="1" langID="0x413">
@@ -207,8 +213,6 @@
             <BlueScale value="0.039625"/>
             <BlueShift value="7"/>
             <BlueFuzz value="1"/>
-            <LanguageGroup value="0"/>
-            <ExpansionFactor value="0.06"/>
           </Private>
         </FontDict>
       </FDArray>
@@ -286,12 +290,12 @@
     </Axis>
 
     <!-- TotallyNormal -->
-    <NamedInstance flags="0x0" subfamilyNameID="2">
+    <NamedInstance flags="0x0" subfamilyNameID="257">
       <coord axis="TEST" value="0.0"/>
     </NamedInstance>
 
     <!-- TotallyTested -->
-    <NamedInstance flags="0x0" subfamilyNameID="257">
+    <NamedInstance flags="0x0" subfamilyNameID="258">
       <coord axis="TEST" value="100.0"/>
     </NamedInstance>
   </fvar>
diff --git a/Tests/fontBuilder/data/test_var.ttf.ttx b/Tests/fontBuilder/data/test_var.ttf.ttx
index e6d4d8d..382d29e 100644
--- a/Tests/fontBuilder/data/test_var.ttf.ttx
+++ b/Tests/fontBuilder/data/test_var.ttf.ttx
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.2">
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.32">
 
   <GlyphOrder>
     <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
@@ -19,7 +19,7 @@
     <unitsPerEm value="1024"/>
     <created value="Thu Nov  1 20:29:01 2018"/>
     <modified value="Thu Nov  1 20:29:01 2018"/>
-    <xMin value="50"/>
+    <xMin value="100"/>
     <yMin value="0"/>
     <xMax value="500"/>
     <yMax value="400"/>
@@ -36,7 +36,7 @@
     <descent value="200"/>
     <lineGap value="0"/>
     <advanceWidthMax value="600"/>
-    <minLeftSideBearing value="50"/>
+    <minLeftSideBearing value="100"/>
     <minRightSideBearing value="100"/>
     <xMaxExtent value="500"/>
     <caretSlopeRise value="1"/>
@@ -126,7 +126,7 @@
     <mtx name=".notdef" width="600" lsb="0"/>
     <mtx name=".null" width="600" lsb="0"/>
     <mtx name="A" width="600" lsb="100"/>
-    <mtx name="a" width="600" lsb="50"/>
+    <mtx name="a" width="600" lsb="100"/>
   </hmtx>
 
   <cmap>
@@ -164,12 +164,12 @@
       <instructions/>
     </TTGlyph>
 
-    <TTGlyph name="a" xMin="50" yMin="0" xMax="250" yMax="200">
+    <TTGlyph name="a" xMin="100" yMin="0" xMax="500" yMax="400">
       <contour>
-        <pt x="50" y="0" on="1"/>
-        <pt x="50" y="200" on="1"/>
-        <pt x="250" y="200" on="1"/>
-        <pt x="250" y="0" on="1"/>
+        <pt x="100" y="0" on="1"/>
+        <pt x="100" y="400" on="1"/>
+        <pt x="500" y="400" on="1"/>
+        <pt x="500" y="0" on="1"/>
       </contour>
       <instructions/>
     </TTGlyph>
@@ -199,10 +199,10 @@
       Down
     </namerecord>
     <namerecord nameID="260" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Right Up
+      TotallyNormal
     </namerecord>
     <namerecord nameID="261" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Neutral
+      Right Up
     </namerecord>
     <namerecord nameID="1" platformID="1" platEncID="0" langID="0x4" unicode="True">
       HalloTestFont
@@ -232,10 +232,10 @@
       Down
     </namerecord>
     <namerecord nameID="260" platformID="3" platEncID="1" langID="0x409">
-      Right Up
+      TotallyNormal
     </namerecord>
     <namerecord nameID="261" platformID="3" platEncID="1" langID="0x409">
-      Neutral
+      Right Up
     </namerecord>
     <namerecord nameID="1" platformID="3" platEncID="1" langID="0x413">
       HalloTestFont
@@ -269,180 +269,6 @@
     </extraNames>
   </post>
 
-  <GSUB>
-    <Version value="0x00010001"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=1 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="rclt"/>
-        <Feature>
-          <!-- LookupCount=0 -->
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=1 -->
-      <Lookup index="0">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="A" out="a"/>
-        </SingleSubst>
-      </Lookup>
-    </LookupList>
-    <FeatureVariations>
-      <Version value="0x00010000"/>
-      <!-- FeatureVariationCount=2 -->
-      <FeatureVariationRecord index="0">
-        <ConditionSet>
-          <!-- ConditionCount=2 -->
-          <ConditionTable index="0" Format="1">
-            <AxisIndex value="3"/>
-            <FilterRangeMinValue value="0.8"/>
-            <FilterRangeMaxValue value="1.0"/>
-          </ConditionTable>
-          <ConditionTable index="1" Format="1">
-            <AxisIndex value="0"/>
-            <FilterRangeMinValue value="0.8"/>
-            <FilterRangeMaxValue value="1.0"/>
-          </ConditionTable>
-        </ConditionSet>
-        <FeatureTableSubstitution>
-          <Version value="0x00010000"/>
-          <!-- SubstitutionCount=1 -->
-          <SubstitutionRecord index="0">
-            <FeatureIndex value="0"/>
-            <Feature>
-              <!-- LookupCount=1 -->
-              <LookupListIndex index="0" value="0"/>
-            </Feature>
-          </SubstitutionRecord>
-        </FeatureTableSubstitution>
-      </FeatureVariationRecord>
-      <FeatureVariationRecord index="1">
-        <ConditionSet>
-          <!-- ConditionCount=2 -->
-          <ConditionTable index="0" Format="1">
-            <AxisIndex value="1"/>
-            <FilterRangeMinValue value="0.8"/>
-            <FilterRangeMaxValue value="1.0"/>
-          </ConditionTable>
-          <ConditionTable index="1" Format="1">
-            <AxisIndex value="2"/>
-            <FilterRangeMinValue value="0.8"/>
-            <FilterRangeMaxValue value="1.0"/>
-          </ConditionTable>
-        </ConditionSet>
-        <FeatureTableSubstitution>
-          <Version value="0x00010000"/>
-          <!-- SubstitutionCount=1 -->
-          <SubstitutionRecord index="0">
-            <FeatureIndex value="0"/>
-            <Feature>
-              <!-- LookupCount=1 -->
-              <LookupListIndex index="0" value="0"/>
-            </Feature>
-          </SubstitutionRecord>
-        </FeatureTableSubstitution>
-      </FeatureVariationRecord>
-    </FeatureVariations>
-  </GSUB>
-
-  <STAT>
-    <Version value="0x00010001"/>
-    <DesignAxisRecordSize value="8"/>
-    <!-- DesignAxisCount=4 -->
-    <DesignAxisRecord>
-      <Axis index="0">
-        <AxisTag value="LEFT"/>
-        <AxisNameID value="256"/>  <!-- Left -->
-        <AxisOrdering value="0"/>
-      </Axis>
-      <Axis index="1">
-        <AxisTag value="RGHT"/>
-        <AxisNameID value="257"/>  <!-- Right -->
-        <AxisOrdering value="1"/>
-      </Axis>
-      <Axis index="2">
-        <AxisTag value="UPPP"/>
-        <AxisNameID value="258"/>  <!-- Up -->
-        <AxisOrdering value="2"/>
-      </Axis>
-      <Axis index="3">
-        <AxisTag value="DOWN"/>
-        <AxisNameID value="259"/>  <!-- Down -->
-        <AxisOrdering value="3"/>
-      </Axis>
-    </DesignAxisRecord>
-    <!-- AxisValueCount=8 -->
-    <AxisValueArray>
-      <AxisValue index="0" Format="1">
-        <AxisIndex value="0"/>
-        <Flags value="2"/>  <!-- ElidableAxisValueName -->
-        <ValueNameID value="261"/>  <!-- Neutral -->
-        <Value value="0.0"/>
-      </AxisValue>
-      <AxisValue index="1" Format="1">
-        <AxisIndex value="0"/>
-        <Flags value="0"/>
-        <ValueNameID value="256"/>  <!-- Left -->
-        <Value value="100.0"/>
-      </AxisValue>
-      <AxisValue index="2" Format="1">
-        <AxisIndex value="1"/>
-        <Flags value="2"/>  <!-- ElidableAxisValueName -->
-        <ValueNameID value="261"/>  <!-- Neutral -->
-        <Value value="0.0"/>
-      </AxisValue>
-      <AxisValue index="3" Format="1">
-        <AxisIndex value="1"/>
-        <Flags value="0"/>
-        <ValueNameID value="257"/>  <!-- Right -->
-        <Value value="100.0"/>
-      </AxisValue>
-      <AxisValue index="4" Format="1">
-        <AxisIndex value="2"/>
-        <Flags value="2"/>  <!-- ElidableAxisValueName -->
-        <ValueNameID value="261"/>  <!-- Neutral -->
-        <Value value="0.0"/>
-      </AxisValue>
-      <AxisValue index="5" Format="1">
-        <AxisIndex value="2"/>
-        <Flags value="0"/>
-        <ValueNameID value="258"/>  <!-- Up -->
-        <Value value="100.0"/>
-      </AxisValue>
-      <AxisValue index="6" Format="1">
-        <AxisIndex value="3"/>
-        <Flags value="2"/>  <!-- ElidableAxisValueName -->
-        <ValueNameID value="261"/>  <!-- Neutral -->
-        <Value value="0.0"/>
-      </AxisValue>
-      <AxisValue index="7" Format="1">
-        <AxisIndex value="3"/>
-        <Flags value="0"/>
-        <ValueNameID value="259"/>  <!-- Down -->
-        <Value value="100.0"/>
-      </AxisValue>
-    </AxisValueArray>
-    <ElidedFallbackNameID value="2"/>  <!-- TotallyNormal -->
-  </STAT>
-
   <fvar>
 
     <!-- Left -->
@@ -486,7 +312,7 @@
     </Axis>
 
     <!-- TotallyNormal -->
-    <NamedInstance flags="0x0" subfamilyNameID="2">
+    <NamedInstance flags="0x0" subfamilyNameID="260">
       <coord axis="LEFT" value="0.0"/>
       <coord axis="RGHT" value="0.0"/>
       <coord axis="UPPP" value="0.0"/>
@@ -494,7 +320,7 @@
     </NamedInstance>
 
     <!-- Right Up -->
-    <NamedInstance flags="0x0" subfamilyNameID="260">
+    <NamedInstance flags="0x0" subfamilyNameID="261">
       <coord axis="LEFT" value="0.0"/>
       <coord axis="RGHT" value="100.0"/>
       <coord axis="UPPP" value="100.0"/>
diff --git a/Tests/fontBuilder/fontBuilder_test.py b/Tests/fontBuilder/fontBuilder_test.py
index 6368cb8..3095284 100644
--- a/Tests/fontBuilder/fontBuilder_test.py
+++ b/Tests/fontBuilder/fontBuilder_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
 
 import os
 import pytest
@@ -164,20 +166,13 @@
     pen.lineTo((500, 400))
     pen.lineTo((500, 000))
     pen.closePath()
-    glyph1 = pen.glyph()
 
-    pen = TTGlyphPen(None)
-    pen.moveTo((50, 0))
-    pen.lineTo((50, 200))
-    pen.lineTo((250, 200))
-    pen.lineTo((250, 0))
-    pen.closePath()
-    glyph2 = pen.glyph()
+    glyph = pen.glyph()
 
     pen = TTGlyphPen(None)
     emptyGlyph = pen.glyph()
 
-    glyphs = {".notdef": emptyGlyph, "A": glyph1, "a": glyph2, ".null": emptyGlyph}
+    glyphs = {".notdef": emptyGlyph, "A": glyph, "a": glyph, ".null": emptyGlyph}
     fb.setupGlyf(glyphs)
     metrics = {}
     glyphTable = fb.font["glyf"]
@@ -213,26 +208,6 @@
     ]
     fb.setupGvar(variations)
 
-    fb.addFeatureVariations(
-        [
-            (
-                [
-                    {"LEFT": (0.8, 1), "DOWN": (0.8, 1)},
-                    {"RGHT": (0.8, 1), "UPPP": (0.8, 1)},
-                  ],
-                {"A": "a"}
-            )
-        ],
-        featureTag="rclt",
-    )
-
-    statAxes = []
-    for tag, minVal, defaultVal, maxVal, name in axes:
-        values = [dict(name="Neutral", value=defaultVal, flags=0x2),
-                  dict(name=name, value=maxVal)]
-        statAxes.append(dict(tag=tag, name=name, values=values))
-    fb.setupStat(statAxes)
-
     fb.setupOS2()
     fb.setupPost()
     fb.setupDummyDSIG()
@@ -262,19 +237,6 @@
     _verifyOutput(outPath)
 
 
-def test_build_cff_to_cff2(tmpdir):
-    fb, _, _ = _setupFontBuilder(False, 1000)
-
-    pen = T2CharStringPen(600, None)
-    drawTestGlyph(pen)
-    charString = pen.getCharString()
-    charStrings = {".notdef": charString, "A": charString, "a": charString, ".null": charString}
-    fb.setupCFF("TestFont", {}, charStrings, {})
-
-    from fontTools.varLib.cff import convertCFFtoCFF2
-    convertCFFtoCFF2(fb.font)
-
-
 def test_setupNameTable_no_mac():
     fb, _, nameStrings = _setupFontBuilder(True)
     fb.setupNameTable(nameStrings, mac=False)
diff --git a/Tests/merge_test.py b/Tests/merge_test.py
index 015248d..00e719b 100644
--- a/Tests/merge_test.py
+++ b/Tests/merge_test.py
@@ -1,11 +1,7 @@
-import io
-import itertools
+from fontTools.misc.py23 import *
 from fontTools import ttLib
-from fontTools.ttLib.tables._g_l_y_f import Glyph
-from fontTools.fontBuilder import FontBuilder
-from fontTools.merge import Merger
+from fontTools.merge import *
 import unittest
-import pytest
 
 
 class MergeIntegrationTest(unittest.TestCase):
@@ -117,53 +113,6 @@
 		self.assertEqual(self.merger.duplicateGlyphsPerFont, [{}, {'space#0': 'space#1'}])
 
 
-def _compile(ttFont):
-	buf = io.BytesIO()
-	ttFont.save(buf)
-	buf.seek(0)
-	return buf
-
-
-def _make_fontfile_with_OS2(*, version, **kwargs):
-	upem = 1000
-	glyphOrder = [".notdef", "a"]
-	cmap = {0x61: "a"}
-	glyphs = {gn: Glyph() for gn in glyphOrder}
-	hmtx = {gn: (500, 0) for gn in glyphOrder}
-	names = {"familyName": "TestOS2", "styleName": "Regular"}
-
-	fb = FontBuilder(unitsPerEm=upem)
-	fb.setupGlyphOrder(glyphOrder)
-	fb.setupCharacterMap(cmap)
-	fb.setupGlyf(glyphs)
-	fb.setupHorizontalMetrics(hmtx)
-	fb.setupHorizontalHeader()
-	fb.setupNameTable(names)
-	fb.setupOS2(version=version, **kwargs)
-
-	return _compile(fb.font)
-
-
-def _merge_and_recompile(fontfiles, options=None):
-	merger = Merger(options)
-	merged = merger.merge(fontfiles)
-	buf = _compile(merged)
-	return ttLib.TTFont(buf)
-
-
-@pytest.mark.parametrize(
-	"v1, v2", list(itertools.permutations(range(5+1), 2))
-)
-def test_merge_OS2_mixed_versions(v1, v2):
-	# https://github.com/fonttools/fonttools/issues/1865
-	fontfiles = [
-		_make_fontfile_with_OS2(version=v1),
-		_make_fontfile_with_OS2(version=v2),
-	]
-	merged = _merge_and_recompile(fontfiles)
-	assert merged["OS/2"].version == max(v1, v2)
-
-
 if __name__ == "__main__":
 	import sys
 	sys.exit(unittest.main())
diff --git a/Tests/misc/arrayTools_test.py b/Tests/misc/arrayTools_test.py
index 45b186f..2610c0f 100644
--- a/Tests/misc/arrayTools_test.py
+++ b/Tests/misc/arrayTools_test.py
@@ -1,3 +1,6 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools.misc.py23 import round3
 from fontTools.misc.arrayTools import (
     calcBounds, calcIntBounds, updateBounds, pointInRect, pointsInRect,
     vectorLength, asInt16, normRect, scaleRect, offsetRect, insetRect,
@@ -18,7 +21,7 @@
 
     assert calcIntBounds(
         [(0.1, 40.1), (0.1, 100.1), (49.9, 49.9), (78.5, 9.5)],
-        round=round
+        round=round3
     ) == (0, 10, 78, 100)
 
 
diff --git a/Tests/misc/bezierTools_test.py b/Tests/misc/bezierTools_test.py
index c5cd1b7..1519543 100644
--- a/Tests/misc/bezierTools_test.py
+++ b/Tests/misc/bezierTools_test.py
@@ -1,5 +1,7 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.bezierTools import (
-    calcQuadraticBounds, calcCubicBounds, segmentPointAtT, splitLine, splitQuadratic,
+    calcQuadraticBounds, calcCubicBounds, splitLine, splitQuadratic,
     splitCubic, splitQuadraticAtT, splitCubicAtT, solveCubic)
 import pytest
 
@@ -129,22 +131,3 @@
     assert solveCubic(1.0, -4.5, 6.75, -3.375) == [1.5, 1.5, 1.5]
     assert solveCubic(-12.0, 18.0, -9.0, 1.50023651123) == [0.5, 0.5, 0.5]
     assert solveCubic(9.0, 0.0, 0.0, -7.62939453125e-05) == [-0.0, -0.0, -0.0]
-
-
-_segmentPointAtT_testData = [
-    ([(0, 10), (200, 100)], 0.0, (0, 10)),
-    ([(0, 10), (200, 100)], 0.5, (100, 55)),
-    ([(0, 10), (200, 100)], 1.0, (200, 100)),
-    ([(0, 10), (100, 100), (200, 50)], 0.0, (0, 10)),
-    ([(0, 10), (100, 100), (200, 50)], 0.5, (100, 65.0)),
-    ([(0, 10), (100, 100), (200, 50)], 1.0, (200, 50.0)),
-    ([(0, 10), (100, 100), (200, 100), (300, 0)], 0.0, (0, 10)),
-    ([(0, 10), (100, 100), (200, 100), (300, 0)], 0.5, (150, 76.25)),
-    ([(0, 10), (100, 100), (200, 100), (300, 0)], 1.0, (300, 0)),
-]
-
-
-@pytest.mark.parametrize("segment, t, expectedPoint", _segmentPointAtT_testData)
-def test_segmentPointAtT(segment, t, expectedPoint):
-    point = segmentPointAtT(segment, t)
-    assert expectedPoint == point
diff --git a/Tests/misc/classifyTools_test.py b/Tests/misc/classifyTools_test.py
index 72a9752..ac1f656 100644
--- a/Tests/misc/classifyTools_test.py
+++ b/Tests/misc/classifyTools_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.classifyTools import classify
 
 
diff --git a/Tests/misc/eexec_test.py b/Tests/misc/eexec_test.py
index f72760a..2043095 100644
--- a/Tests/misc/eexec_test.py
+++ b/Tests/misc/eexec_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.eexec import decrypt, encrypt
 
 
diff --git a/Tests/misc/encodingTools_test.py b/Tests/misc/encodingTools_test.py
index 1a131f6..4c9628b 100644
--- a/Tests/misc/encodingTools_test.py
+++ b/Tests/misc/encodingTools_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 import unittest
 from fontTools.misc.encodingTools import getEncoding
 
@@ -18,7 +20,7 @@
 	def test_extended_mac_encodings(self):
 		encoding = getEncoding(1, 1, 0) # Mac Japanese
 		decoded = b'\xfe'.decode(encoding)
-		self.assertEqual(decoded, chr(0x2122))
+		self.assertEqual(decoded, unichr(0x2122))
 
 	def test_extended_unknown(self):
 		self.assertEqual(getEncoding(10, 11, 12), None)
diff --git a/Tests/misc/etree_test.py b/Tests/misc/etree_test.py
index 3f3232e..d2f585c 100644
--- a/Tests/misc/etree_test.py
+++ b/Tests/misc/etree_test.py
@@ -1,4 +1,5 @@
 # coding: utf-8
+from __future__ import absolute_import, unicode_literals
 from fontTools.misc import etree
 from collections import OrderedDict
 import io
diff --git a/Tests/misc/filenames_test.py b/Tests/misc/filenames_test.py
index bb7b63c..47d137f 100644
--- a/Tests/misc/filenames_test.py
+++ b/Tests/misc/filenames_test.py
@@ -1,3 +1,4 @@
+from __future__ import unicode_literals
 import unittest
 from fontTools.misc.filenames import (
 	userNameToFileName, handleClash1, handleClash2)
diff --git a/Tests/misc/fixedTools_test.py b/Tests/misc/fixedTools_test.py
index dea61b9..5ef1777 100644
--- a/Tests/misc/fixedTools_test.py
+++ b/Tests/misc/fixedTools_test.py
@@ -1,11 +1,6 @@
-from fontTools.misc.fixedTools import (
-    fixedToFloat,
-    floatToFixed,
-    floatToFixedToStr,
-    fixedToStr,
-    strToFixed,
-    strToFixedToFloat,
-)
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools.misc.fixedTools import fixedToFloat, floatToFixed
 import unittest
 
 
@@ -17,33 +12,19 @@
                 self.assertEqual(value, floatToFixed(fixedToFloat(value, bits), bits))
 
     def test_fixedToFloat_precision14(self):
-        self.assertAlmostEqual(0.7999878, fixedToFloat(13107, 14))
+        self.assertEqual(0.8, fixedToFloat(13107, 14))
         self.assertEqual(0.0, fixedToFloat(0, 14))
         self.assertEqual(1.0, fixedToFloat(16384, 14))
         self.assertEqual(-1.0, fixedToFloat(-16384, 14))
-        self.assertAlmostEqual(0.999939, fixedToFloat(16383, 14))
-        self.assertAlmostEqual(-0.999939, fixedToFloat(-16383, 14))
+        self.assertEqual(0.99994, fixedToFloat(16383, 14))
+        self.assertEqual(-0.99994, fixedToFloat(-16383, 14))
 
     def test_fixedToFloat_precision6(self):
-        self.assertAlmostEqual(-9.984375, fixedToFloat(-639, 6))
+        self.assertAlmostEqual(-9.98, fixedToFloat(-639, 6))
         self.assertAlmostEqual(-10.0, fixedToFloat(-640, 6))
-        self.assertAlmostEqual(9.984375, fixedToFloat(639, 6))
+        self.assertAlmostEqual(9.98, fixedToFloat(639, 6))
         self.assertAlmostEqual(10.0, fixedToFloat(640, 6))
 
-    def test_fixedToStr_precision14(self):
-        self.assertEqual('0.8', fixedToStr(13107, 14))
-        self.assertEqual('0.0', fixedToStr(0, 14))
-        self.assertEqual('1.0', fixedToStr(16384, 14))
-        self.assertEqual('-1.0', fixedToStr(-16384, 14))
-        self.assertEqual('0.99994', fixedToStr(16383, 14))
-        self.assertEqual('-0.99994', fixedToStr(-16383, 14))
-
-    def test_fixedToStr_precision6(self):
-        self.assertAlmostEqual('-9.98', fixedToStr(-639, 6))
-        self.assertAlmostEqual('-10.0', fixedToStr(-640, 6))
-        self.assertAlmostEqual('9.98', fixedToStr(639, 6))
-        self.assertAlmostEqual('10.0', fixedToStr(640, 6))
-
     def test_floatToFixed_precision14(self):
         self.assertEqual(13107, floatToFixed(0.8, 14))
         self.assertEqual(16384, floatToFixed(1.0, 14))
@@ -52,30 +33,6 @@
         self.assertEqual(-16384, floatToFixed(-1, 14))
         self.assertEqual(0, floatToFixed(0, 14))
 
-    def test_strToFixed_precision14(self):
-        self.assertEqual(13107, strToFixed('0.8', 14))
-        self.assertEqual(16384, strToFixed('1.0', 14))
-        self.assertEqual(16384, strToFixed('1', 14))
-        self.assertEqual(-16384, strToFixed('-1.0', 14))
-        self.assertEqual(-16384, strToFixed('-1', 14))
-        self.assertEqual(0, strToFixed('0', 14))
-
-    def test_strToFixedToFloat_precision14(self):
-        self.assertAlmostEqual(0.7999878, strToFixedToFloat('0.8', 14))
-        self.assertEqual(0.0, strToFixedToFloat('0', 14))
-        self.assertEqual(1.0, strToFixedToFloat('1.0', 14))
-        self.assertEqual(-1.0, strToFixedToFloat('-1.0', 14))
-        self.assertAlmostEqual(0.999939, strToFixedToFloat('0.99994', 14))
-        self.assertAlmostEqual(-0.999939, strToFixedToFloat('-0.99994', 14))
-
-    def test_floatToFixedToStr_precision14(self):
-        self.assertEqual('0.8', floatToFixedToStr(0.7999878, 14))
-        self.assertEqual('1.0', floatToFixedToStr(1.0, 14))
-        self.assertEqual('1.0', floatToFixedToStr(1, 14))
-        self.assertEqual('-1.0', floatToFixedToStr(-1.0, 14))
-        self.assertEqual('-1.0', floatToFixedToStr(-1, 14))
-        self.assertEqual('0.0', floatToFixedToStr(0, 14))
-
     def test_fixedToFloat_return_float(self):
         value = fixedToFloat(16384, 14)
         self.assertIsInstance(value, float)
diff --git a/Tests/misc/loggingTools_test.py b/Tests/misc/loggingTools_test.py
index fd13044..fd64b8b 100644
--- a/Tests/misc/loggingTools_test.py
+++ b/Tests/misc/loggingTools_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.loggingTools import (
     LevelFormatter,
     Timer,
@@ -5,7 +7,6 @@
     ChannelsFilter,
     LogMixin,
 )
-from io import StringIO
 import logging
 import textwrap
 import time
diff --git a/Tests/misc/macRes_test.py b/Tests/misc/macRes_test.py
index a6a8e9d..fde13f8 100644
--- a/Tests/misc/macRes_test.py
+++ b/Tests/misc/macRes_test.py
@@ -1,4 +1,5 @@
-from io import BytesIO
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 import sys
 import os
 import tempfile
diff --git a/Tests/misc/plistlib_test.py b/Tests/misc/plistlib_test.py
index b2ce408..c866529 100644
--- a/Tests/misc/plistlib_test.py
+++ b/Tests/misc/plistlib_test.py
@@ -1,3 +1,4 @@
+from __future__ import absolute_import, unicode_literals
 import sys
 import os
 import datetime
@@ -5,15 +6,27 @@
 import collections
 from io import BytesIO
 from numbers import Integral
-from fontTools.misc.py23 import tostr
+from fontTools.misc.py23 import tounicode, unicode
 from fontTools.misc import etree
 from fontTools.misc import plistlib
 from fontTools.ufoLib.plistlib import (
     readPlist, readPlistFromString, writePlist, writePlistToString,
 )
 import pytest
-from collections.abc import Mapping
 
+try:
+    from collections.abc import Mapping # python >= 3.3
+except ImportError:
+    from collections import Mapping
+
+PY2 = sys.version_info < (3,)
+if PY2:
+    # This is a ResourceWarning that only happens on py27 at interpreter
+    # finalization, and only when coverage is enabled. We can ignore it.
+    # https://github.com/numpy/numpy/issues/3778#issuecomment-24885336
+    pytestmark = pytest.mark.filterwarnings(
+        "ignore:tp_compare didn't return -1 or -2 for exception"
+    )
 
 # The testdata is generated using https://github.com/python/cpython/...
 # Mac/Tools/plistlib_generate_testdata.py
@@ -176,7 +189,7 @@
     pl = b"some ASCII bytes"
     data = plistlib.dumps(pl, use_builtin_types=False)
     pl2 = plistlib.loads(data, use_builtin_types=use_builtin_types)
-    assert isinstance(pl2, str)  # it's always a <string>
+    assert isinstance(pl2, unicode)  # it's always a <string>
     assert pl2 == pl.decode()
 
 
@@ -421,7 +434,7 @@
 
 def _strip(txt):
     return (
-        "".join(l.strip() for l in tostr(txt, "utf-8").splitlines())
+        "".join(l.strip() for l in tounicode(txt, "utf-8").splitlines())
         if txt is not None
         else ""
     )
@@ -504,13 +517,15 @@
 
 def test_load_use_builtin_types_default():
     pl = plistlib.loads(TESTDATA)
-    assert isinstance(pl["someData"], bytes)
+    expected = plistlib.Data if PY2 else bytes
+    assert isinstance(pl["someData"], expected)
 
 
 def test_dump_use_builtin_types_default(pl_no_builtin_types):
     data = plistlib.dumps(pl_no_builtin_types)
     pl2 = plistlib.loads(data)
-    assert isinstance(pl2["someData"], bytes)
+    expected = plistlib.Data if PY2 else bytes
+    assert isinstance(pl2["someData"], expected)
     assert pl2 == pl_no_builtin_types
 
 
diff --git a/Tests/misc/psCharStrings_test.py b/Tests/misc/psCharStrings_test.py
index 47ff4fd..f69f748 100644
--- a/Tests/misc/psCharStrings_test.py
+++ b/Tests/misc/psCharStrings_test.py
@@ -1,20 +1,10 @@
+from __future__ import print_function, division, absolute_import
 from fontTools.cffLib import PrivateDict
 from fontTools.cffLib.specializer import stringToProgram
-from fontTools.misc.testTools import getXML, parseXML
-from fontTools.misc.psCharStrings import (
-    T2CharString,
-    encodeFloat,
-    encodeFixed,
-    read_fixed1616,
-    read_realNumber,
-)
+from fontTools.misc.psCharStrings import T2CharString, encodeFloat, read_realNumber
 import unittest
 
 
-def hexenc(s):
-    return ' '.join('%02x' % x for x in s)
-
-
 class T2CharStringTest(unittest.TestCase):
 
     @classmethod
@@ -58,6 +48,14 @@
                           'rrcurveto'])
 
     def test_encodeFloat(self):
+        import sys
+        def hexenc(s):
+            return ' '.join('%02x' % ord(x) for x in s)
+        if sys.version_info[0] >= 3:
+            def hexenc_py3(s):
+                return ' '.join('%02x' % x for x in s)
+            hexenc = hexenc_py3
+
         testNums = [
             # value                expected result
             (-9.399999999999999,   '1e e9 a4 ff'),  # -9.4
@@ -75,7 +73,7 @@
 
         for sample in testNums:
             encoded_result = encodeFloat(sample[0])
-
+            
             # check to see if we got the expected bytes
             self.assertEqual(hexenc(encoded_result), sample[1])
 
@@ -90,74 +88,6 @@
             # We limit to 8 digits of precision to match the implementation
             # of encodeFloat.
 
-    def test_encode_decode_fixed(self):
-        testNums = [
-            # value                expected hex      expected float
-            (-9.399999999999999,   'ff ff f6 99 9a', -9.3999939),
-            (-9.4,                 'ff ff f6 99 9a', -9.3999939),
-            (9.399999999999999999, 'ff 00 09 66 66', 9.3999939),
-            (9.4,                  'ff 00 09 66 66', 9.3999939),
-            (456.8,                'ff 01 c8 cc cd', 456.8000031),
-            (-456.8,               'ff fe 37 33 33', -456.8000031),
-        ]
-
-        for (value, expected_hex, expected_float) in testNums:
-            encoded_result = encodeFixed(value)
-
-            # check to see if we got the expected bytes
-            self.assertEqual(hexenc(encoded_result), expected_hex)
-
-            # check to see if we get the same value by decoding the data
-            decoded_result = read_fixed1616(
-                None,
-                None,
-                encoded_result,
-                1,
-            )
-            self.assertAlmostEqual(decoded_result[0], expected_float)
-
-    def test_toXML(self):
-        program = [
-            '107 53.4004 166.199 hstem',
-            '174.6 163.801 vstem',
-            '338.4 142.8 rmoveto',
-            '28 0 21.9 9 15.8 18 15.8 18 7.9 20.79959 0 23.6 rrcurveto',
-            'endchar'
-        ]
-        cs = self.stringToT2CharString(" ".join(program))
-
-        self.assertEqual(getXML(cs.toXML), program)
-
-    def test_fromXML(self):
-        cs = T2CharString()
-        for name, attrs, content in parseXML(
-            [
-                '<CharString name="period">'
-                '  338.4 142.8 rmoveto',
-                '  28 0 21.9 9 15.8 18 15.8 18 7.9 20.79959 0 23.6 rrcurveto',
-                '  endchar'
-                '</CharString>'
-            ]
-        ):
-            cs.fromXML(name, attrs, content)
-
-        expected_program = [
-            338.3999939, 142.8000031, 'rmoveto',
-            28, 0, 21.8999939, 9, 15.8000031,
-            18, 15.8000031, 18, 7.8999939,
-            20.7995911, 0, 23.6000061, 'rrcurveto',
-            'endchar'
-        ]
-
-        self.assertEqual(len(cs.program), len(expected_program))
-        for arg, expected_arg in zip(cs.program, expected_program):
-            if isinstance(arg, str):
-                self.assertIsInstance(expected_arg, str)
-                self.assertEqual(arg, expected_arg)
-            else:
-                self.assertNotIsInstance(expected_arg, str)
-                self.assertAlmostEqual(arg, expected_arg)
-
 
 if __name__ == "__main__":
     import sys
diff --git a/Tests/misc/py23_test.py b/Tests/misc/py23_test.py
index 61274cc..22b8044 100644
--- a/Tests/misc/py23_test.py
+++ b/Tests/misc/py23_test.py
@@ -1,7 +1,7 @@
-from fontTools.misc.py23 import tobytes
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.textTools import deHexStr
 import filecmp
-from io import StringIO
 import tempfile
 from subprocess import check_call
 import sys
@@ -390,6 +390,35 @@
 		self.assertAllNotClose(fraction_examples, rel_tol=1e-9)
 
 
+@unittest.skipUnless(
+	(sys.version_info[0] == 2 and sys.maxunicode < 0x10FFFF),
+	"requires 'narrow' Python 2.7 build")
+class NarrowUnicodeBuildTest(unittest.TestCase):
+
+	def test_unichr(self):
+		from __builtin__ import unichr as narrow_unichr
+
+		self.assertRaises(
+			ValueError,
+			narrow_unichr, 0xFFFF + 1)
+
+		self.assertEqual(unichr(1114111), u'\U0010FFFF')
+
+		self.assertRaises(
+			ValueError,
+			unichr, 0x10FFFF + 1)
+
+	def test_byteord(self):
+		from __builtin__ import ord as narrow_ord
+
+		self.assertRaises(
+			TypeError,
+			narrow_ord, u'\U00010000')
+
+		self.assertEqual(byteord(u'\U00010000'), 0xFFFF + 1)
+		self.assertEqual(byteord(u'\U0010FFFF'), 1114111)
+
+
 class TestRedirectStream:
 
     redirect_stream = None
diff --git a/Tests/misc/testTools_test.py b/Tests/misc/testTools_test.py
index 80d4d2b..11c04b1 100644
--- a/Tests/misc/testTools_test.py
+++ b/Tests/misc/testTools_test.py
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
+from fontTools.misc.py23 import *
 import fontTools.misc.testTools as testTools
 import unittest
 
diff --git a/Tests/misc/textTools_test.py b/Tests/misc/textTools_test.py
index f83abf9..547569a 100644
--- a/Tests/misc/textTools_test.py
+++ b/Tests/misc/textTools_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.textTools import pad
 
 
diff --git a/Tests/misc/timeTools_test.py b/Tests/misc/timeTools_test.py
index 4d75ce4..6c98f64 100644
--- a/Tests/misc/timeTools_test.py
+++ b/Tests/misc/timeTools_test.py
@@ -1,12 +1,13 @@
-from fontTools.misc.timeTools import asctime, timestampNow, timestampToString, timestampFromString, epoch_diff
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools.misc.timeTools import asctime, timestampNow, epoch_diff
 import os
 import time
-import locale
 import pytest
 
 
 def test_asctime():
-    assert isinstance(asctime(), str)
+    assert isinstance(asctime(), basestring)
     assert asctime(time.gmtime(0)) == 'Thu Jan  1 00:00:00 1970'
 
 
@@ -21,17 +22,3 @@
 
     del os.environ["SOURCE_DATE_EPOCH"]
     assert timestampNow() + epoch_diff != 150687315
-
-
-# test for issue #1838
-def test_date_parsing_with_locale():
-    l = locale.getlocale(locale.LC_TIME)
-    try:
-        locale.setlocale(locale.LC_TIME, 'de_DE.utf8')
-    except locale.Error:
-        pytest.skip("Locale de_DE not available")
-
-    try:
-        assert timestampFromString(timestampToString(timestampNow()))
-    finally:
-        locale.setlocale(locale.LC_TIME, l)
diff --git a/Tests/misc/transform_test.py b/Tests/misc/transform_test.py
index 4efab81..7a7a67d 100644
--- a/Tests/misc/transform_test.py
+++ b/Tests/misc/transform_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.transform import Transform, Identity, Offset, Scale
 import math
 import pytest
diff --git a/Tests/misc/vector_test.py b/Tests/misc/vector_test.py
deleted file mode 100644
index 236a3ba..0000000
--- a/Tests/misc/vector_test.py
+++ /dev/null
@@ -1,71 +0,0 @@
-import math
-import pytest
-from fontTools.misc.arrayTools import Vector as ArrayVector
-from fontTools.misc.vector import Vector
-
-
-def test_Vector():
-    v = Vector((100, 200))
-    assert repr(v) == "Vector((100, 200))"
-    assert v == Vector((100, 200))
-    assert v == Vector([100, 200])
-    assert v == (100, 200)
-    assert (100, 200) == v
-    assert v == [100, 200]
-    assert [100, 200] == v
-    assert v is Vector(v)
-    assert v + 10 == (110, 210)
-    assert 10 + v == (110, 210)
-    assert v + Vector((1, 2)) == (101, 202)
-    assert v - Vector((1, 2)) == (99, 198)
-    assert v * 2 == (200, 400)
-    assert 2 * v == (200, 400)
-    assert v * 0.5 == (50, 100)
-    assert v / 2 == (50, 100)
-    assert 2 / v == (0.02, 0.01)
-    v = Vector((3, 4))
-    assert abs(v) == 5  # length
-    assert v.length() == 5
-    assert v.normalized() == Vector((0.6, 0.8))
-    assert abs(Vector((1, 1, 1))) == math.sqrt(3)
-    assert bool(Vector((0, 0, 1)))
-    assert not bool(Vector((0, 0, 0)))
-    v1 = Vector((2, 3))
-    v2 = Vector((3, 4))
-    assert v1.dot(v2) == 18
-    v = Vector((2, 4))
-    assert round(v / 3) == (1, 1)
-    with pytest.raises(
-        AttributeError,
-        match="'Vector' object has no attribute 'newAttr'",
-    ):
-        v.newAttr = 12
-
-
-def test_deprecated():
-    with pytest.warns(
-        DeprecationWarning,
-        match="fontTools.misc.arrayTools.Vector has been deprecated",
-    ):
-        ArrayVector((1, 2))
-    with pytest.warns(
-        DeprecationWarning,
-        match="the 'keep' argument has been deprecated",
-    ):
-        Vector((1, 2), keep=True)
-    v = Vector((1, 2))
-    with pytest.warns(
-        DeprecationWarning,
-        match="the 'toInt' method has been deprecated",
-    ):
-        v.toInt()
-    with pytest.warns(
-        DeprecationWarning,
-        match="the 'values' attribute has been deprecated",
-    ):
-        v.values
-    with pytest.raises(
-        AttributeError,
-        match="the 'values' attribute has been deprecated",
-    ):
-        v.values = [12, 23]
diff --git a/Tests/misc/xmlReader_test.py b/Tests/misc/xmlReader_test.py
index f6775cb..33fddcc 100644
--- a/Tests/misc/xmlReader_test.py
+++ b/Tests/misc/xmlReader_test.py
@@ -1,5 +1,7 @@
-from fontTools.misc.py23 import strjoin
-from io import BytesIO
+# -*- coding: utf-8 -*-
+
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 import os
 import unittest
 from fontTools.ttLib import TTFont
diff --git a/Tests/misc/xmlWriter_test.py b/Tests/misc/xmlWriter_test.py
index fd4f240..ac8a789 100644
--- a/Tests/misc/xmlWriter_test.py
+++ b/Tests/misc/xmlWriter_test.py
@@ -1,5 +1,5 @@
-from fontTools.misc.py23 import bytesjoin, tobytes
-from io import BytesIO
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 import os
 import unittest
 from fontTools.misc.xmlWriter import XMLWriter
diff --git a/Tests/mtiLib/data/featurename-backward.ttx.GSUB b/Tests/mtiLib/data/featurename-backward.ttx.GSUB
index cc893cd..9469c79 100644
--- a/Tests/mtiLib/data/featurename-backward.ttx.GSUB
+++ b/Tests/mtiLib/data/featurename-backward.ttx.GSUB
@@ -51,7 +51,7 @@
       <LookupType value="1"/>
       <LookupFlag value="0"/>
       <!-- SubTableCount=1 -->
-      <SingleSubst index="0">
+      <SingleSubst index="0" Format="1">
         <Substitution in="a" out="b"/>
       </SingleSubst>
     </Lookup>
diff --git a/Tests/mtiLib/data/featurename-forward.ttx.GSUB b/Tests/mtiLib/data/featurename-forward.ttx.GSUB
index cc893cd..9469c79 100644
--- a/Tests/mtiLib/data/featurename-forward.ttx.GSUB
+++ b/Tests/mtiLib/data/featurename-forward.ttx.GSUB
@@ -51,7 +51,7 @@
       <LookupType value="1"/>
       <LookupFlag value="0"/>
       <!-- SubTableCount=1 -->
-      <SingleSubst index="0">
+      <SingleSubst index="0" Format="1">
         <Substitution in="a" out="b"/>
       </SingleSubst>
     </Lookup>
diff --git a/Tests/mtiLib/data/lookupnames-backward.ttx.GSUB b/Tests/mtiLib/data/lookupnames-backward.ttx.GSUB
index cb358d7..698012c 100644
--- a/Tests/mtiLib/data/lookupnames-backward.ttx.GSUB
+++ b/Tests/mtiLib/data/lookupnames-backward.ttx.GSUB
@@ -39,7 +39,7 @@
       <LookupType value="1"/>
       <LookupFlag value="0"/>
       <!-- SubTableCount=1 -->
-      <SingleSubst index="0">
+      <SingleSubst index="0" Format="1">
         <Substitution in="uuvowelsignkannada" out="uuvowelsignaltkannada"/>
         <Substitution in="uvowelsignkannada" out="uvowelsignaltkannada"/>
       </SingleSubst>
@@ -49,11 +49,11 @@
       <LookupFlag value="0"/>
       <!-- SubTableCount=1 -->
       <ChainContextSubst index="0" Format="2">
-        <Coverage>
+        <Coverage Format="1">
           <Glyph value="uvowelsignkannada"/>
           <Glyph value="uuvowelsignkannada"/>
         </Coverage>
-        <BacktrackClassDef>
+        <BacktrackClassDef Format="2">
           <ClassDef glyph="pakannada" class="1"/>
           <ClassDef glyph="pevowelkannada" class="1"/>
           <ClassDef glyph="phakannada" class="1"/>
@@ -61,7 +61,7 @@
           <ClassDef glyph="vakannada" class="1"/>
           <ClassDef glyph="vevowelkannada" class="1"/>
         </BacktrackClassDef>
-        <InputClassDef>
+        <InputClassDef Format="1">
           <ClassDef glyph="uuvowelsignkannada" class="1"/>
           <ClassDef glyph="uvowelsignkannada" class="1"/>
         </InputClassDef>
diff --git a/Tests/mtiLib/data/lookupnames-forward.ttx.GSUB b/Tests/mtiLib/data/lookupnames-forward.ttx.GSUB
index 249d605..15e48d0 100644
--- a/Tests/mtiLib/data/lookupnames-forward.ttx.GSUB
+++ b/Tests/mtiLib/data/lookupnames-forward.ttx.GSUB
@@ -40,11 +40,11 @@
       <LookupFlag value="0"/>
       <!-- SubTableCount=1 -->
       <ChainContextSubst index="0" Format="2">
-        <Coverage>
+        <Coverage Format="1">
           <Glyph value="uvowelsignkannada"/>
           <Glyph value="uuvowelsignkannada"/>
         </Coverage>
-        <BacktrackClassDef>
+        <BacktrackClassDef Format="2">
           <ClassDef glyph="pakannada" class="1"/>
           <ClassDef glyph="pevowelkannada" class="1"/>
           <ClassDef glyph="phakannada" class="1"/>
@@ -52,7 +52,7 @@
           <ClassDef glyph="vakannada" class="1"/>
           <ClassDef glyph="vevowelkannada" class="1"/>
         </BacktrackClassDef>
-        <InputClassDef>
+        <InputClassDef Format="1">
           <ClassDef glyph="uuvowelsignkannada" class="1"/>
           <ClassDef glyph="uvowelsignkannada" class="1"/>
         </InputClassDef>
@@ -78,7 +78,7 @@
       <LookupType value="1"/>
       <LookupFlag value="0"/>
       <!-- SubTableCount=1 -->
-      <SingleSubst index="0">
+      <SingleSubst index="0" Format="1">
         <Substitution in="uuvowelsignkannada" out="uuvowelsignaltkannada"/>
         <Substitution in="uvowelsignkannada" out="uvowelsignaltkannada"/>
       </SingleSubst>
diff --git a/Tests/mtiLib/data/mixed-toplevels.ttx.GSUB b/Tests/mtiLib/data/mixed-toplevels.ttx.GSUB
index 249d605..15e48d0 100644
--- a/Tests/mtiLib/data/mixed-toplevels.ttx.GSUB
+++ b/Tests/mtiLib/data/mixed-toplevels.ttx.GSUB
@@ -40,11 +40,11 @@
       <LookupFlag value="0"/>
       <!-- SubTableCount=1 -->
       <ChainContextSubst index="0" Format="2">
-        <Coverage>
+        <Coverage Format="1">
           <Glyph value="uvowelsignkannada"/>
           <Glyph value="uuvowelsignkannada"/>
         </Coverage>
-        <BacktrackClassDef>
+        <BacktrackClassDef Format="2">
           <ClassDef glyph="pakannada" class="1"/>
           <ClassDef glyph="pevowelkannada" class="1"/>
           <ClassDef glyph="phakannada" class="1"/>
@@ -52,7 +52,7 @@
           <ClassDef glyph="vakannada" class="1"/>
           <ClassDef glyph="vevowelkannada" class="1"/>
         </BacktrackClassDef>
-        <InputClassDef>
+        <InputClassDef Format="1">
           <ClassDef glyph="uuvowelsignkannada" class="1"/>
           <ClassDef glyph="uvowelsignkannada" class="1"/>
         </InputClassDef>
@@ -78,7 +78,7 @@
       <LookupType value="1"/>
       <LookupFlag value="0"/>
       <!-- SubTableCount=1 -->
-      <SingleSubst index="0">
+      <SingleSubst index="0" Format="1">
         <Substitution in="uuvowelsignkannada" out="uuvowelsignaltkannada"/>
         <Substitution in="uvowelsignkannada" out="uvowelsignaltkannada"/>
       </SingleSubst>
diff --git a/Tests/mtiLib/data/mti/chained-glyph.ttx.GPOS b/Tests/mtiLib/data/mti/chained-glyph.ttx.GPOS
index b550c70..811b1df 100644
--- a/Tests/mtiLib/data/mti/chained-glyph.ttx.GPOS
+++ b/Tests/mtiLib/data/mti/chained-glyph.ttx.GPOS
@@ -5,10 +5,10 @@
     <!-- LookupCount=2 -->
     <Lookup index="0">
       <LookupType value="8"/>
-      <LookupFlag value="512"/><!-- markAttachmentType[2] -->
+      <LookupFlag value="512"/>
       <!-- SubTableCount=1 -->
       <ChainContextPos index="0" Format="1">
-        <Coverage>
+        <Coverage Format="1">
           <Glyph value="uuvowelsignsinh"/>
           <Glyph value="uvowelsignsinh"/>
         </Coverage>
diff --git a/Tests/mtiLib/data/mti/chained-glyph.ttx.GSUB b/Tests/mtiLib/data/mti/chained-glyph.ttx.GSUB
index 7dfdb84..67aa902 100644
--- a/Tests/mtiLib/data/mti/chained-glyph.ttx.GSUB
+++ b/Tests/mtiLib/data/mti/chained-glyph.ttx.GSUB
@@ -5,10 +5,10 @@
     <!-- LookupCount=2 -->
     <Lookup index="0">
       <LookupType value="6"/>
-      <LookupFlag value="512"/><!-- markAttachmentType[2] -->
+      <LookupFlag value="512"/>
       <!-- SubTableCount=1 -->
       <ChainContextSubst index="0" Format="1">
-        <Coverage>
+        <Coverage Format="1">
           <Glyph value="uuvowelsignsinh"/>
           <Glyph value="uvowelsignsinh"/>
         </Coverage>
diff --git a/Tests/mtiLib/data/mti/chainedclass.ttx.GSUB b/Tests/mtiLib/data/mti/chainedclass.ttx.GSUB
index fcd7569..cfa391f 100644
--- a/Tests/mtiLib/data/mti/chainedclass.ttx.GSUB
+++ b/Tests/mtiLib/data/mti/chainedclass.ttx.GSUB
@@ -8,11 +8,11 @@
       <LookupFlag value="0"/>
       <!-- SubTableCount=1 -->
       <ChainContextSubst index="0" Format="2">
-        <Coverage>
+        <Coverage Format="1">
           <Glyph value="uvowelsignkannada"/>
           <Glyph value="uuvowelsignkannada"/>
         </Coverage>
-        <BacktrackClassDef>
+        <BacktrackClassDef Format="2">
           <ClassDef glyph="pakannada" class="1"/>
           <ClassDef glyph="pevowelkannada" class="1"/>
           <ClassDef glyph="phakannada" class="1"/>
@@ -20,7 +20,7 @@
           <ClassDef glyph="vakannada" class="1"/>
           <ClassDef glyph="vevowelkannada" class="1"/>
         </BacktrackClassDef>
-        <InputClassDef>
+        <InputClassDef Format="1">
           <ClassDef glyph="uuvowelsignkannada" class="1"/>
           <ClassDef glyph="uvowelsignkannada" class="1"/>
         </InputClassDef>
@@ -46,7 +46,7 @@
       <LookupType value="1"/>
       <LookupFlag value="0"/>
       <!-- SubTableCount=1 -->
-      <SingleSubst index="0">
+      <SingleSubst index="0" Format="1">
         <Substitution in="uuvowelsignkannada" out="uuvowelsignaltkannada"/>
         <Substitution in="uvowelsignkannada" out="uvowelsignaltkannada"/>
       </SingleSubst>
diff --git a/Tests/mtiLib/data/mti/chainedcoverage.ttx.GSUB b/Tests/mtiLib/data/mti/chainedcoverage.ttx.GSUB
index 4f312c6..7c807a4 100644
--- a/Tests/mtiLib/data/mti/chainedcoverage.ttx.GSUB
+++ b/Tests/mtiLib/data/mti/chainedcoverage.ttx.GSUB
@@ -9,7 +9,7 @@
       <!-- SubTableCount=1 -->
       <ChainContextSubst index="0" Format="3">
         <!-- BacktrackGlyphCount=1 -->
-        <BacktrackCoverage index="0">
+        <BacktrackCoverage index="0" Format="2">
           <Glyph value="zero"/>
           <Glyph value="one"/>
           <Glyph value="two"/>
@@ -22,11 +22,11 @@
           <Glyph value="nine"/>
         </BacktrackCoverage>
         <!-- InputGlyphCount=1 -->
-        <InputCoverage index="0">
+        <InputCoverage index="0" Format="1">
           <Glyph value="slash"/>
         </InputCoverage>
         <!-- LookAheadGlyphCount=1 -->
-        <LookAheadCoverage index="0">
+        <LookAheadCoverage index="0" Format="2">
           <Glyph value="zero"/>
           <Glyph value="one"/>
           <Glyph value="two"/>
@@ -49,7 +49,7 @@
       <LookupType value="1"/>
       <LookupFlag value="0"/>
       <!-- SubTableCount=1 -->
-      <SingleSubst index="0">
+      <SingleSubst index="0" Format="1">
         <Substitution in="slash" out="fraction"/>
       </SingleSubst>
     </Lookup>
diff --git a/Tests/mtiLib/data/mti/gdefattach.ttx.GDEF b/Tests/mtiLib/data/mti/gdefattach.ttx.GDEF
index 79aed8f..cc4c70d 100644
--- a/Tests/mtiLib/data/mti/gdefattach.ttx.GDEF
+++ b/Tests/mtiLib/data/mti/gdefattach.ttx.GDEF
@@ -2,7 +2,7 @@
 <GDEF>
   <Version value="0x00010000"/>
   <AttachList>
-    <Coverage>
+    <Coverage Format="1">
       <Glyph value="A"/>
       <Glyph value="B"/>
     </Coverage>
diff --git a/Tests/mtiLib/data/mti/gdefclasses.ttx.GDEF b/Tests/mtiLib/data/mti/gdefclasses.ttx.GDEF
index c3c9d68..e298c28 100644
--- a/Tests/mtiLib/data/mti/gdefclasses.ttx.GDEF
+++ b/Tests/mtiLib/data/mti/gdefclasses.ttx.GDEF
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <GDEF>
   <Version value="0x00010000"/>
-  <GlyphClassDef>
+  <GlyphClassDef Format="1">
     <ClassDef glyph="A" class="1"/>
     <ClassDef glyph="C" class="1"/>
     <ClassDef glyph="acute" class="3"/>
diff --git a/Tests/mtiLib/data/mti/gdefligcaret.ttx.GDEF b/Tests/mtiLib/data/mti/gdefligcaret.ttx.GDEF
index 174af8e..48f7347 100644
--- a/Tests/mtiLib/data/mti/gdefligcaret.ttx.GDEF
+++ b/Tests/mtiLib/data/mti/gdefligcaret.ttx.GDEF
@@ -2,7 +2,7 @@
 <GDEF>
   <Version value="0x00010000"/>
   <LigCaretList>
-    <Coverage>
+    <Coverage Format="1">
       <Glyph value="uniFB01"/>
       <Glyph value="ffi"/>
     </Coverage>
diff --git a/Tests/mtiLib/data/mti/gdefmarkattach.ttx.GDEF b/Tests/mtiLib/data/mti/gdefmarkattach.ttx.GDEF
index 97683ab..b6cbe10 100644
--- a/Tests/mtiLib/data/mti/gdefmarkattach.ttx.GDEF
+++ b/Tests/mtiLib/data/mti/gdefmarkattach.ttx.GDEF
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <GDEF>
   <Version value="0x00010000"/>
-  <MarkAttachClassDef>
+  <MarkAttachClassDef Format="1">
     <ClassDef glyph="breve" class="1"/>
     <ClassDef glyph="commaacent" class="2"/>
     <ClassDef glyph="dotbelow" class="2"/>
diff --git a/Tests/mtiLib/data/mti/gdefmarkfilter.ttx.GDEF b/Tests/mtiLib/data/mti/gdefmarkfilter.ttx.GDEF
index 4f3593e..3b23481 100644
--- a/Tests/mtiLib/data/mti/gdefmarkfilter.ttx.GDEF
+++ b/Tests/mtiLib/data/mti/gdefmarkfilter.ttx.GDEF
@@ -5,17 +5,17 @@
     <MarkSetTableFormat value="1"/>
     <!-- MarkSetCount=4 -->
     <Coverage index="0" empty="1"/>
-    <Coverage index="1">
+    <Coverage index="1" Format="1">
       <Glyph value="breve"/>
       <Glyph value="acute"/>
       <Glyph value="dotabove"/>
     </Coverage>
-    <Coverage index="2">
+    <Coverage index="2" Format="1">
       <Glyph value="dotbelow"/>
       <Glyph value="cedilla"/>
       <Glyph value="commaaccent"/>
     </Coverage>
-    <Coverage index="3">
+    <Coverage index="3" Format="1">
       <Glyph value="dotbelow"/>
       <Glyph value="dotabove"/>
     </Coverage>
diff --git a/Tests/mtiLib/data/mti/gposcursive.ttx.GPOS b/Tests/mtiLib/data/mti/gposcursive.ttx.GPOS
index 6c08c50..2965139 100644
--- a/Tests/mtiLib/data/mti/gposcursive.ttx.GPOS
+++ b/Tests/mtiLib/data/mti/gposcursive.ttx.GPOS
@@ -8,7 +8,7 @@
       <LookupFlag value="0"/>
       <!-- SubTableCount=1 -->
       <CursivePos index="0" Format="1">
-        <Coverage>
+        <Coverage Format="1">
           <Glyph value="A"/>
           <Glyph value="B"/>
         </Coverage>
diff --git a/Tests/mtiLib/data/mti/gposkernset.ttx.GPOS b/Tests/mtiLib/data/mti/gposkernset.ttx.GPOS
index a837123..edfea10 100644
--- a/Tests/mtiLib/data/mti/gposkernset.ttx.GPOS
+++ b/Tests/mtiLib/data/mti/gposkernset.ttx.GPOS
@@ -8,7 +8,7 @@
       <LookupFlag value="0"/>
       <!-- SubTableCount=2 -->
       <PairPos index="0" Format="1">
-        <Coverage>
+        <Coverage Format="1">
           <Glyph value="Acircumflex"/>
           <Glyph value="T"/>
         </Coverage>
@@ -31,7 +31,7 @@
         </PairSet>
       </PairPos>
       <PairPos index="1" Format="2">
-        <Coverage>
+        <Coverage Format="1">
           <Glyph value="A"/>
           <Glyph value="Acircumflex"/>
           <Glyph value="T"/>
@@ -44,7 +44,7 @@
         </Coverage>
         <ValueFormat1 value="4"/>
         <ValueFormat2 value="0"/>
-        <ClassDef1>
+        <ClassDef1 Format="2">
           <ClassDef glyph="A" class="1"/>
           <ClassDef glyph="Aacute" class="1"/>
           <ClassDef glyph="Acircumflex" class="1"/>
@@ -55,7 +55,7 @@
           <ClassDef glyph="Ograve" class="2"/>
           <ClassDef glyph="T" class="3"/>
         </ClassDef1>
-        <ClassDef2>
+        <ClassDef2 Format="2">
           <ClassDef glyph="V" class="1"/>
           <ClassDef glyph="a" class="2"/>
           <ClassDef glyph="aacute" class="2"/>
diff --git a/Tests/mtiLib/data/mti/gposmarktobase.ttx.GPOS b/Tests/mtiLib/data/mti/gposmarktobase.ttx.GPOS
index e6e2102..b0a74e7 100644
--- a/Tests/mtiLib/data/mti/gposmarktobase.ttx.GPOS
+++ b/Tests/mtiLib/data/mti/gposmarktobase.ttx.GPOS
@@ -8,7 +8,7 @@
       <LookupFlag value="0"/>
       <!-- SubTableCount=1 -->
       <MarkBasePos index="0" Format="1">
-        <MarkCoverage>
+        <MarkCoverage Format="2">
           <Glyph value="aimatrabindigurmukhi"/>
           <Glyph value="aimatragurmukhi"/>
           <Glyph value="aimatratippigurmukhi"/>
@@ -22,7 +22,7 @@
           <Glyph value="oomatragurmukhi"/>
           <Glyph value="oomatratippigurmukhi"/>
         </MarkCoverage>
-        <BaseCoverage>
+        <BaseCoverage Format="2">
           <Glyph value="lagurmukhi"/>
           <Glyph value="lanuktagurmukhi"/>
           <Glyph value="nagurmukhi"/>
diff --git a/Tests/mtiLib/data/mti/gpospairclass.ttx.GPOS b/Tests/mtiLib/data/mti/gpospairclass.ttx.GPOS
index 32b35ae..567b2a7 100644
--- a/Tests/mtiLib/data/mti/gpospairclass.ttx.GPOS
+++ b/Tests/mtiLib/data/mti/gpospairclass.ttx.GPOS
@@ -8,7 +8,7 @@
       <LookupFlag value="0"/>
       <!-- SubTableCount=1 -->
       <PairPos index="0" Format="2">
-        <Coverage>
+        <Coverage Format="1">
           <Glyph value="A"/>
           <Glyph value="Acircumflex"/>
           <Glyph value="T"/>
@@ -21,7 +21,7 @@
         </Coverage>
         <ValueFormat1 value="4"/>
         <ValueFormat2 value="0"/>
-        <ClassDef1>
+        <ClassDef1 Format="2">
           <ClassDef glyph="A" class="1"/>
           <ClassDef glyph="Aacute" class="1"/>
           <ClassDef glyph="Acircumflex" class="1"/>
@@ -32,7 +32,7 @@
           <ClassDef glyph="Ograve" class="2"/>
           <ClassDef glyph="T" class="3"/>
         </ClassDef1>
-        <ClassDef2>
+        <ClassDef2 Format="2">
           <ClassDef glyph="V" class="1"/>
           <ClassDef glyph="a" class="2"/>
           <ClassDef glyph="aacute" class="2"/>
diff --git a/Tests/mtiLib/data/mti/gpospairglyph.ttx.GPOS b/Tests/mtiLib/data/mti/gpospairglyph.ttx.GPOS
index f03a90e..ea0161b 100644
--- a/Tests/mtiLib/data/mti/gpospairglyph.ttx.GPOS
+++ b/Tests/mtiLib/data/mti/gpospairglyph.ttx.GPOS
@@ -8,7 +8,7 @@
       <LookupFlag value="0"/>
       <!-- SubTableCount=1 -->
       <PairPos index="0" Format="1">
-        <Coverage>
+        <Coverage Format="1">
           <Glyph value="A"/>
           <Glyph value="Acircumflex"/>
           <Glyph value="T"/>
diff --git a/Tests/mtiLib/data/mti/gpossingle.ttx.GPOS b/Tests/mtiLib/data/mti/gpossingle.ttx.GPOS
index c3bdbf6..adbb44f 100644
--- a/Tests/mtiLib/data/mti/gpossingle.ttx.GPOS
+++ b/Tests/mtiLib/data/mti/gpossingle.ttx.GPOS
@@ -8,7 +8,7 @@
       <LookupFlag value="0"/>
       <!-- SubTableCount=1 -->
       <SinglePos index="0" Format="1">
-        <Coverage>
+        <Coverage Format="2">
           <Glyph value="bsuperior"/>
           <Glyph value="isuperior"/>
           <Glyph value="vsuperior"/>
diff --git a/Tests/mtiLib/data/mti/gsubalternate.ttx.GSUB b/Tests/mtiLib/data/mti/gsubalternate.ttx.GSUB
index 86b0b73..4184325 100644
--- a/Tests/mtiLib/data/mti/gsubalternate.ttx.GSUB
+++ b/Tests/mtiLib/data/mti/gsubalternate.ttx.GSUB
@@ -7,7 +7,7 @@
       <LookupType value="3"/>
       <LookupFlag value="0"/>
       <!-- SubTableCount=1 -->
-      <AlternateSubst index="0">
+      <AlternateSubst index="0" Format="1">
         <AlternateSet glyph="eight">
           <Alternate glyph="uniF738"/>
           <Alternate glyph="uniE0C0"/>
diff --git a/Tests/mtiLib/data/mti/gsubligature.ttx.GSUB b/Tests/mtiLib/data/mti/gsubligature.ttx.GSUB
index 26c88c8..ad8f505 100644
--- a/Tests/mtiLib/data/mti/gsubligature.ttx.GSUB
+++ b/Tests/mtiLib/data/mti/gsubligature.ttx.GSUB
@@ -7,7 +7,7 @@
       <LookupType value="4"/>
       <LookupFlag value="0"/>
       <!-- SubTableCount=1 -->
-      <LigatureSubst index="0">
+      <LigatureSubst index="0" Format="1">
         <LigatureSet glyph="I">
           <Ligature components="J" glyph="IJ"/>
         </LigatureSet>
diff --git a/Tests/mtiLib/data/mti/gsubmultiple.ttx.GSUB b/Tests/mtiLib/data/mti/gsubmultiple.ttx.GSUB
index 5bedfba..a68a45a 100644
--- a/Tests/mtiLib/data/mti/gsubmultiple.ttx.GSUB
+++ b/Tests/mtiLib/data/mti/gsubmultiple.ttx.GSUB
@@ -7,7 +7,7 @@
       <LookupType value="2"/>
       <LookupFlag value="0"/>
       <!-- SubTableCount=1 -->
-      <MultipleSubst index="0">
+      <MultipleSubst index="0" Format="1">
         <Substitution in="janyevoweltelugu" out="jaivoweltelugu,nyasubscripttelugu"/>
         <Substitution in="kassevoweltelugu" out="kaivoweltelugu,ssasubscripttelugu"/>
       </MultipleSubst>
diff --git a/Tests/mtiLib/data/mti/gsubreversechanined.ttx.GSUB b/Tests/mtiLib/data/mti/gsubreversechanined.ttx.GSUB
index d705af5..62ba14f 100644
--- a/Tests/mtiLib/data/mti/gsubreversechanined.ttx.GSUB
+++ b/Tests/mtiLib/data/mti/gsubreversechanined.ttx.GSUB
@@ -5,17 +5,17 @@
     <!-- LookupCount=1 -->
     <Lookup index="0">
       <LookupType value="8"/>
-      <LookupFlag value="9"/><!-- rightToLeft ignoreMarks -->
+      <LookupFlag value="9"/>
       <!-- SubTableCount=3 -->
       <ReverseChainSingleSubst index="0" Format="1">
-        <Coverage>
+        <Coverage Format="2">
           <Glyph value="rayf2"/>
           <Glyph value="reyf2"/>
           <Glyph value="yayf2"/>
           <Glyph value="zayf2"/>
         </Coverage>
         <!-- BacktrackGlyphCount=1 -->
-        <BacktrackCoverage index="0">
+        <BacktrackCoverage index="0" Format="2">
           <Glyph value="bayi1"/>
           <Glyph value="jeemi1"/>
           <Glyph value="kafi1"/>
@@ -33,14 +33,14 @@
         <Substitute index="3" value="zayf1"/>
       </ReverseChainSingleSubst>
       <ReverseChainSingleSubst index="1" Format="1">
-        <Coverage>
+        <Coverage Format="2">
           <Glyph value="ayehf2"/>
           <Glyph value="hamzayeharabf2"/>
           <Glyph value="hamzayehf2"/>
           <Glyph value="yehf2"/>
         </Coverage>
         <!-- BacktrackGlyphCount=1 -->
-        <BacktrackCoverage index="0">
+        <BacktrackCoverage index="0" Format="1">
           <Glyph value="bayi1"/>
           <Glyph value="kafi1"/>
           <Glyph value="ghafi1"/>
@@ -58,14 +58,14 @@
         <Substitute index="3" value="yehf1"/>
       </ReverseChainSingleSubst>
       <ReverseChainSingleSubst index="2" Format="1">
-        <Coverage>
+        <Coverage Format="1">
           <Glyph value="dal"/>
           <Glyph value="del"/>
           <Glyph value="zal"/>
         </Coverage>
         <!-- BacktrackGlyphCount=0 -->
         <!-- LookAheadGlyphCount=1 -->
-        <LookAheadCoverage index="0">
+        <LookAheadCoverage index="0" Format="2">
           <Glyph value="ray"/>
           <Glyph value="rey"/>
           <Glyph value="zay"/>
diff --git a/Tests/mtiLib/data/mti/gsubsingle.ttx.GSUB b/Tests/mtiLib/data/mti/gsubsingle.ttx.GSUB
index dc6a295..525b365 100644
--- a/Tests/mtiLib/data/mti/gsubsingle.ttx.GSUB
+++ b/Tests/mtiLib/data/mti/gsubsingle.ttx.GSUB
@@ -7,7 +7,7 @@
       <LookupType value="1"/>
       <LookupFlag value="0"/>
       <!-- SubTableCount=1 -->
-      <SingleSubst index="0">
+      <SingleSubst index="0" Format="1">
         <Substitution in="onehalf" out="onehalf.alt"/>
         <Substitution in="onequarter" out="onequarter.alt"/>
         <Substitution in="threequarters" out="threequarters.alt"/>
diff --git a/Tests/mtiLib/data/mti/mark-to-ligature.ttx.GPOS b/Tests/mtiLib/data/mti/mark-to-ligature.ttx.GPOS
index b5f275e..7e02fe0 100644
--- a/Tests/mtiLib/data/mti/mark-to-ligature.ttx.GPOS
+++ b/Tests/mtiLib/data/mti/mark-to-ligature.ttx.GPOS
@@ -8,7 +8,7 @@
       <LookupFlag value="0"/>
       <!-- SubTableCount=1 -->
       <MarkLigPos index="0" Format="1">
-        <MarkCoverage>
+        <MarkCoverage Format="2">
           <Glyph value="AlefSuperiorNS"/>
           <Glyph value="DammaNS"/>
           <Glyph value="DammaRflxNS"/>
@@ -37,7 +37,7 @@
           <Glyph value="UltapeshNS"/>
           <Glyph value="WaslaNS"/>
         </MarkCoverage>
-        <LigatureCoverage>
+        <LigatureCoverage Format="2">
           <Glyph value="AinIni.12m_MeemFin.02"/>
           <Glyph value="AinIni_YehBarreeFin"/>
           <Glyph value="AinMed_YehBarreeFin"/>
diff --git a/Tests/mtiLib/mti_test.py b/Tests/mtiLib/mti_test.py
index f0e7bdf..4916828 100644
--- a/Tests/mtiLib/mti_test.py
+++ b/Tests/mtiLib/mti_test.py
@@ -1,8 +1,10 @@
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.xmlWriter import XMLWriter
 from fontTools.ttLib import TTFont
 from fontTools import mtiLib
 import difflib
-from io import StringIO
 import os
 import sys
 import unittest
diff --git a/Tests/otlLib/__init__.py b/Tests/otlLib/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/Tests/otlLib/__init__.py
+++ /dev/null
diff --git a/Tests/otlLib/builder_test.py b/Tests/otlLib/builder_test.py
index 1c2c324..83f7c82 100644
--- a/Tests/otlLib/builder_test.py
+++ b/Tests/otlLib/builder_test.py
@@ -1,9 +1,7 @@
-import io
-import struct
-from fontTools.misc.fixedTools import floatToFixed
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
 from fontTools.misc.testTools import getXML
-from fontTools.otlLib import builder, error
-from fontTools import ttLib
+from fontTools.otlLib import builder
 from fontTools.ttLib.tables import otTables
 import pytest
 
@@ -474,7 +472,7 @@
         assert getXML(lookup.toXML) == [
             "<Lookup>",
             '  <LookupType value="1"/>',
-            '  <LookupFlag value="7"/><!-- rightToLeft ignoreBaseGlyphs ignoreLigatures -->',
+            '  <LookupFlag value="7"/>',
             "  <!-- SubTableCount=2 -->",
             '  <SingleSubst index="0">',
             '    <Substitution in="one" out="two"/>',
@@ -495,6 +493,14 @@
             ),
         ) 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"})
@@ -520,7 +526,7 @@
         assert getXML(lookup.toXML) == [
             "<Lookup>",
             '  <LookupType value="1"/>',
-            '  <LookupFlag value="17"/><!-- rightToLeft useMarkFilteringSet -->',
+            '  <LookupFlag value="17"/>',
             "  <!-- SubTableCount=1 -->",
             '  <SingleSubst index="0">',
             '    <Substitution in="one" out="two"/>',
@@ -839,12 +845,8 @@
             "  <!-- Class2Count=3 -->",
             '  <Class1Record index="0">',
             '    <Class2Record index="0">',
-            '      <Value1 XPlacement="0" YPlacement="0"/>',
-            '      <Value2 XPlacement="0"/>',
             "    </Class2Record>",
             '    <Class2Record index="1">',
-            '      <Value1 XPlacement="0" YPlacement="0"/>',
-            '      <Value2 XPlacement="0"/>',
             "    </Class2Record>",
             '    <Class2Record index="2">',
             '      <Value1 XPlacement="-80" YPlacement="-20"/>',
@@ -853,15 +855,12 @@
             "  </Class1Record>",
             '  <Class1Record index="1">',
             '    <Class2Record index="0">',
-            '      <Value1 XPlacement="0" YPlacement="0"/>',
-            '      <Value2 XPlacement="0"/>',
             "    </Class2Record>",
             '    <Class2Record index="1">',
-            '      <Value1 XPlacement="0" YPlacement="0"/>',
             '      <Value2 XPlacement="-20"/>',
             "    </Class2Record>",
             '    <Class2Record index="2">',
-            '      <Value1 XPlacement="0" YPlacement="0"/>',
+            "      <Value1/>",
             '      <Value2 XPlacement="-50"/>',
             "    </Class2Record>",
             "  </Class1Record>",
@@ -918,11 +917,9 @@
                 ("A", "zero"): (d0, d50),
                 ("A", "one"): (None, d20),
                 ("B", "five"): (d8020, d50),
-
             },
             self.GLYPHMAP,
         )
-
         assert getXML(subtable.toXML) == [
             '<PairPos Format="1">',
             "  <Coverage>",
@@ -936,12 +933,10 @@
             "    <!-- PairValueCount=2 -->",
             '    <PairValueRecord index="0">',
             '      <SecondGlyph value="zero"/>',
-            '      <Value1 XPlacement="0" YPlacement="0"/>',
             '      <Value2 XPlacement="-50"/>',
             "    </PairValueRecord>",
             '    <PairValueRecord index="1">',
             '      <SecondGlyph value="one"/>',
-            '      <Value1 XPlacement="0" YPlacement="0"/>',
             '      <Value2 XPlacement="-20"/>',
             "    </PairValueRecord>",
             "  </PairSet>",
@@ -1042,8 +1037,8 @@
             "  </Coverage>",
             '  <ValueFormat value="3"/>',
             "  <!-- ValueCount=2 -->",
-            '  <Value index="0" XPlacement="777" YPlacement="0"/>',
-            '  <Value index="1" XPlacement="0" YPlacement="-888"/>',
+            '  <Value index="0" XPlacement="777"/>',
+            '  <Value index="1" YPlacement="-888"/>',
             "</SinglePos>",
         ]
 
@@ -1112,353 +1107,6 @@
         assert not b.canAdd({"d", "e", "f"})
         assert not b.canAdd({"f"})
 
-    def test_add_exception(self):
-        b = builder.ClassDefBuilder(useClass0=True)
-        b.add({"a", "b", "c"})
-        with pytest.raises(error.OpenTypeLibError):
-            b.add({"a", "d"})
-
-
-buildStatTable_test_data = [
-    ([
-        dict(
-            tag="wght",
-            name="Weight",
-            values=[
-                dict(value=100, name='Thin'),
-                dict(value=400, name='Regular', flags=0x2),
-                dict(value=900, name='Black')])], None, "Regular", [
-        '  <STAT>',
-        '    <Version value="0x00010001"/>',
-        '    <DesignAxisRecordSize value="8"/>',
-        '    <!-- DesignAxisCount=1 -->',
-        '    <DesignAxisRecord>',
-        '      <Axis index="0">',
-        '        <AxisTag value="wght"/>',
-        '        <AxisNameID value="257"/>  <!-- Weight -->',
-        '        <AxisOrdering value="0"/>',
-        '      </Axis>',
-        '    </DesignAxisRecord>',
-        '    <!-- AxisValueCount=3 -->',
-        '    <AxisValueArray>',
-        '      <AxisValue index="0" Format="1">',
-        '        <AxisIndex value="0"/>',
-        '        <Flags value="0"/>',
-        '        <ValueNameID value="258"/>  <!-- Thin -->',
-        '        <Value value="100.0"/>',
-        '      </AxisValue>',
-        '      <AxisValue index="1" Format="1">',
-        '        <AxisIndex value="0"/>',
-        '        <Flags value="2"/>  <!-- ElidableAxisValueName -->',
-        '        <ValueNameID value="256"/>  <!-- Regular -->',
-        '        <Value value="400.0"/>',
-        '      </AxisValue>',
-        '      <AxisValue index="2" Format="1">',
-        '        <AxisIndex value="0"/>',
-        '        <Flags value="0"/>',
-        '        <ValueNameID value="259"/>  <!-- Black -->',
-        '        <Value value="900.0"/>',
-        '      </AxisValue>',
-        '    </AxisValueArray>',
-        '    <ElidedFallbackNameID value="256"/>  <!-- Regular -->',
-        '  </STAT>']),
-    ([
-        dict(
-            tag="wght",
-            name=dict(en="Weight", nl="Gewicht"),
-            values=[
-                dict(value=100, name=dict(en='Thin', nl='Dun')),
-                dict(value=400, name='Regular', flags=0x2),
-                dict(value=900, name='Black'),
-            ]),
-        dict(
-            tag="wdth",
-            name="Width",
-            values=[
-                dict(value=50, name='Condensed'),
-                dict(value=100, name='Regular', flags=0x2),
-                dict(value=200, name='Extended')])], None, 2, [
-        '  <STAT>',
-        '    <Version value="0x00010001"/>',
-        '    <DesignAxisRecordSize value="8"/>',
-        '    <!-- DesignAxisCount=2 -->',
-        '    <DesignAxisRecord>',
-        '      <Axis index="0">',
-        '        <AxisTag value="wght"/>',
-        '        <AxisNameID value="256"/>  <!-- Weight -->',
-        '        <AxisOrdering value="0"/>',
-        '      </Axis>',
-        '      <Axis index="1">',
-        '        <AxisTag value="wdth"/>',
-        '        <AxisNameID value="260"/>  <!-- Width -->',
-        '        <AxisOrdering value="1"/>',
-        '      </Axis>',
-        '    </DesignAxisRecord>',
-        '    <!-- AxisValueCount=6 -->',
-        '    <AxisValueArray>',
-        '      <AxisValue index="0" Format="1">',
-        '        <AxisIndex value="0"/>',
-        '        <Flags value="0"/>',
-        '        <ValueNameID value="257"/>  <!-- Thin -->',
-        '        <Value value="100.0"/>',
-        '      </AxisValue>',
-        '      <AxisValue index="1" Format="1">',
-        '        <AxisIndex value="0"/>',
-        '        <Flags value="2"/>  <!-- ElidableAxisValueName -->',
-        '        <ValueNameID value="258"/>  <!-- Regular -->',
-        '        <Value value="400.0"/>',
-        '      </AxisValue>',
-        '      <AxisValue index="2" Format="1">',
-        '        <AxisIndex value="0"/>',
-        '        <Flags value="0"/>',
-        '        <ValueNameID value="259"/>  <!-- Black -->',
-        '        <Value value="900.0"/>',
-        '      </AxisValue>',
-        '      <AxisValue index="3" Format="1">',
-        '        <AxisIndex value="1"/>',
-        '        <Flags value="0"/>',
-        '        <ValueNameID value="261"/>  <!-- Condensed -->',
-        '        <Value value="50.0"/>',
-        '      </AxisValue>',
-        '      <AxisValue index="4" Format="1">',
-        '        <AxisIndex value="1"/>',
-        '        <Flags value="2"/>  <!-- ElidableAxisValueName -->',
-        '        <ValueNameID value="258"/>  <!-- Regular -->',
-        '        <Value value="100.0"/>',
-        '      </AxisValue>',
-        '      <AxisValue index="5" Format="1">',
-        '        <AxisIndex value="1"/>',
-        '        <Flags value="0"/>',
-        '        <ValueNameID value="262"/>  <!-- Extended -->',
-        '        <Value value="200.0"/>',
-        '      </AxisValue>',
-        '    </AxisValueArray>',
-        '    <ElidedFallbackNameID value="2"/>  <!-- missing from name table -->',
-        '  </STAT>']),
-    ([
-        dict(
-            tag="wght",
-            name="Weight",
-            values=[
-                dict(value=400, name='Regular', flags=0x2),
-                dict(value=600, linkedValue=650, name='Bold')])], None, 18, [
-        '  <STAT>',
-        '    <Version value="0x00010001"/>',
-        '    <DesignAxisRecordSize value="8"/>',
-        '    <!-- DesignAxisCount=1 -->',
-        '    <DesignAxisRecord>',
-        '      <Axis index="0">',
-        '        <AxisTag value="wght"/>',
-        '        <AxisNameID value="256"/>  <!-- Weight -->',
-        '        <AxisOrdering value="0"/>',
-        '      </Axis>',
-        '    </DesignAxisRecord>',
-        '    <!-- AxisValueCount=2 -->',
-        '    <AxisValueArray>',
-        '      <AxisValue index="0" Format="1">',
-        '        <AxisIndex value="0"/>',
-        '        <Flags value="2"/>  <!-- ElidableAxisValueName -->',
-        '        <ValueNameID value="257"/>  <!-- Regular -->',
-        '        <Value value="400.0"/>',
-        '      </AxisValue>',
-        '      <AxisValue index="1" Format="3">',
-        '        <AxisIndex value="0"/>',
-        '        <Flags value="0"/>',
-        '        <ValueNameID value="258"/>  <!-- Bold -->',
-        '        <Value value="600.0"/>',
-        '        <LinkedValue value="650.0"/>',
-        '      </AxisValue>',
-        '    </AxisValueArray>',
-        '    <ElidedFallbackNameID value="18"/>  <!-- missing from name table -->',
-        '  </STAT>']),
-    ([
-        dict(
-            tag="opsz",
-            name="Optical Size",
-            values=[
-                dict(nominalValue=6, rangeMaxValue=10, name='Small'),
-                dict(rangeMinValue=10, nominalValue=14, rangeMaxValue=24, name='Text', flags=0x2),
-                dict(rangeMinValue=24, nominalValue=600, name='Display')])], None, 2, [
-        '  <STAT>',
-        '    <Version value="0x00010001"/>',
-        '    <DesignAxisRecordSize value="8"/>',
-        '    <!-- DesignAxisCount=1 -->',
-        '    <DesignAxisRecord>',
-        '      <Axis index="0">',
-        '        <AxisTag value="opsz"/>',
-        '        <AxisNameID value="256"/>  <!-- Optical Size -->',
-        '        <AxisOrdering value="0"/>',
-        '      </Axis>',
-        '    </DesignAxisRecord>',
-        '    <!-- AxisValueCount=3 -->',
-        '    <AxisValueArray>',
-        '      <AxisValue index="0" Format="2">',
-        '        <AxisIndex value="0"/>',
-        '        <Flags value="0"/>',
-        '        <ValueNameID value="257"/>  <!-- Small -->',
-        '        <NominalValue value="6.0"/>',
-        '        <RangeMinValue value="-32768.0"/>',
-        '        <RangeMaxValue value="10.0"/>',
-        '      </AxisValue>',
-        '      <AxisValue index="1" Format="2">',
-        '        <AxisIndex value="0"/>',
-        '        <Flags value="2"/>  <!-- ElidableAxisValueName -->',
-        '        <ValueNameID value="258"/>  <!-- Text -->',
-        '        <NominalValue value="14.0"/>',
-        '        <RangeMinValue value="10.0"/>',
-        '        <RangeMaxValue value="24.0"/>',
-        '      </AxisValue>',
-        '      <AxisValue index="2" Format="2">',
-        '        <AxisIndex value="0"/>',
-        '        <Flags value="0"/>',
-        '        <ValueNameID value="259"/>  <!-- Display -->',
-        '        <NominalValue value="600.0"/>',
-        '        <RangeMinValue value="24.0"/>',
-        '        <RangeMaxValue value="32767.99998"/>',
-        '      </AxisValue>',
-        '    </AxisValueArray>',
-        '    <ElidedFallbackNameID value="2"/>  <!-- missing from name table -->',
-        '  </STAT>']),
-    ([
-        dict(
-            tag="wght",
-            name="Weight",
-            ordering=1,
-            values=[]),
-        dict(
-            tag="ABCD",
-            name="ABCDTest",
-            ordering=0,
-            values=[
-                dict(value=100, name="Regular", flags=0x2)])],
-     [dict(location=dict(wght=300, ABCD=100), name='Regular ABCD')], 18, [
-        '  <STAT>',
-        '    <Version value="0x00010002"/>',
-        '    <DesignAxisRecordSize value="8"/>',
-        '    <!-- DesignAxisCount=2 -->',
-        '    <DesignAxisRecord>',
-        '      <Axis index="0">',
-        '        <AxisTag value="wght"/>',
-        '        <AxisNameID value="256"/>  <!-- Weight -->',
-        '        <AxisOrdering value="1"/>',
-        '      </Axis>',
-        '      <Axis index="1">',
-        '        <AxisTag value="ABCD"/>',
-        '        <AxisNameID value="257"/>  <!-- ABCDTest -->',
-        '        <AxisOrdering value="0"/>',
-        '      </Axis>',
-        '    </DesignAxisRecord>',
-        '    <!-- AxisValueCount=2 -->',
-        '    <AxisValueArray>',
-        '      <AxisValue index="0" Format="4">',
-        '        <!-- AxisCount=2 -->',
-        '        <Flags value="0"/>',
-        '        <ValueNameID value="259"/>  <!-- Regular ABCD -->',
-        '        <AxisValueRecord index="0">',
-        '          <AxisIndex value="0"/>',
-        '          <Value value="300.0"/>',
-        '        </AxisValueRecord>',
-        '        <AxisValueRecord index="1">',
-        '          <AxisIndex value="1"/>',
-        '          <Value value="100.0"/>',
-        '        </AxisValueRecord>',
-        '      </AxisValue>',
-        '      <AxisValue index="1" Format="1">',
-        '        <AxisIndex value="1"/>',
-        '        <Flags value="2"/>  <!-- ElidableAxisValueName -->',
-        '        <ValueNameID value="258"/>  <!-- Regular -->',
-        '        <Value value="100.0"/>',
-        '      </AxisValue>',
-        '    </AxisValueArray>',
-        '    <ElidedFallbackNameID value="18"/>  <!-- missing from name table -->',
-        '  </STAT>']),
-]
-
-
-@pytest.mark.parametrize("axes, axisValues, elidedFallbackName, expected_ttx", buildStatTable_test_data)
-def test_buildStatTable(axes, axisValues, elidedFallbackName, expected_ttx):
-    font = ttLib.TTFont()
-    font["name"] = ttLib.newTable("name")
-    font["name"].names = []
-    # https://github.com/fonttools/fonttools/issues/1985
-    # Add nameID < 256 that matches a test axis name, to test whether
-    # the nameID is not reused: AxisNameIDs must be > 255 according
-    # to the spec.
-    font["name"].addMultilingualName(dict(en="ABCDTest"), nameID=6)
-    builder.buildStatTable(font, axes, axisValues, elidedFallbackName)
-    f = io.StringIO()
-    font.saveXML(f, tables=["STAT"])
-    ttx = f.getvalue().splitlines()
-    ttx = ttx[3:-2]  # strip XML header and <ttFont> element
-    assert expected_ttx == ttx
-    # Compile and round-trip
-    f = io.BytesIO()
-    font.save(f)
-    font = ttLib.TTFont(f)
-    f = io.StringIO()
-    font.saveXML(f, tables=["STAT"])
-    ttx = f.getvalue().splitlines()
-    ttx = ttx[3:-2]  # strip XML header and <ttFont> element
-    assert expected_ttx == ttx
-
-
-def test_stat_infinities():
-    negInf = floatToFixed(builder.AXIS_VALUE_NEGATIVE_INFINITY, 16)
-    assert struct.pack(">l", negInf) == b"\x80\x00\x00\x00"
-    posInf = floatToFixed(builder.AXIS_VALUE_POSITIVE_INFINITY, 16)
-    assert struct.pack(">l", posInf) == b"\x7f\xff\xff\xff"
-
-
-class ChainContextualRulesetTest(object):
-    def test_makeRulesets(self):
-        font = ttLib.TTFont()
-        font.setGlyphOrder(["a","b","c","d","A","B","C","D","E"])
-        sb = builder.ChainContextSubstBuilder(font, None)
-        prefix, input_, suffix, lookups = [["a"], ["b"]], [["c"]], [], [None]
-        sb.rules.append(builder.ChainContextualRule(prefix, input_, suffix, lookups))
-
-        prefix, input_, suffix, lookups = [["a"], ["d"]], [["c"]], [], [None]
-        sb.rules.append(builder.ChainContextualRule(prefix, input_, suffix, lookups))
-
-        sb.add_subtable_break(None)
-
-        # Second subtable has some glyph classes
-        prefix, input_, suffix, lookups = [["A"]], [["E"]], [], [None]
-        sb.rules.append(builder.ChainContextualRule(prefix, input_, suffix, lookups))
-        prefix, input_, suffix, lookups = [["A"]], [["C","D"]], [], [None]
-        sb.rules.append(builder.ChainContextualRule(prefix, input_, suffix, lookups))
-        prefix, input_, suffix, lookups = [["A", "B"]], [["E"]], [], [None]
-        sb.rules.append(builder.ChainContextualRule(prefix, input_, suffix, lookups))
-
-        sb.add_subtable_break(None)
-
-        # Third subtable has no pre/post context
-        prefix, input_, suffix, lookups = [], [["E"]], [], [None]
-        sb.rules.append(builder.ChainContextualRule(prefix, input_, suffix, lookups))
-        prefix, input_, suffix, lookups = [], [["C","D"]], [], [None]
-        sb.rules.append(builder.ChainContextualRule(prefix, input_, suffix, lookups))
-
-        rulesets = sb.rulesets()
-        assert len(rulesets) == 3
-        assert rulesets[0].hasPrefixOrSuffix
-        assert not rulesets[0].hasAnyGlyphClasses
-        cd = rulesets[0].format2ClassDefs()
-        assert set(cd[0].classes()[1:]) == set([("d",),("b",),("a",)])
-        assert set(cd[1].classes()[1:]) == set([("c",)])
-        assert set(cd[2].classes()[1:]) == set()
-
-        assert rulesets[1].hasPrefixOrSuffix
-        assert rulesets[1].hasAnyGlyphClasses
-        assert not rulesets[1].format2ClassDefs()
-
-        assert not rulesets[2].hasPrefixOrSuffix
-        assert rulesets[2].hasAnyGlyphClasses
-        assert rulesets[2].format2ClassDefs()
-        cd = rulesets[2].format2ClassDefs()
-        assert set(cd[0].classes()[1:]) == set()
-        assert set(cd[1].classes()[1:]) == set([("C","D"), ("E",)])
-        assert set(cd[2].classes()[1:]) == set()
-
 
 if __name__ == "__main__":
     import sys
diff --git a/Tests/otlLib/data/gpos_91.ttx b/Tests/otlLib/data/gpos_91.ttx
index 7befe7b..ee7bf7c 100644
--- a/Tests/otlLib/data/gpos_91.ttx
+++ b/Tests/otlLib/data/gpos_91.ttx
@@ -85,7 +85,7 @@
         <ExtensionPos index="0" Format="1">
           <ExtensionLookupType value="1"/>
           <SinglePos Format="1">
-            <Coverage>
+            <Coverage Format="1">
               <Glyph value="A"/>
             </Coverage>
             <ValueFormat value="4"/>
diff --git a/Tests/otlLib/data/gsub_51.ttx b/Tests/otlLib/data/gsub_51.ttx
index 0e6a413..280582c 100644
--- a/Tests/otlLib/data/gsub_51.ttx
+++ b/Tests/otlLib/data/gsub_51.ttx
@@ -88,7 +88,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
         </SingleSubst>
@@ -97,7 +97,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -105,9 +105,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -117,7 +117,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -126,7 +126,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- SubRuleSetCount=1 -->
diff --git a/Tests/otlLib/data/gsub_52.ttx b/Tests/otlLib/data/gsub_52.ttx
index 4e83b96..189178c 100644
--- a/Tests/otlLib/data/gsub_52.ttx
+++ b/Tests/otlLib/data/gsub_52.ttx
@@ -88,7 +88,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
         </SingleSubst>
@@ -97,7 +97,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -105,9 +105,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -117,7 +117,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -126,10 +126,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
           </ClassDef>
           <!-- SubClassSetCount=2 -->
diff --git a/Tests/otlLib/data/gsub_71.ttx b/Tests/otlLib/data/gsub_71.ttx
index acf6cdb..201de4c 100644
--- a/Tests/otlLib/data/gsub_71.ttx
+++ b/Tests/otlLib/data/gsub_71.ttx
@@ -87,7 +87,7 @@
         <!-- SubTableCount=1 -->
         <ExtensionSubst index="0" Format="1">
           <ExtensionLookupType value="1"/>
-          <SingleSubst>
+          <SingleSubst Format="1">
             <Substitution in="g18" out="g23"/>
             <Substitution in="g19" out="g24"/>
           </SingleSubst>
diff --git a/Tests/otlLib/maxContextCalc_test.py b/Tests/otlLib/maxContextCalc_test.py
index dc169c6..759b30d 100644
--- a/Tests/otlLib/maxContextCalc_test.py
+++ b/Tests/otlLib/maxContextCalc_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
 
 import os
 import pytest
diff --git a/Tests/otlLib/mock_builder_test.py b/Tests/otlLib/mock_builder_test.py
deleted file mode 100644
index b3fecd8..0000000
--- a/Tests/otlLib/mock_builder_test.py
+++ /dev/null
@@ -1,86 +0,0 @@
-from fontTools.otlLib.builder import (
-    AlternateSubstBuilder,
-    ChainContextPosBuilder,
-    ChainContextSubstBuilder,
-    LigatureSubstBuilder,
-    MultipleSubstBuilder,
-    CursivePosBuilder,
-    MarkBasePosBuilder,
-    MarkLigPosBuilder,
-    MarkMarkPosBuilder,
-    ReverseChainSingleSubstBuilder,
-    SingleSubstBuilder,
-    ClassPairPosSubtableBuilder,
-    PairPosBuilder,
-    SinglePosBuilder,
-    ChainContextualRule
-)
-from fontTools.otlLib.error import OpenTypeLibError
-from fontTools.ttLib import TTFont
-from fontTools.misc.loggingTools import CapturingLogHandler
-import logging
-import pytest
-
-
-@pytest.fixture
-def ttfont():
-    glyphs = """
-        .notdef space slash fraction semicolon period comma ampersand
-        quotedblleft quotedblright quoteleft quoteright
-        zero one two three four five six seven eight nine
-        zero.oldstyle one.oldstyle two.oldstyle three.oldstyle
-        four.oldstyle five.oldstyle six.oldstyle seven.oldstyle
-        eight.oldstyle nine.oldstyle onequarter onehalf threequarters
-        onesuperior twosuperior threesuperior ordfeminine ordmasculine
-        A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
-        a b c d e f g h i j k l m n o p q r s t u v w x y z
-        A.sc B.sc C.sc D.sc E.sc F.sc G.sc H.sc I.sc J.sc K.sc L.sc M.sc
-        N.sc O.sc P.sc Q.sc R.sc S.sc T.sc U.sc V.sc W.sc X.sc Y.sc Z.sc
-        A.alt1 A.alt2 A.alt3 B.alt1 B.alt2 B.alt3 C.alt1 C.alt2 C.alt3
-        a.alt1 a.alt2 a.alt3 a.end b.alt c.mid d.alt d.mid
-        e.begin e.mid e.end m.begin n.end s.end z.end
-        Eng Eng.alt1 Eng.alt2 Eng.alt3
-        A.swash B.swash C.swash D.swash E.swash F.swash G.swash H.swash
-        I.swash J.swash K.swash L.swash M.swash N.swash O.swash P.swash
-        Q.swash R.swash S.swash T.swash U.swash V.swash W.swash X.swash
-        Y.swash Z.swash
-        f_l c_h c_k c_s c_t f_f f_f_i f_f_l f_i o_f_f_i s_t f_i.begin
-        a_n_d T_h T_h.swash germandbls ydieresis yacute breve
-        grave acute dieresis macron circumflex cedilla umlaut ogonek caron
-        damma hamza sukun kasratan lam_meem_jeem noon.final noon.initial
-        by feature lookup sub table uni0327 uni0328 e.fina
-    """.split()
-    glyphs.extend("cid{:05d}".format(cid) for cid in range(800, 1001 + 1))
-    font = TTFont()
-    font.setGlyphOrder(glyphs)
-    return font
-
-
-class MockBuilderLocation(object):
-    def __init__(self, location):
-        self.location = location
-
-    def __str__(self):
-        return "%s:%s" % self.location
-
-
-def test_unsupported_subtable_break_1(ttfont):
-    location = MockBuilderLocation((0, "alpha"))
-
-    logger = logging.getLogger("fontTools.otlLib.builder")
-
-    with CapturingLogHandler(logger, "INFO") as captor:
-        builder = SinglePosBuilder(ttfont, location)
-        builder.add_subtable_break(MockBuilderLocation((5, "beta")))
-        builder.build()
-
-    captor.assertRegex('5:beta: unsupported "subtable" statement for lookup type')
-
-def test_chain_pos_references_GSUB_lookup(ttfont):
-    location = MockBuilderLocation((0, "alpha"))
-    builder = ChainContextPosBuilder(ttfont, location)
-    builder2 = SingleSubstBuilder(ttfont, location)
-    builder.rules.append(ChainContextualRule([], [], [], [[builder2]]))
-
-    with pytest.raises(OpenTypeLibError, match="0:alpha: Missing index of the specified lookup, might be a substitution lookup"):
-        builder.build()
diff --git a/Tests/pens/__init__.py b/Tests/pens/__init__.py
deleted file mode 100644
index 187b981..0000000
--- a/Tests/pens/__init__.py
+++ /dev/null
@@ -1,13 +0,0 @@
-import os
-from fontTools.ufoLib.glifLib import GlyphSet
-import pkg_resources
-
-DATADIR = os.path.join(os.path.dirname(__file__), 'data')
-CUBIC_GLYPHS = GlyphSet(os.path.join(DATADIR, 'cubic'))
-QUAD_GLYPHS = GlyphSet(os.path.join(DATADIR, 'quadratic'))
-
-import unittest
-# Python 3 renamed 'assertRaisesRegexp' to 'assertRaisesRegex', and fires
-# deprecation warnings if a program uses the old name.
-if not hasattr(unittest.TestCase, 'assertRaisesRegex'):
-    unittest.TestCase.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp
diff --git a/Tests/pens/areaPen_test.py b/Tests/pens/areaPen_test.py
index c3f3f80..ae915df 100644
--- a/Tests/pens/areaPen_test.py
+++ b/Tests/pens/areaPen_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.pens.areaPen import AreaPen
 import unittest
 
diff --git a/Tests/pens/basePen_test.py b/Tests/pens/basePen_test.py
index db57e80..2a7e43c 100644
--- a/Tests/pens/basePen_test.py
+++ b/Tests/pens/basePen_test.py
@@ -1,6 +1,7 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.pens.basePen import \
-    AbstractPen, BasePen, decomposeSuperBezierSegment, decomposeQuadraticSegment
-from fontTools.pens.pointPen import AbstractPointPen
+    BasePen, decomposeSuperBezierSegment, decomposeQuadraticSegment
 from fontTools.misc.loggingTools import CapturingLogHandler
 import unittest
 
diff --git a/Tests/pens/boundsPen_test.py b/Tests/pens/boundsPen_test.py
index c0c5610..533c575 100644
--- a/Tests/pens/boundsPen_test.py
+++ b/Tests/pens/boundsPen_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.pens.boundsPen import BoundsPen, ControlBoundsPen
 import unittest
 
diff --git a/Tests/pens/cocoaPen_test.py b/Tests/pens/cocoaPen_test.py
deleted file mode 100644
index 11077c0..0000000
--- a/Tests/pens/cocoaPen_test.py
+++ /dev/null
@@ -1,58 +0,0 @@
-import unittest
-
-try:
-    from fontTools.pens.cocoaPen import CocoaPen
-    from AppKit import NSBezierPathElementMoveTo, NSBezierPathElementLineTo
-    from AppKit import NSBezierPathElementCurveTo, NSBezierPathElementClosePath
-
-    PATH_ELEMENTS = {
-        # NSBezierPathElement key      desc
-        NSBezierPathElementMoveTo:    'moveto',
-        NSBezierPathElementLineTo:    'lineto',
-        NSBezierPathElementCurveTo:   'curveto',
-        NSBezierPathElementClosePath: 'close',
-    }
-
-    PYOBJC_AVAILABLE = True
-except ImportError:
-    PYOBJC_AVAILABLE = False
-
-
-def draw(pen):
-    pen.moveTo((50, 0))
-    pen.lineTo((50, 500))
-    pen.lineTo((200, 500))
-    pen.curveTo((350, 500), (450, 400), (450, 250))
-    pen.curveTo((450, 100), (350, 0), (200, 0))
-    pen.closePath()
-
-
-def cocoaPathToString(path):
-    num_elements = path.elementCount()
-    output = []
-    for i in range(num_elements - 1):
-        elem_type, elem_points = path.elementAtIndex_associatedPoints_(i)
-        elem_type = PATH_ELEMENTS[elem_type]
-        path_points = " ".join([f"{p.x} {p.y}" for p in elem_points])
-        output.append(f"{elem_type} {path_points}")
-    return " ".join(output)
-
-
-@unittest.skipUnless(PYOBJC_AVAILABLE, "pyobjc not installed")
-class CocoaPenTest(unittest.TestCase):
-    def test_draw(self):
-        pen = CocoaPen(None)
-        draw(pen)
-        self.assertEqual(
-            "moveto 50.0 0.0 lineto 50.0 500.0 lineto 200.0 500.0 curveto 350.0 500.0 450.0 400.0 450.0 250.0 curveto 450.0 100.0 350.0 0.0 200.0 0.0 close ",
-            cocoaPathToString(pen.path)
-        )
-
-    def test_empty(self):
-        pen = CocoaPen(None)
-        self.assertEqual("", cocoaPathToString(pen.path))
-
-
-if __name__ == '__main__':
-    import sys
-    sys.exit(unittest.main())
diff --git a/Tests/pens/cu2quPen_test.py b/Tests/pens/cu2quPen_test.py
deleted file mode 100644
index db51787..0000000
--- a/Tests/pens/cu2quPen_test.py
+++ /dev/null
@@ -1,390 +0,0 @@
-# Copyright 2016 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import unittest
-
-from fontTools.pens.cu2quPen import Cu2QuPen, Cu2QuPointPen
-from . import CUBIC_GLYPHS, QUAD_GLYPHS
-from .utils import DummyGlyph, DummyPointGlyph
-from .utils import DummyPen, DummyPointPen
-from fontTools.misc.loggingTools import CapturingLogHandler
-from textwrap import dedent
-import logging
-
-
-MAX_ERR = 1.0
-
-
-class _TestPenMixin(object):
-    """Collection of tests that are shared by both the SegmentPen and the
-    PointPen test cases, plus some helper methods.
-    """
-
-    maxDiff = None
-
-    def diff(self, expected, actual):
-        import difflib
-        expected = str(self.Glyph(expected)).splitlines(True)
-        actual = str(self.Glyph(actual)).splitlines(True)
-        diff = difflib.unified_diff(
-            expected, actual, fromfile='expected', tofile='actual')
-        return "".join(diff)
-
-    def convert_glyph(self, glyph, **kwargs):
-        # draw source glyph onto a new glyph using a Cu2Qu pen and return it
-        converted = self.Glyph()
-        pen = getattr(converted, self.pen_getter_name)()
-        quadpen = self.Cu2QuPen(pen, MAX_ERR, **kwargs)
-        getattr(glyph, self.draw_method_name)(quadpen)
-        return converted
-
-    def expect_glyph(self, source, expected):
-        converted = self.convert_glyph(source)
-        self.assertNotEqual(converted, source)
-        if not converted.approx(expected):
-            print(self.diff(expected, converted))
-            self.fail("converted glyph is different from expected")
-
-    def test_convert_simple_glyph(self):
-        self.expect_glyph(CUBIC_GLYPHS['a'], QUAD_GLYPHS['a'])
-        self.expect_glyph(CUBIC_GLYPHS['A'], QUAD_GLYPHS['A'])
-
-    def test_convert_composite_glyph(self):
-        source = CUBIC_GLYPHS['Aacute']
-        converted = self.convert_glyph(source)
-        # components don't change after quadratic conversion
-        self.assertEqual(converted, source)
-
-    def test_convert_mixed_glyph(self):
-        # this contains a mix of contours and components
-        self.expect_glyph(CUBIC_GLYPHS['Eacute'], QUAD_GLYPHS['Eacute'])
-
-    def test_reverse_direction(self):
-        for name in ('a', 'A', 'Eacute'):
-            source = CUBIC_GLYPHS[name]
-            normal_glyph = self.convert_glyph(source)
-            reversed_glyph = self.convert_glyph(source, reverse_direction=True)
-
-            # the number of commands is the same, just their order is iverted
-            self.assertTrue(
-                len(normal_glyph.outline), len(reversed_glyph.outline))
-            self.assertNotEqual(normal_glyph, reversed_glyph)
-
-    def test_stats(self):
-        stats = {}
-        for name in CUBIC_GLYPHS.keys():
-            source = CUBIC_GLYPHS[name]
-            self.convert_glyph(source, stats=stats)
-
-        self.assertTrue(stats)
-        self.assertTrue('1' in stats)
-        self.assertEqual(type(stats['1']), int)
-
-    def test_addComponent(self):
-        pen = self.Pen()
-        quadpen = self.Cu2QuPen(pen, MAX_ERR)
-        quadpen.addComponent("a", (1, 2, 3, 4, 5.0, 6.0))
-
-        # components are passed through without changes
-        self.assertEqual(str(pen).splitlines(), [
-            "pen.addComponent('a', (1, 2, 3, 4, 5.0, 6.0))",
-        ])
-
-
-class TestCu2QuPen(unittest.TestCase, _TestPenMixin):
-
-    def __init__(self, *args, **kwargs):
-        super(TestCu2QuPen, self).__init__(*args, **kwargs)
-        self.Glyph = DummyGlyph
-        self.Pen = DummyPen
-        self.Cu2QuPen = Cu2QuPen
-        self.pen_getter_name = 'getPen'
-        self.draw_method_name = 'draw'
-
-    def test__check_contour_is_open(self):
-        msg = "moveTo is required"
-        quadpen = Cu2QuPen(DummyPen(), MAX_ERR)
-
-        with self.assertRaisesRegex(AssertionError, msg):
-            quadpen.lineTo((0, 0))
-        with self.assertRaisesRegex(AssertionError, msg):
-            quadpen.qCurveTo((0, 0), (1, 1))
-        with self.assertRaisesRegex(AssertionError, msg):
-            quadpen.curveTo((0, 0), (1, 1), (2, 2))
-        with self.assertRaisesRegex(AssertionError, msg):
-            quadpen.closePath()
-        with self.assertRaisesRegex(AssertionError, msg):
-            quadpen.endPath()
-
-        quadpen.moveTo((0, 0))  # now it works
-        quadpen.lineTo((1, 1))
-        quadpen.qCurveTo((2, 2), (3, 3))
-        quadpen.curveTo((4, 4), (5, 5), (6, 6))
-        quadpen.closePath()
-
-    def test__check_contour_closed(self):
-        msg = "closePath or endPath is required"
-        quadpen = Cu2QuPen(DummyPen(), MAX_ERR)
-        quadpen.moveTo((0, 0))
-
-        with self.assertRaisesRegex(AssertionError, msg):
-            quadpen.moveTo((1, 1))
-        with self.assertRaisesRegex(AssertionError, msg):
-            quadpen.addComponent("a", (1, 0, 0, 1, 0, 0))
-
-        # it works if contour is closed
-        quadpen.closePath()
-        quadpen.moveTo((1, 1))
-        quadpen.endPath()
-        quadpen.addComponent("a", (1, 0, 0, 1, 0, 0))
-
-    def test_qCurveTo_no_points(self):
-        quadpen = Cu2QuPen(DummyPen(), MAX_ERR)
-        quadpen.moveTo((0, 0))
-
-        with self.assertRaisesRegex(
-                AssertionError, "illegal qcurve segment point count: 0"):
-            quadpen.qCurveTo()
-
-    def test_qCurveTo_1_point(self):
-        pen = DummyPen()
-        quadpen = Cu2QuPen(pen, MAX_ERR)
-        quadpen.moveTo((0, 0))
-        quadpen.qCurveTo((1, 1))
-
-        self.assertEqual(str(pen).splitlines(), [
-            "pen.moveTo((0, 0))",
-            "pen.lineTo((1, 1))",
-        ])
-
-    def test_qCurveTo_more_than_1_point(self):
-        pen = DummyPen()
-        quadpen = Cu2QuPen(pen, MAX_ERR)
-        quadpen.moveTo((0, 0))
-        quadpen.qCurveTo((1, 1), (2, 2))
-
-        self.assertEqual(str(pen).splitlines(), [
-            "pen.moveTo((0, 0))",
-            "pen.qCurveTo((1, 1), (2, 2))",
-        ])
-
-    def test_curveTo_no_points(self):
-        quadpen = Cu2QuPen(DummyPen(), MAX_ERR)
-        quadpen.moveTo((0, 0))
-
-        with self.assertRaisesRegex(
-                AssertionError, "illegal curve segment point count: 0"):
-            quadpen.curveTo()
-
-    def test_curveTo_1_point(self):
-        pen = DummyPen()
-        quadpen = Cu2QuPen(pen, MAX_ERR)
-        quadpen.moveTo((0, 0))
-        quadpen.curveTo((1, 1))
-
-        self.assertEqual(str(pen).splitlines(), [
-            "pen.moveTo((0, 0))",
-            "pen.lineTo((1, 1))",
-        ])
-
-    def test_curveTo_2_points(self):
-        pen = DummyPen()
-        quadpen = Cu2QuPen(pen, MAX_ERR)
-        quadpen.moveTo((0, 0))
-        quadpen.curveTo((1, 1), (2, 2))
-
-        self.assertEqual(str(pen).splitlines(), [
-            "pen.moveTo((0, 0))",
-            "pen.qCurveTo((1, 1), (2, 2))",
-        ])
-
-    def test_curveTo_3_points(self):
-        pen = DummyPen()
-        quadpen = Cu2QuPen(pen, MAX_ERR)
-        quadpen.moveTo((0, 0))
-        quadpen.curveTo((1, 1), (2, 2), (3, 3))
-
-        self.assertEqual(str(pen).splitlines(), [
-            "pen.moveTo((0, 0))",
-            "pen.qCurveTo((0.75, 0.75), (2.25, 2.25), (3, 3))",
-        ])
-
-    def test_curveTo_more_than_3_points(self):
-        # a 'SuperBezier' as described in fontTools.basePen.AbstractPen
-        pen = DummyPen()
-        quadpen = Cu2QuPen(pen, MAX_ERR)
-        quadpen.moveTo((0, 0))
-        quadpen.curveTo((1, 1), (2, 2), (3, 3), (4, 4))
-
-        self.assertEqual(str(pen).splitlines(), [
-            "pen.moveTo((0, 0))",
-            "pen.qCurveTo((0.75, 0.75), (1.625, 1.625), (2, 2))",
-            "pen.qCurveTo((2.375, 2.375), (3.25, 3.25), (4, 4))",
-        ])
-
-    def test_addComponent(self):
-        pen = DummyPen()
-        quadpen = Cu2QuPen(pen, MAX_ERR)
-        quadpen.addComponent("a", (1, 2, 3, 4, 5.0, 6.0))
-
-        # components are passed through without changes
-        self.assertEqual(str(pen).splitlines(), [
-            "pen.addComponent('a', (1, 2, 3, 4, 5.0, 6.0))",
-        ])
-
-    def test_ignore_single_points(self):
-        pen = DummyPen()
-        try:
-            logging.captureWarnings(True)
-            with CapturingLogHandler("py.warnings", level="WARNING") as log:
-                quadpen = Cu2QuPen(pen, MAX_ERR, ignore_single_points=True)
-        finally:
-            logging.captureWarnings(False)
-        quadpen.moveTo((0, 0))
-        quadpen.endPath()
-        quadpen.moveTo((1, 1))
-        quadpen.closePath()
-
-        self.assertGreaterEqual(len(log.records), 1)
-        self.assertIn("ignore_single_points is deprecated",
-                      log.records[0].args[0])
-
-        # single-point contours were ignored, so the pen commands are empty
-        self.assertFalse(pen.commands)
-
-        # redraw without ignoring single points
-        quadpen.ignore_single_points = False
-        quadpen.moveTo((0, 0))
-        quadpen.endPath()
-        quadpen.moveTo((1, 1))
-        quadpen.closePath()
-
-        self.assertTrue(pen.commands)
-        self.assertEqual(str(pen).splitlines(), [
-            "pen.moveTo((0, 0))",
-            "pen.endPath()",
-            "pen.moveTo((1, 1))",
-            "pen.closePath()"
-        ])
-
-
-class TestCu2QuPointPen(unittest.TestCase, _TestPenMixin):
-
-    def __init__(self, *args, **kwargs):
-        super(TestCu2QuPointPen, self).__init__(*args, **kwargs)
-        self.Glyph = DummyPointGlyph
-        self.Pen = DummyPointPen
-        self.Cu2QuPen = Cu2QuPointPen
-        self.pen_getter_name = 'getPointPen'
-        self.draw_method_name = 'drawPoints'
-
-    def test_super_bezier_curve(self):
-        pen = DummyPointPen()
-        quadpen = Cu2QuPointPen(pen, MAX_ERR)
-        quadpen.beginPath()
-        quadpen.addPoint((0, 0), segmentType="move")
-        quadpen.addPoint((1, 1))
-        quadpen.addPoint((2, 2))
-        quadpen.addPoint((3, 3))
-        quadpen.addPoint(
-            (4, 4), segmentType="curve", smooth=False, name="up", selected=1)
-        quadpen.endPath()
-
-        self.assertEqual(str(pen).splitlines(), """\
-pen.beginPath()
-pen.addPoint((0, 0), name=None, segmentType='move', smooth=False)
-pen.addPoint((0.75, 0.75), name=None, segmentType=None, smooth=False)
-pen.addPoint((1.625, 1.625), name=None, segmentType=None, smooth=False)
-pen.addPoint((2, 2), name=None, segmentType='qcurve', smooth=True)
-pen.addPoint((2.375, 2.375), name=None, segmentType=None, smooth=False)
-pen.addPoint((3.25, 3.25), name=None, segmentType=None, smooth=False)
-pen.addPoint((4, 4), name='up', segmentType='qcurve', selected=1, smooth=False)
-pen.endPath()""".splitlines())
-
-    def test__flushContour_restore_starting_point(self):
-        pen = DummyPointPen()
-        quadpen = Cu2QuPointPen(pen, MAX_ERR)
-
-        # collect the output of _flushContour before it's sent to _drawPoints
-        new_segments = []
-        def _drawPoints(segments):
-            new_segments.extend(segments)
-            Cu2QuPointPen._drawPoints(quadpen, segments)
-        quadpen._drawPoints = _drawPoints
-
-        # a closed path (ie. no "move" segmentType)
-        quadpen._flushContour([
-            ("curve", [
-                ((2, 2), False, None, {}),
-                ((1, 1), False, None, {}),
-                ((0, 0), False, None, {}),
-            ]),
-            ("curve", [
-                ((1, 1), False, None, {}),
-                ((2, 2), False, None, {}),
-                ((3, 3), False, None, {}),
-            ]),
-        ])
-
-        # the original starting point is restored: the last segment has become
-        # the first
-        self.assertEqual(new_segments[0][1][-1][0], (3, 3))
-        self.assertEqual(new_segments[-1][1][-1][0], (0, 0))
-
-        new_segments = []
-        # an open path (ie. starting with "move")
-        quadpen._flushContour([
-            ("move", [
-                ((0, 0), False, None, {}),
-            ]),
-            ("curve", [
-                ((1, 1), False, None, {}),
-                ((2, 2), False, None, {}),
-                ((3, 3), False, None, {}),
-            ]),
-        ])
-
-        # the segment order stays the same before and after _flushContour
-        self.assertEqual(new_segments[0][1][-1][0], (0, 0))
-        self.assertEqual(new_segments[-1][1][-1][0], (3, 3))
-
-    def test_quad_no_oncurve(self):
-        """When passed a contour which has no on-curve points, the
-        Cu2QuPointPen will treat it as a special quadratic contour whose
-        first point has 'None' coordinates.
-        """
-        self.maxDiff = None
-        pen = DummyPointPen()
-        quadpen = Cu2QuPointPen(pen, MAX_ERR)
-        quadpen.beginPath()
-        quadpen.addPoint((1, 1))
-        quadpen.addPoint((2, 2))
-        quadpen.addPoint((3, 3))
-        quadpen.endPath()
-
-        self.assertEqual(
-            str(pen),
-            dedent(
-                """\
-                pen.beginPath()
-                pen.addPoint((1, 1), name=None, segmentType=None, smooth=False)
-                pen.addPoint((2, 2), name=None, segmentType=None, smooth=False)
-                pen.addPoint((3, 3), name=None, segmentType=None, smooth=False)
-                pen.endPath()"""
-            )
-        )
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/Tests/pens/data/cubic/A_.glif b/Tests/pens/data/cubic/A_.glif
deleted file mode 100755
index bee6cd7..0000000
--- a/Tests/pens/data/cubic/A_.glif
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="A" format="1">
-	<unicode hex="0041"/>
-	<advance width="668"/>
-	<outline>
-		<contour>
-			<point x="501" y="347" type="line"/>
-			<point x="412" y="393"/>
-			<point x="359" y="401"/>
-			<point x="282" y="401" type="curve" smooth="yes"/>
-			<point x="192" y="401"/>
-			<point x="131" y="390"/>
-			<point x="114" y="347" type="curve"/>
-			<point x="119" y="347"/>
-			<point x="127" y="330"/>
-			<point x="127" y="316" type="curve" smooth="yes"/>
-			<point x="127" y="292"/>
-			<point x="102" y="277"/>
-			<point x="71" y="277" type="curve" smooth="yes"/>
-			<point x="37" y="277"/>
-			<point x="9" y="296"/>
-			<point x="9" y="335" type="curve" smooth="yes"/>
-			<point x="9" y="403"/>
-			<point x="95" y="458"/>
-			<point x="213" y="458" type="curve" smooth="yes"/>
-			<point x="278" y="458"/>
-			<point x="428" y="439"/>
-			<point x="526" y="385" type="curve"/>
-		</contour>
-		<contour>
-			<point x="629" y="678" type="line"/>
-			<point x="615" y="685"/>
-			<point x="596" y="692"/>
-			<point x="578" y="692" type="curve" smooth="yes"/>
-			<point x="421" y="692"/>
-			<point x="204" y="149"/>
-			<point x="204" y="-58" type="curve" smooth="yes"/>
-			<point x="204" y="-90"/>
-			<point x="212" y="-105"/>
-			<point x="218" y="-114" type="curve"/>
-			<point x="164" y="-114"/>
-			<point x="84" y="-112"/>
-			<point x="84" y="-8" type="curve" smooth="yes"/>
-			<point x="84" y="191"/>
-			<point x="374" y="750"/>
-			<point x="613" y="750" type="curve" smooth="yes"/>
-			<point x="636" y="750"/>
-			<point x="668" y="746"/>
-			<point x="692" y="736" type="curve"/>
-		</contour>
-		<contour>
-			<point x="391" y="0" type="line"/>
-			<point x="547" y="736" type="line"/>
-			<point x="692" y="736" type="line"/>
-			<point x="535" y="0" type="line"/>
-		</contour>
-	</outline>
-</glyph>
\ No newline at end of file
diff --git a/Tests/pens/data/cubic/A_acute.glif b/Tests/pens/data/cubic/A_acute.glif
deleted file mode 100755
index 72a8855..0000000
--- a/Tests/pens/data/cubic/A_acute.glif
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="Aacute" format="1">
-	<unicode hex="00C1"/>
-	<advance width="668"/>
-	<outline>
-		<component base="A"/>
-		<component base="acute" xOffset="366" yOffset="250"/>
-	</outline>
-</glyph>
\ No newline at end of file
diff --git a/Tests/pens/data/cubic/E_acute.glif b/Tests/pens/data/cubic/E_acute.glif
deleted file mode 100755
index fa57e34..0000000
--- a/Tests/pens/data/cubic/E_acute.glif
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="E" format="1">
-	<unicode hex="0045"/>
-	<advance width="459"/>
-	<outline>
-		<contour>
-			<point x="461" y="180" type="line"/>
-			<point x="425" y="114"/>
-			<point x="337" y="78"/>
-			<point x="276" y="78" type="curve" smooth="yes"/>
-			<point x="208" y="78"/>
-			<point x="181" y="123"/>
-			<point x="181" y="179" type="curve" smooth="yes"/>
-			<point x="181" y="271"/>
-			<point x="253" y="394"/>
-			<point x="360" y="418" type="curve"/>
-			<point x="288" y="437"/>
-			<point x="259" y="494"/>
-			<point x="259" y="552" type="curve" smooth="yes"/>
-			<point x="259" y="622"/>
-			<point x="302" y="693"/>
-			<point x="361" y="693" type="curve" smooth="yes"/>
-			<point x="388" y="693"/>
-			<point x="416" y="678"/>
-			<point x="416" y="637" type="curve" smooth="yes"/>
-			<point x="416" y="603"/>
-			<point x="397" y="558"/>
-			<point x="372" y="550" type="curve"/>
-			<point x="386" y="531"/>
-			<point x="402" y="523"/>
-			<point x="419" y="523" type="curve" smooth="yes"/>
-			<point x="459" y="523"/>
-			<point x="493" y="567"/>
-			<point x="493" y="627" type="curve" smooth="yes"/>
-			<point x="493" y="709"/>
-			<point x="429" y="752"/>
-			<point x="350" y="752" type="curve" smooth="yes"/>
-			<point x="222" y="752"/>
-			<point x="131" y="640"/>
-			<point x="131" y="537" type="curve" smooth="yes"/>
-			<point x="131" y="492"/>
-			<point x="149" y="448"/>
-			<point x="192" y="417" type="curve"/>
-			<point x="77" y="389"/>
-			<point x="7" y="263"/>
-			<point x="7" y="158" type="curve" smooth="yes"/>
-			<point x="7" y="64"/>
-			<point x="63" y="-18"/>
-			<point x="191" y="-18" type="curve" smooth="yes"/>
-			<point x="310" y="-18"/>
-			<point x="432" y="52"/>
-			<point x="484" y="170" type="curve"/>
-		</contour>
-		<component base="acute" xOffset="210" yOffset="250"/>
-	</outline>
-</glyph>
\ No newline at end of file
diff --git a/Tests/pens/data/cubic/a.glif b/Tests/pens/data/cubic/a.glif
deleted file mode 100644
index 1fc63b4..0000000
--- a/Tests/pens/data/cubic/a.glif
+++ /dev/null
@@ -1,80 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="a" format="1">
-	<unicode hex="0061"/>
-	<advance width="1118"/>
-	<outline>
-		<contour>
-			<point x="771" y="183" type="line"/>
-			<point x="771" y="123"/>
-			<point x="782" y="41"/>
-			<point x="802" y="0" type="curve"/>
-			<point x="1010" y="0" type="line"/>
-			<point x="1010" y="17" type="line"/>
-			<point x="984" y="76"/>
-			<point x="971" y="166"/>
-			<point x="971" y="238" type="curve" smooth="yes"/>
-			<point x="971" y="738" type="line"/>
-			<point x="971" y="981"/>
-			<point x="803" y="1102"/>
-			<point x="566" y="1102" type="curve" smooth="yes"/>
-			<point x="301" y="1102"/>
-			<point x="133" y="935"/>
-			<point x="133" y="782" type="curve"/>
-			<point x="333" y="782" type="line"/>
-			<point x="333" y="867"/>
-			<point x="421" y="945"/>
-			<point x="554" y="945" type="curve" smooth="yes"/>
-			<point x="697" y="945"/>
-			<point x="771" y="864"/>
-			<point x="771" y="740" type="curve"/>
-		</contour>
-		<contour>
-			<point x="804" y="661" type="line"/>
-			<point x="596" y="661" type="line"/>
-			<point x="301" y="661"/>
-			<point x="111" y="539"/>
-			<point x="111" y="303" type="curve" smooth="yes"/>
-			<point x="111" y="123"/>
-			<point x="257" y="-20"/>
-			<point x="480" y="-20" type="curve" smooth="yes"/>
-			<point x="711" y="-20"/>
-			<point x="857" y="170"/>
-			<point x="874" y="277" type="curve"/>
-			<point x="789" y="370" type="line"/>
-			<point x="789" y="279"/>
-			<point x="673" y="151"/>
-			<point x="510" y="151" type="curve" smooth="yes"/>
-			<point x="377" y="151"/>
-			<point x="311" y="230"/>
-			<point x="311" y="331" type="curve" smooth="yes"/>
-			<point x="311" y="462"/>
-			<point x="425" y="524"/>
-			<point x="629" y="524" type="curve"/>
-			<point x="806" y="524" type="line"/>
-		</contour>
-		<contour>
-			<point name="top" x="582" y="1290" type="move"/>
-		</contour>
-		<contour>
-			<point name="bottom" x="501" y="0" type="move"/>
-		</contour>
-		<contour>
-			<point name="ogonek" x="974" y="0" type="move"/>
-		</contour>
-		<contour>
-			<point name="rhalfring" x="700" y="1290" type="move"/>
-		</contour>
-		<contour>
-			<point name="top_dd" x="1118" y="1600" type="move"/>
-		</contour>
-		<contour>
-			<point name="bottom_dd" x="1118" y="-407" type="move"/>
-		</contour>
-		<contour>
-			<point name="rhotichook" x="879" y="654" type="move"/>
-		</contour>
-		<contour>
-			<point name="top0315" x="1118" y="1290" type="move"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/pens/data/cubic/acute.glif b/Tests/pens/data/cubic/acute.glif
deleted file mode 100755
index 2d39251..0000000
--- a/Tests/pens/data/cubic/acute.glif
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="acute" format="1">
-	<unicode hex="00B4"/>
-	<advance width="316"/>
-	<outline>
-		<contour>
-			<point x="120" y="561" type="line"/>
-			<point x="195" y="561" type="line"/>
-			<point x="316" y="750" type="line"/>
-			<point x="211" y="750" type="line"/>
-		</contour>
-	</outline>
-</glyph>
\ No newline at end of file
diff --git a/Tests/pens/data/cubic/contents.plist b/Tests/pens/data/cubic/contents.plist
deleted file mode 100644
index 3baa4e7..0000000
--- a/Tests/pens/data/cubic/contents.plist
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>A</key>
-	<string>A_.glif</string>
-	<key>Aacute</key>
-	<string>A_acute.glif</string>
-	<key>Eacute</key>
-	<string>E_acute.glif</string>
-	<key>a</key>
-	<string>a.glif</string>
-	<key>acute</key>
-	<string>acute.glif</string>
-</dict>
-</plist>
diff --git a/Tests/pens/data/quadratic/A_.glif b/Tests/pens/data/quadratic/A_.glif
deleted file mode 100644
index dbc10e9..0000000
--- a/Tests/pens/data/quadratic/A_.glif
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="A" format="1">
-	<unicode hex="0041"/>
-	<advance width="668"/>
-	<outline>
-		<contour>
-			<point x="501" y="347" type="line"/>
-			<point x="456.5" y="370"/>
-			<point x="386.5" y="393.16666666666663"/>
-			<point x="320.5" y="401"/>
-			<point x="282" y="401" type="qcurve" smooth="yes"/>
-			<point x="214.5" y="401"/>
-			<point x="126.75" y="379.25"/>
-			<point x="114" y="347" type="qcurve"/>
-			<point x="117.75" y="347"/>
-			<point x="127" y="326.5"/>
-			<point x="127" y="316" type="qcurve" smooth="yes"/>
-			<point x="127" y="298"/>
-			<point x="94.25" y="277"/>
-			<point x="71" y="277" type="qcurve" smooth="yes"/>
-			<point x="45.5" y="277"/>
-			<point x="9" y="305.75"/>
-			<point x="9" y="335" type="qcurve" smooth="yes"/>
-			<point x="9" y="369"/>
-			<point x="61.83333333333332" y="424.8333333333333"/>
-			<point x="154" y="458"/>
-			<point x="213" y="458" type="qcurve" smooth="yes"/>
-			<point x="237.375" y="458"/>
-			<point x="313.0052083333333" y="450.2916666666667"/>
-			<point x="401.2447916666667" y="433.2083333333333"/>
-			<point x="489.25" y="405.25"/>
-			<point x="526" y="385" type="qcurve"/>
-		</contour>
-		<contour>
-			<point x="629" y="678" type="line"/>
-			<point x="618.5" y="683.25"/>
-			<point x="591.5" y="692"/>
-			<point x="578" y="692" type="qcurve" smooth="yes"/>
-			<point x="544.3571428571429" y="692"/>
-			<point x="471.67614188532553" y="631.7033527696792"/>
-			<point x="398.9164237123421" y="527.9810495626824"/>
-			<point x="330.9234693877551" y="396.2091836734695"/>
-			<point x="272.54275996112733" y="251.76384839650154"/>
-			<point x="228.61977648202145" y="110.0211370262391"/>
-			<point x="204.00000000000006" y="-13.64285714285704"/>
-			<point x="204" y="-58" type="qcurve" smooth="yes"/>
-			<point x="204" y="-82"/>
-			<point x="213.5" y="-107.25"/>
-			<point x="218" y="-114" type="qcurve"/>
-			<point x="197.75" y="-114"/>
-			<point x="151.36458333333334" y="-109.60416666666667"/>
-			<point x="110.13541666666667" y="-90.39583333333333"/>
-			<point x="84" y="-47"/>
-			<point x="84" y="-8" type="qcurve" smooth="yes"/>
-			<point x="84" y="34.64285714285714"/>
-			<point x="117.10762876579204" y="157.5352283770651"/>
-			<point x="176.7779397473275" y="300.3955296404276"/>
-			<point x="257.04591836734687" y="447.1479591836734"/>
-			<point x="351.94655004859084" y="581.7167152575314"/>
-			<point x="455.5148202137998" y="688.0259961127308"/>
-			<point x="561.7857142857142" y="750"/>
-			<point x="613" y="750" type="qcurve" smooth="yes"/>
-			<point x="630.25" y="750"/>
-			<point x="674" y="743.5"/>
-			<point x="692" y="736" type="qcurve"/>
-		</contour>
-		<contour>
-			<point x="391" y="0" type="line"/>
-			<point x="547" y="736" type="line"/>
-			<point x="692" y="736" type="line"/>
-			<point x="535" y="0" type="line"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/pens/data/quadratic/E_acute.glif b/Tests/pens/data/quadratic/E_acute.glif
deleted file mode 100644
index 89b4a5a..0000000
--- a/Tests/pens/data/quadratic/E_acute.glif
+++ /dev/null
@@ -1,64 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="E" format="1">
-	<unicode hex="0045"/>
-	<advance width="459"/>
-	<outline>
-		<contour>
-			<point x="461" y="180" type="line"/>
-			<point x="443" y="147"/>
-			<point x="378.91666666666663" y="101.49999999999999"/>
-			<point x="306.5" y="78"/>
-			<point x="276" y="78" type="qcurve" smooth="yes"/>
-			<point x="225" y="78"/>
-			<point x="181" y="137"/>
-			<point x="181" y="179" type="qcurve" smooth="yes"/>
-			<point x="181" y="213.5"/>
-			<point x="206.65104166666666" y="289.3854166666667"/>
-			<point x="254.09895833333334" y="358.6145833333333"/>
-			<point x="319.875" y="409"/>
-			<point x="360" y="418" type="qcurve"/>
-			<point x="306" y="432.25"/>
-			<point x="259" y="508.5"/>
-			<point x="259" y="552" type="qcurve" smooth="yes"/>
-			<point x="259" y="587"/>
-			<point x="285.41666666666663" y="651.6666666666667"/>
-			<point x="331.5" y="693"/>
-			<point x="361" y="693" type="qcurve" smooth="yes"/>
-			<point x="381.25" y="693"/>
-			<point x="416" y="667.75"/>
-			<point x="416" y="637" type="qcurve" smooth="yes"/>
-			<point x="416" y="611.5"/>
-			<point x="390.75" y="556"/>
-			<point x="372" y="550" type="qcurve"/>
-			<point x="391.89473684210526" y="523"/>
-			<point x="419" y="523" type="qcurve" smooth="yes"/>
-			<point x="449" y="523"/>
-			<point x="493" y="582"/>
-			<point x="493" y="627" type="qcurve" smooth="yes"/>
-			<point x="493" y="688.5"/>
-			<point x="409.25" y="752"/>
-			<point x="350" y="752" type="qcurve" smooth="yes"/>
-			<point x="302" y="752"/>
-			<point x="221.84375" y="714.4114583333334"/>
-			<point x="163.15625" y="651.8385416666666"/>
-			<point x="131" y="575.625"/>
-			<point x="131" y="537" type="qcurve" smooth="yes"/>
-			<point x="131" y="503.25"/>
-			<point x="159.75" y="440.25"/>
-			<point x="192" y="417" type="qcurve"/>
-			<point x="134.5" y="403"/>
-			<point x="51.58333333333333" y="319.58333333333326"/>
-			<point x="7" y="210.5"/>
-			<point x="7" y="158" type="qcurve" smooth="yes"/>
-			<point x="7" y="111"/>
-			<point x="45.66666666666667" y="30.83333333333333"/>
-			<point x="127.00000000000001" y="-18"/>
-			<point x="191" y="-18" type="qcurve" smooth="yes"/>
-			<point x="250.5" y="-18"/>
-			<point x="365.4166666666667" y="26.833333333333336"/>
-			<point x="458" y="110.99999999999999"/>
-			<point x="484" y="170" type="qcurve"/>
-		</contour>
-		<component base="acute" xOffset="210" yOffset="250"/>
-	</outline>
-</glyph>
diff --git a/Tests/pens/data/quadratic/a.glif b/Tests/pens/data/quadratic/a.glif
deleted file mode 100644
index dc776e1..0000000
--- a/Tests/pens/data/quadratic/a.glif
+++ /dev/null
@@ -1,93 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="a" format="1">
-	<unicode hex="0061"/>
-	<advance width="1118"/>
-	<outline>
-		<contour>
-			<point x="771" y="183" type="line"/>
-			<point x="771" y="153"/>
-			<point x="778.1666666666665" y="83.58333333333333"/>
-			<point x="792" y="20.5"/>
-			<point x="802" y="0" type="qcurve"/>
-			<point x="1010" y="0" type="line"/>
-			<point x="1010" y="17" type="line"/>
-			<point x="990.5" y="61.25"/>
-			<point x="971" y="184"/>
-			<point x="971" y="238" type="qcurve" smooth="yes"/>
-			<point x="971" y="738" type="line"/>
-			<point x="971" y="859.5"/>
-			<point x="867.25" y="1021.25"/>
-			<point x="684.5" y="1102"/>
-			<point x="566" y="1102" type="qcurve" smooth="yes"/>
-			<point x="466.625" y="1102"/>
-			<point x="306.8385416666667" y="1045.9739583333333"/>
-			<point x="193.41145833333334" y="952.7760416666666"/>
-			<point x="133" y="839.375"/>
-			<point x="133" y="782" type="qcurve"/>
-			<point x="333" y="782" type="line"/>
-			<point x="333" y="824.5"/>
-			<point x="388.0833333333333" y="898.9166666666665"/>
-			<point x="487.5" y="945"/>
-			<point x="554" y="945" type="qcurve" smooth="yes"/>
-			<point x="661.25" y="945"/>
-			<point x="771" y="833"/>
-			<point x="771" y="740" type="qcurve"/>
-		</contour>
-		<contour>
-			<point x="804" y="661" type="line"/>
-			<point x="596" y="661" type="line"/>
-			<point x="448.5" y="661"/>
-			<point x="230.58333333333331" y="580.3333333333334"/>
-			<point x="111" y="421"/>
-			<point x="111" y="303" type="qcurve" smooth="yes"/>
-			<point x="111" y="213"/>
-			<point x="202.58333333333334" y="66.5"/>
-			<point x="368.5" y="-20"/>
-			<point x="480" y="-20" type="qcurve" smooth="yes"/>
-			<point x="549.3000000000001" y="-20"/>
-			<point x="666.664" y="20.413000000000004"/>
-			<point x="760.4599999999999" y="86.77000000000001"/>
-			<point x="828.576" y="165.967"/>
-			<point x="868.8999999999999" y="244.90000000000003"/>
-			<point x="874" y="277" type="qcurve"/>
-			<point x="789" y="370" type="line"/>
-			<point x="789" y="335.875"/>
-			<point x="748.015625" y="259.765625"/>
-			<point x="673.234375" y="192.984375"/>
-			<point x="571.125" y="151"/>
-			<point x="510" y="151" type="qcurve" smooth="yes"/>
-			<point x="443.5" y="151"/>
-			<point x="355.08333333333326" y="198.916666666666666"/>
-			<point x="311" y="280.5"/>
-			<point x="311" y="331" type="qcurve" smooth="yes"/>
-			<point x="311" y="429.25"/>
-			<point x="476" y="524"/>
-			<point x="629" y="524" type="qcurve"/>
-			<point x="806" y="524" type="line"/>
-		</contour>
-		<contour>
-			<point name="top" x="582" y="1290" type="move"/>
-		</contour>
-		<contour>
-			<point name="bottom" x="501" y="0" type="move"/>
-		</contour>
-		<contour>
-			<point name="ogonek" x="974" y="0" type="move"/>
-		</contour>
-		<contour>
-			<point name="rhalfring" x="700" y="1290" type="move"/>
-		</contour>
-		<contour>
-			<point name="top_dd" x="1118" y="1600" type="move"/>
-		</contour>
-		<contour>
-			<point name="bottom_dd" x="1118" y="-407" type="move"/>
-		</contour>
-		<contour>
-			<point name="rhotichook" x="879" y="654" type="move"/>
-		</contour>
-		<contour>
-			<point name="top0315" x="1118" y="1290" type="move"/>
-		</contour>
-	</outline>
-</glyph>
diff --git a/Tests/pens/data/quadratic/acute.glif b/Tests/pens/data/quadratic/acute.glif
deleted file mode 100755
index 2d39251..0000000
--- a/Tests/pens/data/quadratic/acute.glif
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<glyph name="acute" format="1">
-	<unicode hex="00B4"/>
-	<advance width="316"/>
-	<outline>
-		<contour>
-			<point x="120" y="561" type="line"/>
-			<point x="195" y="561" type="line"/>
-			<point x="316" y="750" type="line"/>
-			<point x="211" y="750" type="line"/>
-		</contour>
-	</outline>
-</glyph>
\ No newline at end of file
diff --git a/Tests/pens/data/quadratic/contents.plist b/Tests/pens/data/quadratic/contents.plist
deleted file mode 100644
index 5ed74ed..0000000
--- a/Tests/pens/data/quadratic/contents.plist
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>A</key>
-	<string>A_.glif</string>
-	<key>Eacute</key>
-	<string>E_acute.glif</string>
-	<key>a</key>
-	<string>a.glif</string>
-	<key>acute</key>
-	<string>acute.glif</string>
-</dict>
-</plist>
diff --git a/Tests/pens/hashPointPen_test.py b/Tests/pens/hashPointPen_test.py
deleted file mode 100644
index 6b744e6..0000000
--- a/Tests/pens/hashPointPen_test.py
+++ /dev/null
@@ -1,138 +0,0 @@
-from fontTools.misc.transform import Identity
-from fontTools.pens.hashPointPen import HashPointPen
-import pytest
-
-
-class _TestGlyph(object):
-    width = 500
-
-    def drawPoints(self, pen):
-        pen.beginPath(identifier="abc")
-        pen.addPoint((0.0, 0.0), "line", False, "start", identifier="0000")
-        pen.addPoint((10, 110), "line", False, None, identifier="0001")
-        pen.addPoint((50.0, 75.0), None, False, None, identifier="0002")
-        pen.addPoint((60.0, 50.0), None, False, None, identifier="0003")
-        pen.addPoint((50.0, 0.0), "curve", True, "last", identifier="0004")
-        pen.endPath()
-
-
-class _TestGlyph2(_TestGlyph):
-    def drawPoints(self, pen):
-        pen.beginPath(identifier="abc")
-        pen.addPoint((0.0, 0.0), "line", False, "start", identifier="0000")
-        # Minor difference to _TestGlyph() is in the next line:
-        pen.addPoint((101, 10), "line", False, None, identifier="0001")
-        pen.addPoint((50.0, 75.0), None, False, None, identifier="0002")
-        pen.addPoint((60.0, 50.0), None, False, None, identifier="0003")
-        pen.addPoint((50.0, 0.0), "curve", True, "last", identifier="0004")
-        pen.endPath()
-
-
-class _TestGlyph3(_TestGlyph):
-    def drawPoints(self, pen):
-        pen.beginPath(identifier="abc")
-        pen.addPoint((0.0, 0.0), "line", False, "start", identifier="0000")
-        pen.addPoint((10, 110), "line", False, None, identifier="0001")
-        pen.endPath()
-        # Same segment, but in a different path:
-        pen.beginPath(identifier="pth2")
-        pen.addPoint((50.0, 75.0), None, False, None, identifier="0002")
-        pen.addPoint((60.0, 50.0), None, False, None, identifier="0003")
-        pen.addPoint((50.0, 0.0), "curve", True, "last", identifier="0004")
-        pen.endPath()
-
-
-class _TestGlyph4(_TestGlyph):
-    def drawPoints(self, pen):
-        pen.beginPath(identifier="abc")
-        pen.addPoint((0.0, 0.0), "move", False, "start", identifier="0000")
-        pen.addPoint((10, 110), "line", False, None, identifier="0001")
-        pen.addPoint((50.0, 75.0), None, False, None, identifier="0002")
-        pen.addPoint((60.0, 50.0), None, False, None, identifier="0003")
-        pen.addPoint((50.0, 0.0), "curve", True, "last", identifier="0004")
-        pen.endPath()
-
-
-class _TestGlyph5(_TestGlyph):
-    def drawPoints(self, pen):
-        pen.addComponent("b", Identity)
-
-
-class HashPointPenTest(object):
-    def test_addComponent(self):
-        pen = HashPointPen(_TestGlyph().width, {"a": _TestGlyph()})
-        pen.addComponent("a", (2, 0, 0, 3, -10, 5))
-        assert pen.hash == "w500[l0+0l10+110o50+75o60+50c50+0|(+2+0+0+3-10+5)]"
-
-    def test_NestedComponents(self):
-        pen = HashPointPen(
-            _TestGlyph().width, {"a": _TestGlyph5(), "b": _TestGlyph()}
-        )  # "a" contains "b" as a component
-        pen.addComponent("a", (2, 0, 0, 3, -10, 5))
-
-        assert (
-            pen.hash
-            == "w500[[l0+0l10+110o50+75o60+50c50+0|(+1+0+0+1+0+0)](+2+0+0+3-10+5)]"
-        )
-
-    def test_outlineAndComponent(self):
-        pen = HashPointPen(_TestGlyph().width, {"a": _TestGlyph()})
-        glyph = _TestGlyph()
-        glyph.drawPoints(pen)
-        pen.addComponent("a", (2, 0, 0, 2, -10, 5))
-
-        assert (
-            pen.hash
-            == "w500l0+0l10+110o50+75o60+50c50+0|[l0+0l10+110o50+75o60+50c50+0|(+2+0+0+2-10+5)]"
-        )
-
-    def test_addComponent_missing_raises(self):
-        pen = HashPointPen(_TestGlyph().width, dict())
-        with pytest.raises(KeyError) as excinfo:
-            pen.addComponent("a", Identity)
-        assert excinfo.value.args[0] == "a"
-
-    def test_similarGlyphs(self):
-        pen = HashPointPen(_TestGlyph().width)
-        glyph = _TestGlyph()
-        glyph.drawPoints(pen)
-
-        pen2 = HashPointPen(_TestGlyph2().width)
-        glyph = _TestGlyph2()
-        glyph.drawPoints(pen2)
-
-        assert pen.hash != pen2.hash
-
-    def test_similarGlyphs2(self):
-        pen = HashPointPen(_TestGlyph().width)
-        glyph = _TestGlyph()
-        glyph.drawPoints(pen)
-
-        pen2 = HashPointPen(_TestGlyph3().width)
-        glyph = _TestGlyph3()
-        glyph.drawPoints(pen2)
-
-        assert pen.hash != pen2.hash
-
-    def test_similarGlyphs3(self):
-        pen = HashPointPen(_TestGlyph().width)
-        glyph = _TestGlyph()
-        glyph.drawPoints(pen)
-
-        pen2 = HashPointPen(_TestGlyph4().width)
-        glyph = _TestGlyph4()
-        glyph.drawPoints(pen2)
-
-        assert pen.hash != pen2.hash
-
-    def test_glyphVsComposite(self):
-        # If a glyph contains a component, the decomposed glyph should still
-        # compare false
-        pen = HashPointPen(_TestGlyph().width, {"a": _TestGlyph()})
-        pen.addComponent("a", Identity)
-
-        pen2 = HashPointPen(_TestGlyph().width)
-        glyph = _TestGlyph()
-        glyph.drawPoints(pen2)
-
-        assert pen.hash != pen2.hash
diff --git a/Tests/pens/perimeterPen_test.py b/Tests/pens/perimeterPen_test.py
index 1b64534..aa73c3d 100644
--- a/Tests/pens/perimeterPen_test.py
+++ b/Tests/pens/perimeterPen_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.pens.perimeterPen import PerimeterPen
 import unittest
 
diff --git a/Tests/pens/pointInsidePen_test.py b/Tests/pens/pointInsidePen_test.py
index b561c43..3696ece 100644
--- a/Tests/pens/pointInsidePen_test.py
+++ b/Tests/pens/pointInsidePen_test.py
@@ -1,4 +1,5 @@
-from io import StringIO
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.pens.pointInsidePen import PointInsidePen
 import unittest
 
@@ -72,16 +73,16 @@
 
     @staticmethod
     def render(draw_function, even_odd):
-        result = StringIO()
+        result = BytesIO()
         for y in range(5):
             for x in range(10):
                 pen = PointInsidePen(None, (x + 0.5, y + 0.5), even_odd)
                 draw_function(pen)
                 if pen.getResult():
-                    result.write("*")
+                    result.write(b"*")
                 else:
-                    result.write(" ")
-        return result.getvalue()
+                    result.write(b" ")
+        return tounicode(result.getvalue())
 
 
     def test_contour_no_solutions(self):
diff --git a/Tests/pens/pointPen_test.py b/Tests/pens/pointPen_test.py
index a920178..9c71c5e 100644
--- a/Tests/pens/pointPen_test.py
+++ b/Tests/pens/pointPen_test.py
@@ -1,3 +1,6 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools.misc.loggingTools import CapturingLogHandler
 import unittest
 
 from fontTools.pens.basePen import AbstractPen
@@ -41,7 +44,7 @@
     items = []
     for key in sorted(kwargs):
         value = kwargs[key]
-        if isinstance(value, str):
+        if isinstance(value, basestring):
             items.append("%s='%s'" % (key, value))
         else:
             items.append("%s=%s" % (key, value))
@@ -154,67 +157,6 @@
                          "addPoint((20, 20)) addPoint((20, 40), segmentType='curve') endPath()",
                          repr(tpen))
 
-    def test_closed_outputImpliedClosingLine(self):
-        tpen = _TestSegmentPen()
-        ppen = PointToSegmentPen(tpen, outputImpliedClosingLine=True)
-        ppen.beginPath()
-        ppen.addPoint((10, 10), "line")
-        ppen.addPoint((10, 20), "line")
-        ppen.addPoint((20, 20), "line")
-        ppen.endPath()
-        self.assertEqual(
-            "10 10 moveto "
-            "10 20 lineto "
-            "20 20 lineto "
-            "10 10 lineto "  # explicit closing line
-            "closepath",
-            repr(tpen)
-        )
-
-    def test_closed_line_overlapping_start_end_points(self):
-        # Test case from https://github.com/googlefonts/fontmake/issues/572.
-        tpen = _TestSegmentPen()
-        ppen = PointToSegmentPen(tpen, outputImpliedClosingLine=False)
-        # The last oncurve point on this closed contour is a "line" segment and has
-        # same coordinates as the starting point.
-        ppen.beginPath()
-        ppen.addPoint((0, 651), segmentType="line")
-        ppen.addPoint((0, 101), segmentType="line")
-        ppen.addPoint((0, 101), segmentType="line")
-        ppen.addPoint((0, 651), segmentType="line")
-        ppen.endPath()
-        # Check that we always output an explicit 'lineTo' segment at the end,
-        # regardless of the value of 'outputImpliedClosingLine', to disambiguate
-        # the duplicate point from the implied closing line.
-        self.assertEqual(
-            "0 651 moveto "
-            "0 101 lineto "
-            "0 101 lineto "
-            "0 651 lineto "
-            "0 651 lineto "
-            "closepath",
-            repr(tpen)
-        )
-
-    def test_roundTrip2(self):
-        tpen = _TestPointPen()
-        ppen = PointToSegmentPen(SegmentToPointPen(tpen))
-        ppen.beginPath()
-        ppen.addPoint((0, 651), segmentType="line")
-        ppen.addPoint((0, 101), segmentType="line")
-        ppen.addPoint((0, 101), segmentType="line")
-        ppen.addPoint((0, 651), segmentType="line")
-        ppen.endPath()
-        self.assertEqual(
-            "beginPath() "
-            "addPoint((0, 651), segmentType='line') "
-            "addPoint((0, 101), segmentType='line') "
-            "addPoint((0, 101), segmentType='line') "
-            "addPoint((0, 651), segmentType='line') "
-            "endPath()",
-            repr(tpen)
-        )
-
 
 class TestSegmentToPointPen(unittest.TestCase):
 
@@ -256,10 +198,10 @@
         pen.closePath()
         self.assertEqual("beginPath() addPoint((10, 10), segmentType='line') "
                          "addPoint((10, 20)) addPoint((20, 20)) "
-                         "addPoint((20, 10), segmentType='qcurve') endPath()",
+                         "addPoint((20, 10), segmentType=qcurve) endPath()",
                          repr(tpen))
 
-    def test_quad2(self):
+    def test_quad(self):
         tpen = _TestPointPen()
         pen = SegmentToPointPen(tpen)
         pen.qCurveTo((10, 20), (20, 20), (20, 10), (10, 10), None)
@@ -468,23 +410,3 @@
                          "endPath() "
                          "addComponent('base', [1, 0, 0, 1, 0, 0], identifier='foo')",
                          repr(tpen))
-
-    def test_closed_line_overlapping_start_end_points(self):
-        # Test case from https://github.com/googlefonts/fontmake/issues/572
-        tpen = _TestPointPen()
-        pen = ReverseContourPointPen(tpen)
-        pen.beginPath()
-        pen.addPoint((0, 651), segmentType="line")
-        pen.addPoint((0, 101), segmentType="line")
-        pen.addPoint((0, 101), segmentType="line")
-        pen.addPoint((0, 651), segmentType="line")
-        pen.endPath()
-        self.assertEqual(
-            "beginPath() "
-            "addPoint((0, 651), segmentType='line') "
-            "addPoint((0, 651), segmentType='line') "
-            "addPoint((0, 101), segmentType='line') "
-            "addPoint((0, 101), segmentType='line') "
-            "endPath()",
-            repr(tpen)
-        )
diff --git a/Tests/pens/quartzPen_test.py b/Tests/pens/quartzPen_test.py
deleted file mode 100644
index 3a81d97..0000000
--- a/Tests/pens/quartzPen_test.py
+++ /dev/null
@@ -1,78 +0,0 @@
-import unittest
-
-try:
-    from fontTools.pens.quartzPen import QuartzPen
-
-    from Quartz.CoreGraphics import CGPathApply
-    from Quartz.CoreGraphics import kCGPathElementMoveToPoint
-    from Quartz.CoreGraphics import kCGPathElementAddLineToPoint
-    from Quartz.CoreGraphics import kCGPathElementAddQuadCurveToPoint
-    from Quartz.CoreGraphics import kCGPathElementAddCurveToPoint
-    from Quartz.CoreGraphics import kCGPathElementCloseSubpath
-
-    PATH_ELEMENTS = {
-        # CG constant key                    desc       num_points
-        kCGPathElementMoveToPoint:         ('moveto',   1),
-        kCGPathElementAddLineToPoint:      ('lineto',   1),
-        kCGPathElementAddCurveToPoint:     ('curveto',  3),
-        kCGPathElementAddQuadCurveToPoint: ('qcurveto', 2),
-        kCGPathElementCloseSubpath:        ('close',    0),
-    }
-
-    PYOBJC_AVAILABLE = True
-except ImportError:
-    PYOBJC_AVAILABLE = False
-
-
-def draw(pen):
-    pen.moveTo((50, 0))
-    pen.lineTo((50, 500))
-    pen.lineTo((200, 500))
-    pen.curveTo((350, 500), (450, 400), (450, 250))
-    pen.curveTo((450, 100), (350, 0), (200, 0))
-    pen.closePath()
-
-
-def quartzPathApplier(elements, element):
-    num_points = 0
-    elem_type = None
-    if element.type in PATH_ELEMENTS:
-        num_points = PATH_ELEMENTS[element.type][1]
-        elem_type = PATH_ELEMENTS[element.type][0]
-    elements.append((elem_type, element.points.as_tuple(num_points)))
-
-
-def quartzPathElements(path):
-    elements = []
-    CGPathApply(path, elements, quartzPathApplier)
-    return elements
-
-
-def quartzPathToString(path):
-    elements = quartzPathElements(path)
-    output = []
-    for element in elements:
-        elem_type, elem_points = element
-        path_points = " ".join([f"{p.x} {p.y}" for p in elem_points])
-        output.append(f"{elem_type} {path_points}")
-    return " ".join(output)
-
-
-@unittest.skipUnless(PYOBJC_AVAILABLE, "pyobjc not installed")
-class QuartzPenTest(unittest.TestCase):
-    def test_draw(self):
-        pen = QuartzPen(None)
-        draw(pen)
-        self.assertEqual(
-            "moveto 50.0 0.0 lineto 50.0 500.0 lineto 200.0 500.0 curveto 350.0 500.0 450.0 400.0 450.0 250.0 curveto 450.0 100.0 350.0 0.0 200.0 0.0 close ",
-            quartzPathToString(pen.path)
-        )
-
-    def test_empty(self):
-        pen = QuartzPen(None)
-        self.assertEqual("", quartzPathToString(pen.path))
-
-
-if __name__ == '__main__':
-    import sys
-    sys.exit(unittest.main())
diff --git a/Tests/pens/recordingPen_test.py b/Tests/pens/recordingPen_test.py
index 6977b93..fdc5d06 100644
--- a/Tests/pens/recordingPen_test.py
+++ b/Tests/pens/recordingPen_test.py
@@ -1,29 +1,20 @@
-from fontTools.pens.recordingPen import (
-    RecordingPen,
-    DecomposingRecordingPen,
-    RecordingPointPen,
-)
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools.pens.recordingPen import RecordingPen, DecomposingRecordingPen
 import pytest
 
 
 class _TestGlyph(object):
+
     def draw(self, pen):
         pen.moveTo((0.0, 0.0))
         pen.lineTo((0.0, 100.0))
         pen.curveTo((50.0, 75.0), (60.0, 50.0), (50.0, 0.0))
         pen.closePath()
 
-    def drawPoints(self, pen):
-        pen.beginPath(identifier="abc")
-        pen.addPoint((0.0, 0.0), "line", False, "start", identifier="0000")
-        pen.addPoint((0.0, 100.0), "line", False, None, identifier="0001")
-        pen.addPoint((50.0, 75.0), None, False, None, identifier="0002")
-        pen.addPoint((60.0, 50.0), None, False, None, identifier="0003")
-        pen.addPoint((50.0, 0.0), "curve", True, "last", identifier="0004")
-        pen.endPath()
-
 
 class RecordingPenTest(object):
+
     def test_addComponent(self):
         pen = RecordingPen()
         pen.addComponent("a", (2, 0, 0, 3, -10, 5))
@@ -31,42 +22,18 @@
 
 
 class DecomposingRecordingPenTest(object):
+
     def test_addComponent_decomposed(self):
         pen = DecomposingRecordingPen({"a": _TestGlyph()})
         pen.addComponent("a", (2, 0, 0, 3, -10, 5))
         assert pen.value == [
-            ("moveTo", ((-10.0, 5.0),)),
-            ("lineTo", ((-10.0, 305.0),)),
-            ("curveTo", ((90.0, 230.0), (110.0, 155.0), (90.0, 5.0))),
-            ("closePath", ()),
-        ]
+            ('moveTo', ((-10.0, 5.0),)),
+            ('lineTo', ((-10.0, 305.0),)),
+            ('curveTo', ((90.0, 230.0), (110.0, 155.0), (90.0, 5.0),)),
+            ('closePath', ())]
 
     def test_addComponent_missing_raises(self):
         pen = DecomposingRecordingPen(dict())
         with pytest.raises(KeyError) as excinfo:
             pen.addComponent("a", (1, 0, 0, 1, 0, 0))
         assert excinfo.value.args[0] == "a"
-
-
-class RecordingPointPenTest:
-    def test_record_and_replay(self):
-        pen = RecordingPointPen()
-        glyph = _TestGlyph()
-        glyph.drawPoints(pen)
-        pen.addComponent("a", (2, 0, 0, 2, -10, 5))
-
-        assert pen.value == [
-            ("beginPath", (), {"identifier": "abc"}),
-            ("addPoint", ((0.0, 0.0), "line", False, "start"), {"identifier": "0000"}),
-            ("addPoint", ((0.0, 100.0), "line", False, None), {"identifier": "0001"}),
-            ("addPoint", ((50.0, 75.0), None, False, None), {"identifier": "0002"}),
-            ("addPoint", ((60.0, 50.0), None, False, None), {"identifier": "0003"}),
-            ("addPoint", ((50.0, 0.0), "curve", True, "last"), {"identifier": "0004"}),
-            ("endPath", (), {}),
-            ("addComponent", ("a", (2, 0, 0, 2, -10, 5)), {}),
-        ]
-
-        pen2 = RecordingPointPen()
-        pen.replay(pen2)
-
-        assert pen2.value == pen.value
diff --git a/Tests/pens/reverseContourPen_test.py b/Tests/pens/reverseContourPen_test.py
index 9c71540..6dbc5e0 100644
--- a/Tests/pens/reverseContourPen_test.py
+++ b/Tests/pens/reverseContourPen_test.py
@@ -278,26 +278,6 @@
             ('lineTo', ((848, 348),)),  # the duplicate point is kept
             ('closePath', ())
         ]
-    ),
-    # Test case from https://github.com/googlefonts/fontmake/issues/572
-    # An additional closing lineTo is required to disambiguate a duplicate
-    # point at the end of a contour from the implied closing line.
-    (
-        [
-            ('moveTo', ((0, 651),)),
-            ('lineTo', ((0, 101),)),
-            ('lineTo', ((0, 101),)),
-            ('lineTo', ((0, 651),)),
-            ('lineTo', ((0, 651),)),
-            ('closePath', ())
-        ],
-        [
-            ('moveTo', ((0, 651),)),
-            ('lineTo', ((0, 651),)),
-            ('lineTo', ((0, 101),)),
-            ('lineTo', ((0, 101),)),
-            ('closePath', ())
-        ]
     )
 ]
 
diff --git a/Tests/pens/t2CharStringPen_test.py b/Tests/pens/t2CharStringPen_test.py
index b710df5..c09d810 100644
--- a/Tests/pens/t2CharStringPen_test.py
+++ b/Tests/pens/t2CharStringPen_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.pens.t2CharStringPen import T2CharStringPen
 import unittest
 
@@ -6,12 +8,16 @@
 
     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
 
     def assertAlmostEqualProgram(self, expected, actual):
         self.assertEqual(len(expected), len(actual))
         for i1, i2 in zip(expected, actual):
-            if isinstance(i1, str):
-                self.assertIsInstance(i2, str)
+            if isinstance(i1, basestring):
+                self.assertIsInstance(i2, basestring)
                 self.assertEqual(i1, i2)
             else:
                 self.assertAlmostEqual(i1, i2)
diff --git a/Tests/pens/ttGlyphPen_test.py b/Tests/pens/ttGlyphPen_test.py
index 53db025..ede240a 100644
--- a/Tests/pens/ttGlyphPen_test.py
+++ b/Tests/pens/ttGlyphPen_test.py
@@ -1,3 +1,6 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+
 import os
 import unittest
 import struct
@@ -237,58 +240,6 @@
         with self.assertRaises(struct.error):
             compositeGlyph.compile({'a': baseGlyph})
 
-    def assertGlyphBoundsEqual(self, glyph, bounds):
-        self.assertEqual((glyph.xMin, glyph.yMin, glyph.xMax, glyph.yMax), bounds)
-
-    def test_round_float_coordinates_and_component_offsets(self):
-        glyphSet = {}
-        pen = TTGlyphPen(glyphSet)
-
-        pen.moveTo((0, 0))
-        pen.lineTo((0, 1))
-        pen.lineTo((367.6, 0))
-        pen.closePath()
-        simpleGlyph = pen.glyph()
-
-        simpleGlyph.recalcBounds(glyphSet)
-        self.assertGlyphBoundsEqual(simpleGlyph, (0, 0, 368, 1))
-
-        componentName = 'a'
-        glyphSet[componentName] = simpleGlyph
-
-        pen.addComponent(componentName, (1, 0, 0, 1, -86.4, 0))
-        compositeGlyph = pen.glyph()
-
-        compositeGlyph.recalcBounds(glyphSet)
-        self.assertGlyphBoundsEqual(compositeGlyph, (-86, 0, 282, 1))
-
-    def test_scaled_component_bounds(self):
-        glyphSet = {}
-
-        pen = TTGlyphPen(glyphSet)
-        pen.moveTo((-231, 939))
-        pen.lineTo((-55, 939))
-        pen.lineTo((-55, 745))
-        pen.lineTo((-231, 745))
-        pen.closePath()
-        glyphSet["gravecomb"] = gravecomb = pen.glyph()
-
-        pen = TTGlyphPen(glyphSet)
-        pen.moveTo((-278, 939))
-        pen.lineTo((8, 939))
-        pen.lineTo((8, 745))
-        pen.lineTo((-278, 745))
-        pen.closePath()
-        glyphSet["circumflexcomb"] = circumflexcomb = pen.glyph()
-
-        pen = TTGlyphPen(glyphSet)
-        pen.addComponent("circumflexcomb", (1, 0, 0, 1, 0, 0))
-        pen.addComponent("gravecomb", (0.9, 0, 0, 0.9, 198, 180))
-        glyphSet["uni0302_uni0300"] = uni0302_uni0300 = pen.glyph()
-
-        uni0302_uni0300.recalcBounds(glyphSet)
-        self.assertGlyphBoundsEqual(uni0302_uni0300, (-278, 745, 148, 1025))
-
 
 class _TestGlyph(object):
     def __init__(self, glyph):
diff --git a/Tests/pens/utils.py b/Tests/pens/utils.py
deleted file mode 100644
index dced3c1..0000000
--- a/Tests/pens/utils.py
+++ /dev/null
@@ -1,281 +0,0 @@
-# Copyright 2016 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from . import CUBIC_GLYPHS
-from fontTools.pens.pointPen import PointToSegmentPen, SegmentToPointPen
-from math import isclose
-import unittest
-
-
-class BaseDummyPen(object):
-    """Base class for pens that record the commands they are called with."""
-
-    def __init__(self, *args, **kwargs):
-        self.commands = []
-
-    def __str__(self):
-        """Return the pen commands as a string of python code."""
-        return _repr_pen_commands(self.commands)
-
-    def addComponent(self, glyphName, transformation, **kwargs):
-        self.commands.append(('addComponent', (glyphName, transformation), kwargs))
-
-
-class DummyPen(BaseDummyPen):
-    """A SegmentPen that records the commands it's called with."""
-
-    def moveTo(self, pt):
-        self.commands.append(('moveTo', (pt,), {}))
-
-    def lineTo(self, pt):
-        self.commands.append(('lineTo', (pt,), {}))
-
-    def curveTo(self, *points):
-        self.commands.append(('curveTo', points, {}))
-
-    def qCurveTo(self, *points):
-        self.commands.append(('qCurveTo', points, {}))
-
-    def closePath(self):
-        self.commands.append(('closePath', tuple(), {}))
-
-    def endPath(self):
-        self.commands.append(('endPath', tuple(), {}))
-
-
-class DummyPointPen(BaseDummyPen):
-    """A PointPen that records the commands it's called with."""
-
-    def beginPath(self, **kwargs):
-        self.commands.append(('beginPath', tuple(), kwargs))
-
-    def endPath(self):
-        self.commands.append(('endPath', tuple(), {}))
-
-    def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs):
-        kwargs['segmentType'] = str(segmentType) if segmentType else None
-        kwargs['smooth'] = smooth
-        kwargs['name'] = name
-        self.commands.append(('addPoint', (pt,), kwargs))
-
-
-class DummyGlyph(object):
-    """Provides a minimal interface for storing a glyph's outline data in a
-    SegmentPen-oriented way. The glyph's outline consists in the list of
-    SegmentPen commands required to draw it.
-    """
-
-    # the SegmentPen class used to draw on this glyph type
-    DrawingPen = DummyPen
-
-    def __init__(self, glyph=None):
-        """If another glyph (i.e. any object having a 'draw' method) is given,
-        its outline data is copied to self.
-        """
-        self._pen = self.DrawingPen()
-        self.outline = self._pen.commands
-        if glyph:
-            self.appendGlyph(glyph)
-
-    def appendGlyph(self, glyph):
-        """Copy another glyph's outline onto self."""
-        glyph.draw(self._pen)
-
-    def getPen(self):
-        """Return the SegmentPen that can 'draw' on this glyph."""
-        return self._pen
-
-    def getPointPen(self):
-        """Return a PointPen adapter that can 'draw' on this glyph."""
-        return PointToSegmentPen(self._pen)
-
-    def draw(self, pen):
-        """Use another SegmentPen to replay the glyph's outline commands."""
-        if self.outline:
-            for cmd, args, kwargs in self.outline:
-                getattr(pen, cmd)(*args, **kwargs)
-
-    def drawPoints(self, pointPen):
-        """Use another PointPen to replay the glyph's outline commands,
-        indirectly through an adapter.
-        """
-        pen = SegmentToPointPen(pointPen)
-        self.draw(pen)
-
-    def __eq__(self, other):
-        """Return True if 'other' glyph's outline is the same as self."""
-        if hasattr(other, 'outline'):
-            return self.outline == other.outline
-        elif hasattr(other, 'draw'):
-            return self.outline == self.__class__(other).outline
-        return NotImplemented
-
-    def __ne__(self, other):
-        """Return True if 'other' glyph's outline is different from self."""
-        return not (self == other)
-
-    def approx(self, other, rel_tol=1e-12):
-        if hasattr(other, 'outline'):
-            outline2 == other.outline
-        elif hasattr(other, 'draw'):
-            outline2 = self.__class__(other).outline
-        else:
-            raise TypeError(type(other).__name__)
-        outline1 = self.outline
-        if len(outline1) != len(outline2):
-            return False
-        for (cmd1, arg1, kwd1), (cmd2, arg2, kwd2) in zip(outline1, outline2):
-            if cmd1 != cmd2:
-                return False
-            if kwd1 != kwd2:
-                return False
-            if arg1:
-                if isinstance(arg1[0], tuple):
-                    if not arg2 or not isinstance(arg2[0], tuple):
-                        return False
-                    for (x1, y1), (x2, y2) in zip(arg1, arg2):
-                        if (
-                            not isclose(x1, x2, rel_tol=rel_tol) or
-                            not isclose(y1, y2, rel_tol=rel_tol)
-                        ):
-                            return False
-                elif arg1 != arg2:
-                    return False
-            elif arg2:
-                return False
-        return True
-
-    def __str__(self):
-        """Return commands making up the glyph's outline as a string."""
-        return str(self._pen)
-
-
-class DummyPointGlyph(DummyGlyph):
-    """Provides a minimal interface for storing a glyph's outline data in a
-    PointPen-oriented way. The glyph's outline consists in the list of
-    PointPen commands required to draw it.
-    """
-
-    # the PointPen class used to draw on this glyph type
-    DrawingPen = DummyPointPen
-
-    def appendGlyph(self, glyph):
-        """Copy another glyph's outline onto self."""
-        glyph.drawPoints(self._pen)
-
-    def getPen(self):
-        """Return a SegmentPen adapter that can 'draw' on this glyph."""
-        return SegmentToPointPen(self._pen)
-
-    def getPointPen(self):
-        """Return the PointPen that can 'draw' on this glyph."""
-        return self._pen
-
-    def draw(self, pen):
-        """Use another SegmentPen to replay the glyph's outline commands,
-        indirectly through an adapter.
-        """
-        pointPen = PointToSegmentPen(pen)
-        self.drawPoints(pointPen)
-
-    def drawPoints(self, pointPen):
-        """Use another PointPen to replay the glyph's outline commands."""
-        if self.outline:
-            for cmd, args, kwargs in self.outline:
-                getattr(pointPen, cmd)(*args, **kwargs)
-
-
-def _repr_pen_commands(commands):
-    """
-    >>> print(_repr_pen_commands([
-    ...     ('moveTo', tuple(), {}),
-    ...     ('lineTo', ((1.0, 0.1),), {}),
-    ...     ('curveTo', ((1.0, 0.1), (2.0, 0.2), (3.0, 0.3)), {})
-    ... ]))
-    pen.moveTo()
-    pen.lineTo((1, 0.1))
-    pen.curveTo((1, 0.1), (2, 0.2), (3, 0.3))
-
-    >>> print(_repr_pen_commands([
-    ...     ('beginPath', tuple(), {}),
-    ...     ('addPoint', ((1.0, 0.1),),
-    ...      {"segmentType":"line", "smooth":True, "name":"test", "z":1}),
-    ... ]))
-    pen.beginPath()
-    pen.addPoint((1, 0.1), name='test', segmentType='line', smooth=True, z=1)
-
-    >>> print(_repr_pen_commands([
-    ...    ('addComponent', ('A', (1, 0, 0, 1, 0, 0)), {})
-    ... ]))
-    pen.addComponent('A', (1, 0, 0, 1, 0, 0))
-    """
-    s = []
-    for cmd, args, kwargs in commands:
-        if args:
-            if isinstance(args[0], tuple):
-                # cast float to int if there're no digits after decimal point,
-                # and round floats to 12 decimal digits (more than enough)
-                args = [
-                    tuple((int(v) if int(v) == v else round(v, 12)) for v in pt)
-                    for pt in args
-                ]
-            args = ", ".join(repr(a) for a in args)
-        if kwargs:
-            kwargs = ", ".join("%s=%r" % (k, v)
-                               for k, v in sorted(kwargs.items()))
-        if args and kwargs:
-            s.append("pen.%s(%s, %s)" % (cmd, args, kwargs))
-        elif args:
-            s.append("pen.%s(%s)" % (cmd, args))
-        elif kwargs:
-            s.append("pen.%s(%s)" % (cmd, kwargs))
-        else:
-            s.append("pen.%s()" % cmd)
-    return "\n".join(s)
-
-
-class TestDummyGlyph(unittest.TestCase):
-
-    def test_equal(self):
-        # verify that the copy and the copy of the copy are equal to
-        # the source glyph's outline, as well as to each other
-        source = CUBIC_GLYPHS['a']
-        copy = DummyGlyph(source)
-        copy2 = DummyGlyph(copy)
-        self.assertEqual(source, copy)
-        self.assertEqual(source, copy2)
-        self.assertEqual(copy, copy2)
-        # assert equality doesn't hold any more after modification
-        copy.outline.pop()
-        self.assertNotEqual(source, copy)
-        self.assertNotEqual(copy, copy2)
-
-
-class TestDummyPointGlyph(unittest.TestCase):
-
-    def test_equal(self):
-        # same as above but using the PointPen protocol
-        source = CUBIC_GLYPHS['a']
-        copy = DummyPointGlyph(source)
-        copy2 = DummyPointGlyph(copy)
-        self.assertEqual(source, copy)
-        self.assertEqual(source, copy2)
-        self.assertEqual(copy, copy2)
-        copy.outline.pop()
-        self.assertNotEqual(source, copy)
-        self.assertNotEqual(copy, copy2)
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/Tests/subset/data/CmapSubsetTest.subset.ttx b/Tests/subset/data/CmapSubsetTest.subset.ttx
deleted file mode 100644
index 10b94a3..0000000
--- a/Tests/subset/data/CmapSubsetTest.subset.ttx
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.18">
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_4 platformID="0" platEncID="3" language="0">
-      <map code="0x61" name="a"/><!-- LATIN SMALL LETTER A -->
-    </cmap_format_4>
-    <cmap_format_4 platformID="3" platEncID="1" language="0">
-      <map code="0x61" name="a"/><!-- LATIN SMALL LETTER A -->
-    </cmap_format_4>
-  </cmap>
-
-</ttFont>
diff --git a/Tests/subset/data/CmapSubsetTest.ttx b/Tests/subset/data/CmapSubsetTest.ttx
deleted file mode 100644
index ffbfae7..0000000
--- a/Tests/subset/data/CmapSubsetTest.ttx
+++ /dev/null
@@ -1,225 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.18">
-
-  <GlyphOrder>
-    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="a"/>
-    <GlyphID id="2" name="basket"/>
-  </GlyphOrder>
-
-  <head>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="1.0"/>
-    <fontRevision value="0.0"/>
-    <checkSumAdjustment value="0xc643119c"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00000011"/>
-    <unitsPerEm value="1000"/>
-    <created value="Tue Jan 12 16:39:39 2021"/>
-    <modified value="Tue Jan 12 16:39:39 2021"/>
-    <xMin value="50"/>
-    <yMin value="-200"/>
-    <xMax value="450"/>
-    <yMax value="800"/>
-    <macStyle value="00000000 00000000"/>
-    <lowestRecPPEM value="6"/>
-    <fontDirectionHint value="2"/>
-    <indexToLocFormat value="0"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="1000"/>
-    <descent value="-200"/>
-    <lineGap value="0"/>
-    <advanceWidthMax value="942"/>
-    <minLeftSideBearing value="50"/>
-    <minRightSideBearing value="50"/>
-    <xMaxExtent value="450"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfHMetrics value="3"/>
-  </hhea>
-
-  <maxp>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="0x10000"/>
-    <numGlyphs value="3"/>
-    <maxPoints value="8"/>
-    <maxContours value="2"/>
-    <maxCompositePoints value="0"/>
-    <maxCompositeContours value="0"/>
-    <maxZones value="1"/>
-    <maxTwilightPoints value="0"/>
-    <maxStorage value="0"/>
-    <maxFunctionDefs value="0"/>
-    <maxInstructionDefs value="0"/>
-    <maxStackElements value="0"/>
-    <maxSizeOfInstructions value="0"/>
-    <maxComponentElements value="0"/>
-    <maxComponentDepth value="0"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="4"/>
-    <xAvgCharWidth value="660"/>
-    <usWeightClass value="400"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00000100"/>
-    <ySubscriptXSize value="650"/>
-    <ySubscriptYSize value="600"/>
-    <ySubscriptXOffset value="0"/>
-    <ySubscriptYOffset value="75"/>
-    <ySuperscriptXSize value="650"/>
-    <ySuperscriptYSize value="600"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="350"/>
-    <yStrikeoutSize value="50"/>
-    <yStrikeoutPosition value="300"/>
-    <sFamilyClass value="0"/>
-    <panose>
-      <bFamilyType value="0"/>
-      <bSerifStyle value="0"/>
-      <bWeight value="0"/>
-      <bProportion value="0"/>
-      <bContrast value="0"/>
-      <bStrokeVariation value="0"/>
-      <bArmStyle value="0"/>
-      <bLetterForm value="0"/>
-      <bMidline value="0"/>
-      <bXHeight value="0"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulUnicodeRange2 value="00000010 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="NONE"/>
-    <fsSelection value="00000000 01000000"/>
-    <usFirstCharIndex value="97"/>
-    <usLastCharIndex value="65535"/>
-    <sTypoAscender value="800"/>
-    <sTypoDescender value="-200"/>
-    <sTypoLineGap value="200"/>
-    <usWinAscent value="1000"/>
-    <usWinDescent value="200"/>
-    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
-    <sxHeight value="500"/>
-    <sCapHeight value="700"/>
-    <usDefaultChar value="0"/>
-    <usBreakChar value="32"/>
-    <usMaxContext value="0"/>
-  </OS_2>
-
-  <hmtx>
-    <mtx name=".notdef" width="500" lsb="50"/>
-    <mtx name="a" width="538" lsb="0"/>
-    <mtx name="basket" width="942" lsb="0"/>
-  </hmtx>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_4 platformID="0" platEncID="3" language="0">
-      <map code="0x61" name="a"/><!-- LATIN SMALL LETTER A -->
-    </cmap_format_4>
-    <cmap_format_12 platformID="0" platEncID="4" format="12" reserved="0" length="40" language="0" nGroups="2">
-      <map code="0x61" name="a"/><!-- LATIN SMALL LETTER A -->
-      <map code="0x1f9fa" name="basket"/><!-- BASKET -->
-    </cmap_format_12>
-    <cmap_format_4 platformID="3" platEncID="1" language="0">
-      <map code="0x61" name="a"/><!-- LATIN SMALL LETTER A -->
-    </cmap_format_4>
-    <cmap_format_12 platformID="3" platEncID="10" format="12" reserved="0" length="40" language="0" nGroups="2">
-      <map code="0x61" name="a"/><!-- LATIN SMALL LETTER A -->
-      <map code="0x1f9fa" name="basket"/><!-- BASKET -->
-    </cmap_format_12>
-  </cmap>
-
-  <loca>
-    <!-- The 'loca' table will be calculated by the compiler -->
-  </loca>
-
-  <glyf>
-
-    <!-- The xMin, yMin, xMax and yMax values
-         will be recalculated by the compiler. -->
-
-    <TTGlyph name=".notdef" xMin="50" yMin="-200" xMax="450" yMax="800">
-      <contour>
-        <pt x="50" y="-200" on="1"/>
-        <pt x="50" y="800" on="1"/>
-        <pt x="450" y="800" on="1"/>
-        <pt x="450" y="-200" on="1"/>
-      </contour>
-      <contour>
-        <pt x="100" y="-150" on="1"/>
-        <pt x="400" y="-150" on="1"/>
-        <pt x="400" y="750" on="1"/>
-        <pt x="100" y="750" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="a"/><!-- contains no outline data -->
-
-    <TTGlyph name="basket"/><!-- contains no outline data -->
-
-  </glyf>
-
-  <name>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      New Font
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      0.000;NONE;NewFont-Regular
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      New Font Regular
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version 0.000
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      NewFont-Regular
-    </namerecord>
-  </name>
-
-  <post>
-    <formatType value="2.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-75"/>
-    <underlineThickness value="50"/>
-    <isFixedPitch value="0"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="0"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="0"/>
-    <psNames>
-      <!-- This file uses unique glyph names based on the information
-           found in the 'post' table. Since these names might not be unique,
-           we have to invent artificial names in case of clashes. In order to
-           be able to retain the original information, we need a name to
-           ps name mapping for those cases where they differ. That's what
-           you see below.
-            -->
-    </psNames>
-    <extraNames>
-      <!-- following are the name that are not taken from the standard Mac glyph order -->
-      <psName name="basket"/>
-    </extraNames>
-  </post>
-
-</ttFont>
diff --git a/Tests/subset/data/GPOS_PairPos_Format2_ClassDef1_useClass0.subset.ttx b/Tests/subset/data/GPOS_PairPos_Format2_ClassDef1_useClass0.subset.ttx
deleted file mode 100644
index 3df9aa8..0000000
--- a/Tests/subset/data/GPOS_PairPos_Format2_ClassDef1_useClass0.subset.ttx
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="OTTO" ttLibVersion="4.21">
-
-  <GPOS>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="latn"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=1 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="test"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="0"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=1 -->
-      <Lookup index="0">
-        <LookupType value="2"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <PairPos index="0" Format="2">
-          <Coverage>
-            <Glyph value="g33"/>
-          </Coverage>
-          <ValueFormat1 value="1"/>
-          <ValueFormat2 value="0"/>
-          <ClassDef1>
-          </ClassDef1>
-          <ClassDef2>
-            <ClassDef glyph="g33" class="1"/>
-          </ClassDef2>
-          <!-- Class1Count=1 -->
-          <!-- Class2Count=2 -->
-          <Class1Record index="0">
-            <Class2Record index="0">
-              <Value1 XPlacement="0"/>
-            </Class2Record>
-            <Class2Record index="1">
-              <Value1 XPlacement="-100"/>
-            </Class2Record>
-          </Class1Record>
-        </PairPos>
-      </Lookup>
-    </LookupList>
-  </GPOS>
-
-</ttFont>
diff --git a/Tests/subset/data/GPOS_PairPos_Format2_ClassDef2_useClass0.subset.ttx b/Tests/subset/data/GPOS_PairPos_Format2_ClassDef2_useClass0.subset.ttx
deleted file mode 100644
index dc599f1..0000000
--- a/Tests/subset/data/GPOS_PairPos_Format2_ClassDef2_useClass0.subset.ttx
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="OTTO" ttLibVersion="4.21">
-
-  <GPOS>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=0 -->
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=0 -->
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=0 -->
-    </LookupList>
-  </GPOS>
-
-</ttFont>
diff --git a/Tests/subset/data/GPOS_PairPos_Format2_PR_2221.ttx b/Tests/subset/data/GPOS_PairPos_Format2_PR_2221.ttx
deleted file mode 100644
index d5132d1..0000000
--- a/Tests/subset/data/GPOS_PairPos_Format2_PR_2221.ttx
+++ /dev/null
@@ -1,322 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="OTTO" ttLibVersion="4.21">
-
-  <GlyphOrder>
-    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="g33"/>
-    <GlyphID id="2" name="g35"/>
-  </GlyphOrder>
-
-  <head>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="1.0"/>
-    <fontRevision value="1.0"/>
-    <checkSumAdjustment value="0x3d6ba467"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00000001"/>
-    <unitsPerEm value="1500"/>
-    <created value="Thu Jan  1 00:00:00 1970"/>
-    <modified value="Mon Mar 29 14:18:07 2021"/>
-    <xMin value="24"/>
-    <yMin value="-31"/>
-    <xMax value="1000"/>
-    <yMax value="689"/>
-    <macStyle value="00000000 00000000"/>
-    <lowestRecPPEM value="3"/>
-    <fontDirectionHint value="2"/>
-    <indexToLocFormat value="0"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="2500"/>
-    <descent value="0"/>
-    <lineGap value="200"/>
-    <advanceWidthMax value="1500"/>
-    <minLeftSideBearing value="300"/>
-    <minRightSideBearing value="224"/>
-    <xMaxExtent value="1276"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfHMetrics value="1"/>
-  </hhea>
-
-  <maxp>
-    <tableVersion value="0x5000"/>
-    <numGlyphs value="3"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="2"/>
-    <xAvgCharWidth value="2500"/>
-    <usWeightClass value="400"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00001100"/>
-    <ySubscriptXSize value="500"/>
-    <ySubscriptYSize value="500"/>
-    <ySubscriptXOffset value="250"/>
-    <ySubscriptYOffset value="50"/>
-    <ySuperscriptXSize value="500"/>
-    <ySuperscriptYSize value="500"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="500"/>
-    <yStrikeoutSize value="50"/>
-    <yStrikeoutPosition value="500"/>
-    <sFamilyClass value="0"/>
-    <panose>
-      <bFamilyType value="2"/>
-      <bSerifStyle value="10"/>
-      <bWeight value="6"/>
-      <bProportion value="3"/>
-      <bContrast value="6"/>
-      <bStrokeVariation value="5"/>
-      <bArmStyle value="11"/>
-      <bLetterForm value="2"/>
-      <bMidline value="2"/>
-      <bXHeight value="4"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="ADBE"/>
-    <fsSelection value="00000000 01000000"/>
-    <usFirstCharIndex value="33"/>
-    <usLastCharIndex value="35"/>
-    <sTypoAscender value="2500"/>
-    <sTypoDescender value="0"/>
-    <sTypoLineGap value="200"/>
-    <usWinAscent value="2500"/>
-    <usWinDescent value="0"/>
-    <ulCodePageRange1 value="11100000 00111111 00000001 11111111"/>
-    <ulCodePageRange2 value="11111111 11111111 00000000 00000000"/>
-    <sxHeight value="2500"/>
-    <sCapHeight value="2500"/>
-    <usDefaultChar value="65"/>
-    <usBreakChar value="65"/>
-    <usMaxContext value="0"/>
-  </OS_2>
-
-  <name>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      gpos2_2_font5
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      gpos2_2_font5
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      gpos2_2_font5
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version1.0
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      gpos2_2_font5
-    </namerecord>
-  </name>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_4 platformID="3" platEncID="1" language="0">
-      <map code="0x21" name="g33"/><!-- EXCLAMATION MARK -->
-      <map code="0x23" name="g35"/><!-- NUMBER SIGN -->
-    </cmap_format_4>
-  </cmap>
-
-  <post>
-    <formatType value="3.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-100"/>
-    <underlineThickness value="50"/>
-    <isFixedPitch value="0"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="0"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="0"/>
-  </post>
-
-  <CFF>
-    <major value="1"/>
-    <minor value="0"/>
-    <CFFFont name="dummy">
-      <version value="001.000"/>
-      <Notice value="Copyright (c) 2002 Adobe Systems Incorporated. All Rights Reserved."/>
-      <FullName value="dummy"/>
-      <FamilyName value="dummy"/>
-      <Weight value="Regular"/>
-      <isFixedPitch value="0"/>
-      <ItalicAngle value="0"/>
-      <UnderlinePosition value="-125"/>
-      <UnderlineThickness value="50"/>
-      <PaintType value="0"/>
-      <CharstringType value="2"/>
-      <FontMatrix value="0.0008 0 0 0.0008 0 0"/>
-      <UniqueID value="44788"/>
-      <FontBBox value="24 -31 1000 689"/>
-      <StrokeWidth value="0"/>
-      <!-- charset is dumped separately as the 'GlyphOrder' element -->
-      <Encoding name="StandardEncoding"/>
-      <Private>
-        <BlueValues value="-25 0 657 682 439 464 640 653 708 733 475 500"/>
-        <OtherBlues value="283 308 -251 -226 -154 -129 -194 -169"/>
-        <FamilyBlues value="-25 0 657 682 439 464 640 653 708 733 475 500"/>
-        <FamilyOtherBlues value="283 308 -251 -226 -154 -129 -194 -169"/>
-        <BlueScale value="0.039625"/>
-        <BlueShift value="7"/>
-        <BlueFuzz value="1"/>
-        <StdHW value="32"/>
-        <StdVW value="85"/>
-        <StemSnapH value="32"/>
-        <StemSnapV value="85 90"/>
-        <ForceBold value="0"/>
-        <LanguageGroup value="0"/>
-        <ExpansionFactor value="0.06"/>
-        <initialRandomSeed value="0"/>
-        <defaultWidthX value="2500"/>
-        <nominalWidthX value="2500"/>
-        <Subrs>
-          <!-- The 'index' attribute is only for humans; it is ignored when parsed. -->
-          <CharString index="0">
-            92 580 rmoveto
-            13 6 13 7 14 4 54 16 184 1 9 -81 1 -13 -3 -13 -3 -14 -9 -45 -124 -14 -42 -8 rrcurveto
-            -2 -2 1 -1 hhcurveto
-            -2 vlineto
-            -30 -15 5 -40 35 -4 60 -5 62 -4 47 -43 83 -75 -108 -134 -82 -20 -75 -17 -101 91 -42 -14 -22 -8 -7 -18 10 -21 2 -2 2 -2 1 -2 10 -10 11 -3 10 2 rrcurveto
-            2 2 -1 1 hhcurveto
-            16 -7 15 -7 15 -7 33 -14 33 -14 35 -7 103 -18 81 94 48 78 51 83 -64 98 -77 36 -4 1 -3 2 -4 2 17 7 16 9 15 12 77 61 -32 107 -79 40 -91 47 -115 -9 -91 -40 rrcurveto
-            -27 -24 18 -37 36 7 rrcurveto
-            408 -580 rmoveto
-            return
-          </CharString>
-          <CharString index="1">
-            41 642 rmoveto
-            1 -2 1 -1 -1 vvcurveto
-            -7 2 -7 5 -5 vhcurveto
-            15 -69 -71 -105 61 -45 71 -50 214 60 48 -116 9 -20 3 -24 -3 -22 -13 -128 -51 -35 -120 -6 -38 -1 -62 -5 -26 34 -29 22 -33 -28 16 -33 39 -51 75 0 59 2 83 5 76 21 49 69 rrcurveto
-            25 36 0 48 11 42 19 72 -43 43 -42 45 -62 68 -159 -25 -76 26 -20 43 44 56 -6 66 101 14 102 -5 103 -1 37 7 0 42 -35 11 -109 1 -110 5 -108 -17 rrcurveto
-            -1 1 0 0 1 vvcurveto
-            -25 33 -45 -26 18 -38 rrcurveto
-            407 -673 rmoveto
-            return
-          </CharString>
-        </Subrs>
-      </Private>
-      <CharStrings>
-        <CharString name=".notdef">
-          endchar
-        </CharString>
-        <CharString name="g33">
-          -107 callsubr
-          -107 callsubr
-          endchar
-        </CharString>
-        <CharString name="g35">
-          -107 callsubr
-          -106 callsubr
-          endchar
-        </CharString>
-      </CharStrings>
-    </CFFFont>
-
-    <GlobalSubrs>
-      <!-- The 'index' attribute is only for humans; it is ignored when parsed. -->
-    </GlobalSubrs>
-  </CFF>
-
-  <GPOS>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="latn"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=1 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="test"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="0"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=1 -->
-      <Lookup index="0">
-        <LookupType value="2"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <PairPos index="0" Format="2">
-          <Coverage Format="1">
-            <Glyph value="g33"/>
-            <Glyph value="g35"/>
-          </Coverage>
-          <ValueFormat1 value="1"/>
-          <ValueFormat2 value="0"/>
-          <ClassDef1 Format="1">
-            <ClassDef glyph="g33" class="1"/>
-            <ClassDef glyph="g35" class="2"/>
-          </ClassDef1>
-          <ClassDef2 Format="1">
-            <ClassDef glyph="g33" class="1"/>
-          </ClassDef2>
-          <!-- Class1Count=3 -->
-          <!-- Class2Count=2 -->
-          <Class1Record index="0">
-            <Class2Record index="0">
-              <Value1 XPlacement="0"/>
-            </Class2Record>
-            <Class2Record index="1">
-              <Value1 XPlacement="0"/>
-            </Class2Record>
-          </Class1Record>
-          <Class1Record index="1">
-            <Class2Record index="0">
-              <Value1 XPlacement="0"/>
-            </Class2Record>
-            <Class2Record index="1">
-              <Value1 XPlacement="-100"/>
-            </Class2Record>
-          </Class1Record>
-          <Class1Record index="2">
-            <Class2Record index="0">
-              <Value1 XPlacement="0"/>
-            </Class2Record>
-            <Class2Record index="1">
-              <Value1 XPlacement="-100"/>
-            </Class2Record>
-          </Class1Record>
-        </PairPos>
-      </Lookup>
-    </LookupList>
-  </GPOS>
-
-  <hmtx>
-    <mtx name=".notdef" width="1500" lsb="300"/>
-    <mtx name="g33" width="1500" lsb="300"/>
-    <mtx name="g35" width="1500" lsb="300"/>
-  </hmtx>
-
-</ttFont>
diff --git a/Tests/subset/data/Lobster.subset.ttx b/Tests/subset/data/Lobster.subset.ttx
index 8089b24..c35e570 100644
--- a/Tests/subset/data/Lobster.subset.ttx
+++ b/Tests/subset/data/Lobster.subset.ttx
@@ -490,7 +490,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="2">
             <Glyph value="one"/>
             <Glyph value="three"/>
             <Glyph value="two"/>
@@ -616,7 +616,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="A" out="A.salt"/>
           <Substitution in="B" out="B.salt"/>
         </SingleSubst>
@@ -625,7 +625,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="I">
             <Ligature components="J" glyph="IJ"/>
           </LigatureSet>
@@ -635,7 +635,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="A" out="A.salt"/>
           <Substitution in="B" out="B.salt"/>
         </SingleSubst>
diff --git a/Tests/subset/data/TestContextSubstFormat3.ttx b/Tests/subset/data/TestContextSubstFormat3.ttx
deleted file mode 100644
index 0ed43ee..0000000
--- a/Tests/subset/data/TestContextSubstFormat3.ttx
+++ /dev/null
@@ -1,604 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.9">
-
-  <GlyphOrder>
-    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="plus"/>
-    <GlyphID id="2" name="glyph00002"/>
-    <GlyphID id="3" name="glyph00003"/>
-    <GlyphID id="4" name="glyph00004"/>
-    <GlyphID id="5" name="glyph00005"/>
-    <GlyphID id="6" name="glyph00006"/>
-    <GlyphID id="7" name="glyph00007"/>
-  </GlyphOrder>
-
-  <head>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="1.0"/>
-    <fontRevision value="1.0"/>
-    <checkSumAdjustment value="0xa6bcdc24"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00001111"/>
-    <unitsPerEm value="1000"/>
-    <created value="Mon Nov 21 06:10:39 2016"/>
-    <modified value="Fri Apr 24 05:31:23 2020"/>
-    <xMin value="-1000"/>
-    <yMin value="-509"/>
-    <xMax value="1135"/>
-    <yMax value="1194"/>
-    <macStyle value="00000000 00000000"/>
-    <lowestRecPPEM value="8"/>
-    <fontDirectionHint value="0"/>
-    <indexToLocFormat value="0"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="977"/>
-    <descent value="-205"/>
-    <lineGap value="67"/>
-    <advanceWidthMax value="1000"/>
-    <minLeftSideBearing value="-1000"/>
-    <minRightSideBearing value="-1000"/>
-    <xMaxExtent value="1135"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfHMetrics value="1"/>
-  </hhea>
-
-  <maxp>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="0x10000"/>
-    <numGlyphs value="8"/>
-    <maxPoints value="240"/>
-    <maxContours value="41"/>
-    <maxCompositePoints value="163"/>
-    <maxCompositeContours value="12"/>
-    <maxZones value="1"/>
-    <maxTwilightPoints value="0"/>
-    <maxStorage value="0"/>
-    <maxFunctionDefs value="0"/>
-    <maxInstructionDefs value="0"/>
-    <maxStackElements value="0"/>
-    <maxSizeOfInstructions value="0"/>
-    <maxComponentElements value="4"/>
-    <maxComponentDepth value="3"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="4"/>
-    <xAvgCharWidth value="500"/>
-    <usWeightClass value="500"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00000000"/>
-    <ySubscriptXSize value="665"/>
-    <ySubscriptYSize value="716"/>
-    <ySubscriptXOffset value="0"/>
-    <ySubscriptYOffset value="143"/>
-    <ySuperscriptXSize value="0"/>
-    <ySuperscriptYSize value="0"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="0"/>
-    <yStrikeoutSize value="51"/>
-    <yStrikeoutPosition value="265"/>
-    <sFamilyClass value="2057"/>
-    <panose>
-      <bFamilyType value="2"/>
-      <bSerifStyle value="0"/>
-      <bWeight value="6"/>
-      <bProportion value="9"/>
-      <bContrast value="0"/>
-      <bStrokeVariation value="0"/>
-      <bArmStyle value="0"/>
-      <bLetterForm value="0"/>
-      <bMidline value="0"/>
-      <bXHeight value="0"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="BE5N"/>
-    <fsSelection value="00000000 11000000"/>
-    <usFirstCharIndex value="43"/>
-    <usLastCharIndex value="43"/>
-    <sTypoAscender value="977"/>
-    <sTypoDescender value="-272"/>
-    <sTypoLineGap value="0"/>
-    <usWinAscent value="977"/>
-    <usWinDescent value="272"/>
-    <ulCodePageRange1 value="00100000 00000000 00000001 00011111"/>
-    <ulCodePageRange2 value="11000100 00000000 00000000 00000000"/>
-    <sxHeight value="530"/>
-    <sCapHeight value="735"/>
-    <usDefaultChar value="0"/>
-    <usBreakChar value="32"/>
-    <usMaxContext value="8"/>
-  </OS_2>
-
-  <hmtx>
-    <mtx name=".notdef" width="500" lsb="57"/>
-    <mtx name="glyph00002" width="500" lsb="57"/>
-    <mtx name="glyph00003" width="500" lsb="57"/>
-    <mtx name="glyph00004" width="500" lsb="-8"/>
-    <mtx name="glyph00005" width="500" lsb="-8"/>
-    <mtx name="glyph00006" width="500" lsb="-8"/>
-    <mtx name="glyph00007" width="500" lsb="-65"/>
-    <mtx name="plus" width="500" lsb="57"/>
-  </hmtx>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_4 platformID="0" platEncID="3" language="0">
-      <map code="0x2b" name="plus"/><!-- PLUS SIGN -->
-    </cmap_format_4>
-    <cmap_format_4 platformID="3" platEncID="1" language="0">
-      <map code="0x2b" name="plus"/><!-- PLUS SIGN -->
-    </cmap_format_4>
-  </cmap>
-
-  <loca>
-    <!-- The 'loca' table will be calculated by the compiler -->
-  </loca>
-
-  <glyf>
-
-    <!-- The xMin, yMin, xMax and yMax values
-         will be recalculated by the compiler. -->
-
-    <TTGlyph name=".notdef"/><!-- contains no outline data -->
-
-    <TTGlyph name="glyph00002" xMin="57" yMin="139" xMax="508" yMax="541">
-      <contour>
-        <pt x="203" y="139" on="1"/>
-        <pt x="203" y="298" on="1"/>
-        <pt x="57" y="298" on="1"/>
-        <pt x="57" y="382" on="1"/>
-        <pt x="203" y="382" on="1"/>
-        <pt x="203" y="541" on="1"/>
-        <pt x="297" y="541" on="1"/>
-        <pt x="297" y="382" on="1"/>
-        <pt x="508" y="382" on="1"/>
-        <pt x="508" y="298" on="1"/>
-        <pt x="297" y="298" on="1"/>
-        <pt x="297" y="139" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="glyph00003" xMin="57" yMin="139" xMax="508" yMax="541">
-      <contour>
-        <pt x="260" y="139" on="1"/>
-        <pt x="260" y="298" on="1"/>
-        <pt x="57" y="298" on="1"/>
-        <pt x="57" y="382" on="1"/>
-        <pt x="260" y="382" on="1"/>
-        <pt x="260" y="541" on="1"/>
-        <pt x="354" y="541" on="1"/>
-        <pt x="354" y="382" on="1"/>
-        <pt x="508" y="382" on="1"/>
-        <pt x="508" y="298" on="1"/>
-        <pt x="354" y="298" on="1"/>
-        <pt x="354" y="139" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="glyph00004" xMin="-8" yMin="139" xMax="508" yMax="541">
-      <contour>
-        <pt x="203" y="139" on="1"/>
-        <pt x="203" y="298" on="1"/>
-        <pt x="-8" y="298" on="1"/>
-        <pt x="-8" y="382" on="1"/>
-        <pt x="203" y="382" on="1"/>
-        <pt x="203" y="541" on="1"/>
-        <pt x="297" y="541" on="1"/>
-        <pt x="297" y="382" on="1"/>
-        <pt x="508" y="382" on="1"/>
-        <pt x="508" y="298" on="1"/>
-        <pt x="297" y="298" on="1"/>
-        <pt x="297" y="139" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="glyph00005" xMin="-8" yMin="139" xMax="443" yMax="541">
-      <contour>
-        <pt x="203" y="139" on="1"/>
-        <pt x="203" y="298" on="1"/>
-        <pt x="-8" y="298" on="1"/>
-        <pt x="-8" y="382" on="1"/>
-        <pt x="203" y="382" on="1"/>
-        <pt x="203" y="541" on="1"/>
-        <pt x="297" y="541" on="1"/>
-        <pt x="297" y="382" on="1"/>
-        <pt x="443" y="382" on="1"/>
-        <pt x="443" y="298" on="1"/>
-        <pt x="297" y="298" on="1"/>
-        <pt x="297" y="139" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="glyph00006" xMin="-8" yMin="139" xMax="443" yMax="541">
-      <contour>
-        <pt x="146" y="139" on="1"/>
-        <pt x="146" y="298" on="1"/>
-        <pt x="-8" y="298" on="1"/>
-        <pt x="-8" y="382" on="1"/>
-        <pt x="146" y="382" on="1"/>
-        <pt x="146" y="541" on="1"/>
-        <pt x="240" y="541" on="1"/>
-        <pt x="240" y="382" on="1"/>
-        <pt x="443" y="382" on="1"/>
-        <pt x="443" y="298" on="1"/>
-        <pt x="240" y="298" on="1"/>
-        <pt x="240" y="139" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="glyph00007" xMin="-65" yMin="139" xMax="443" yMax="541">
-      <contour>
-        <pt x="203" y="139" on="1"/>
-        <pt x="203" y="298" on="1"/>
-        <pt x="-65" y="298" on="1"/>
-        <pt x="-65" y="382" on="1"/>
-        <pt x="203" y="382" on="1"/>
-        <pt x="203" y="541" on="1"/>
-        <pt x="297" y="541" on="1"/>
-        <pt x="297" y="382" on="1"/>
-        <pt x="443" y="382" on="1"/>
-        <pt x="443" y="298" on="1"/>
-        <pt x="297" y="298" on="1"/>
-        <pt x="297" y="139" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="plus" xMin="57" yMin="139" xMax="443" yMax="541">
-      <contour>
-        <pt x="203" y="139" on="1"/>
-        <pt x="203" y="298" on="1"/>
-        <pt x="57" y="298" on="1"/>
-        <pt x="57" y="382" on="1"/>
-        <pt x="203" y="382" on="1"/>
-        <pt x="203" y="541" on="1"/>
-        <pt x="297" y="541" on="1"/>
-        <pt x="297" y="382" on="1"/>
-        <pt x="443" y="382" on="1"/>
-        <pt x="443" y="298" on="1"/>
-        <pt x="297" y="298" on="1"/>
-        <pt x="297" y="139" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-  </glyf>
-
-  <name>
-    <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
-      Copyright (c) 2015-2019 Belleve Invis.
-    </namerecord>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      Iosevka Medium
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      Iosevka Medium Version 3.0.0-rc.8
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      Iosevka Medium
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version 3.0.0-rc.8; ttfautohint (v1.8.3)
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      Iosevka-Medium
-    </namerecord>
-  </name>
-
-  <post>
-    <formatType value="3.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-50"/>
-    <underlineThickness value="50"/>
-    <isFixedPitch value="1"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="6380"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="1"/>
-  </post>
-
-  <gasp>
-    <gaspRange rangeMaxPPEM="65535" rangeGaspBehavior="15"/>
-  </gasp>
-
-  <GDEF>
-    <Version value="0x00010000"/>
-    <GlyphClassDef>
-      <ClassDef glyph=".notdef" class="1"/>
-      <ClassDef glyph="glyph00002" class="1"/>
-      <ClassDef glyph="glyph00003" class="1"/>
-      <ClassDef glyph="glyph00004" class="1"/>
-      <ClassDef glyph="glyph00005" class="1"/>
-      <ClassDef glyph="glyph00006" class="1"/>
-      <ClassDef glyph="glyph00007" class="1"/>
-      <ClassDef glyph="plus" class="1"/>
-    </GlyphClassDef>
-  </GDEF>
-
-  <GPOS>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=0 -->
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=0 -->
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=0 -->
-    </LookupList>
-  </GPOS>
-
-  <GSUB>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=4 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-      <ScriptRecord index="1">
-        <ScriptTag value="cyrl"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-      <ScriptRecord index="2">
-        <ScriptTag value="grek"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-      <ScriptRecord index="3">
-        <ScriptTag value="latn"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=1 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="calt"/>
-        <Feature>
-          <!-- LookupCount=2 -->
-          <LookupListIndex index="0" value="0"/>
-          <LookupListIndex index="1" value="1"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=6 -->
-      <Lookup index="0">
-        <LookupType value="6"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <ChainContextSubst index="0" Format="2">
-          <Coverage>
-            <Glyph value="plus"/>
-          </Coverage>
-          <BacktrackClassDef>
-            <ClassDef glyph="glyph00005" class="1"/>
-            <ClassDef glyph="glyph00007" class="1"/>
-          </BacktrackClassDef>
-          <InputClassDef>
-            <ClassDef glyph="plus" class="1"/>
-          </InputClassDef>
-          <LookAheadClassDef>
-          </LookAheadClassDef>
-          <!-- ChainSubClassSetCount=2 -->
-          <ChainSubClassSet index="0" empty="1"/>
-          <ChainSubClassSet index="1">
-            <!-- ChainSubClassRuleCount=4 -->
-            <ChainSubClassRule index="0">
-              <!-- BacktrackGlyphCount=1 -->
-              <Backtrack index="0" value="1"/>
-              <!-- InputGlyphCount=1 -->
-              <!-- LookAheadGlyphCount=0 -->
-              <!-- SubstCount=1 -->
-              <SubstLookupRecord index="0">
-                <SequenceIndex value="0"/>
-                <LookupListIndex value="5"/>
-              </SubstLookupRecord>
-            </ChainSubClassRule>
-            <ChainSubClassRule index="1">
-              <!-- BacktrackGlyphCount=0 -->
-              <!-- InputGlyphCount=4 -->
-              <Input index="0" value="1"/>
-              <Input index="1" value="1"/>
-              <Input index="2" value="1"/>
-              <!-- LookAheadGlyphCount=0 -->
-              <!-- SubstCount=4 -->
-              <SubstLookupRecord index="0">
-                <SequenceIndex value="0"/>
-                <LookupListIndex value="4"/>
-              </SubstLookupRecord>
-              <SubstLookupRecord index="1">
-                <SequenceIndex value="1"/>
-                <LookupListIndex value="3"/>
-              </SubstLookupRecord>
-              <SubstLookupRecord index="2">
-                <SequenceIndex value="2"/>
-                <LookupListIndex value="3"/>
-              </SubstLookupRecord>
-              <SubstLookupRecord index="3">
-                <SequenceIndex value="3"/>
-                <LookupListIndex value="2"/>
-              </SubstLookupRecord>
-            </ChainSubClassRule>
-            <ChainSubClassRule index="2">
-              <!-- BacktrackGlyphCount=0 -->
-              <!-- InputGlyphCount=3 -->
-              <Input index="0" value="1"/>
-              <Input index="1" value="1"/>
-              <!-- LookAheadGlyphCount=0 -->
-              <!-- SubstCount=3 -->
-              <SubstLookupRecord index="0">
-                <SequenceIndex value="0"/>
-                <LookupListIndex value="4"/>
-              </SubstLookupRecord>
-              <SubstLookupRecord index="1">
-                <SequenceIndex value="1"/>
-                <LookupListIndex value="3"/>
-              </SubstLookupRecord>
-              <SubstLookupRecord index="2">
-                <SequenceIndex value="2"/>
-                <LookupListIndex value="2"/>
-              </SubstLookupRecord>
-            </ChainSubClassRule>
-            <ChainSubClassRule index="3">
-              <!-- BacktrackGlyphCount=0 -->
-              <!-- InputGlyphCount=2 -->
-              <Input index="0" value="1"/>
-              <!-- LookAheadGlyphCount=0 -->
-              <!-- SubstCount=2 -->
-              <SubstLookupRecord index="0">
-                <SequenceIndex value="0"/>
-                <LookupListIndex value="4"/>
-              </SubstLookupRecord>
-              <SubstLookupRecord index="1">
-                <SequenceIndex value="1"/>
-                <LookupListIndex value="2"/>
-              </SubstLookupRecord>
-            </ChainSubClassRule>
-          </ChainSubClassSet>
-        </ChainContextSubst>
-      </Lookup>
-      <Lookup index="1">
-        <LookupType value="5"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=2 -->
-        <ContextSubst index="0" Format="3">
-          <!-- GlyphCount=3 -->
-          <!-- SubstCount=2 -->
-          <Coverage index="0">
-            <Glyph value="glyph00002"/>
-          </Coverage>
-          <Coverage index="1">
-            <Glyph value="glyph00004"/>
-          </Coverage>
-          <Coverage index="2">
-            <Glyph value="glyph00005"/>
-          </Coverage>
-          <SubstLookupRecord index="0">
-            <SequenceIndex value="0"/>
-            <LookupListIndex value="5"/>
-          </SubstLookupRecord>
-          <SubstLookupRecord index="1">
-            <SequenceIndex value="2"/>
-            <LookupListIndex value="5"/>
-          </SubstLookupRecord>
-        </ContextSubst>
-        <ContextSubst index="1" Format="3">
-          <!-- GlyphCount=2 -->
-          <!-- SubstCount=2 -->
-          <Coverage index="0">
-            <Glyph value="glyph00002"/>
-          </Coverage>
-          <Coverage index="1">
-            <Glyph value="glyph00005"/>
-          </Coverage>
-          <SubstLookupRecord index="0">
-            <SequenceIndex value="0"/>
-            <LookupListIndex value="5"/>
-          </SubstLookupRecord>
-          <SubstLookupRecord index="1">
-            <SequenceIndex value="1"/>
-            <LookupListIndex value="5"/>
-          </SubstLookupRecord>
-        </ContextSubst>
-      </Lookup>
-      <Lookup index="2">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="plus" out="glyph00005"/>
-        </SingleSubst>
-      </Lookup>
-      <Lookup index="3">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="plus" out="glyph00004"/>
-        </SingleSubst>
-      </Lookup>
-      <Lookup index="4">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="plus" out="glyph00002"/>
-        </SingleSubst>
-      </Lookup>
-      <Lookup index="5">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="glyph00002" out="glyph00003"/>
-          <Substitution in="glyph00005" out="glyph00006"/>
-          <Substitution in="plus" out="glyph00007"/>
-        </SingleSubst>
-      </Lookup>
-    </LookupList>
-  </GSUB>
-
-</ttFont>
diff --git a/Tests/subset/data/expect_keep_math.ttx b/Tests/subset/data/expect_keep_math.ttx
index f2bc41d..c734dd9 100644
--- a/Tests/subset/data/expect_keep_math.ttx
+++ b/Tests/subset/data/expect_keep_math.ttx
@@ -417,7 +417,7 @@
     </MathConstants>
     <MathGlyphInfo>
       <MathItalicsCorrectionInfo>
-        <Coverage>
+        <Coverage Format="1">
           <Glyph value="u1D435"/>
         </Coverage>
         <!-- ItalicsCorrectionCount=1 -->
@@ -426,7 +426,7 @@
         </ItalicsCorrection>
       </MathItalicsCorrectionInfo>
       <MathTopAccentAttachment>
-        <TopAccentCoverage>
+        <TopAccentCoverage Format="1">
           <Glyph value="A"/>
           <Glyph value="uni0302"/>
           <Glyph value="u1D400"/>
@@ -466,14 +466,14 @@
           <Value value="1164"/>
         </TopAccentAttachment>
       </MathTopAccentAttachment>
-      <ExtendedShapeCoverage>
+      <ExtendedShapeCoverage Format="1">
         <Glyph value="parenleft.size1"/>
         <Glyph value="parenleft.size2"/>
         <Glyph value="parenleft.size3"/>
         <Glyph value="parenleft.size4"/>
       </ExtendedShapeCoverage>
       <MathKernInfo>
-        <MathKernCoverage>
+        <MathKernCoverage Format="1">
           <Glyph value="A"/>
           <Glyph value="u1D400"/>
         </MathKernCoverage>
@@ -522,10 +522,10 @@
     </MathGlyphInfo>
     <MathVariants>
       <MinConnectorOverlap value="50"/>
-      <VertGlyphCoverage>
+      <VertGlyphCoverage Format="1">
         <Glyph value="parenleft"/>
       </VertGlyphCoverage>
-      <HorizGlyphCoverage>
+      <HorizGlyphCoverage Format="1">
         <Glyph value="uni0302"/>
       </HorizGlyphCoverage>
       <!-- VertGlyphCount=1 -->
diff --git a/Tests/subset/data/expect_layout_scripts.ttx b/Tests/subset/data/expect_layout_scripts.ttx
deleted file mode 100644
index bd35083..0000000
--- a/Tests/subset/data/expect_layout_scripts.ttx
+++ /dev/null
@@ -1,129 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont>
-
-  <GPOS>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=0 -->
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=0 -->
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=0 -->
-    </LookupList>
-  </GPOS>
-
-  <GSUB>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=2 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="arab"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="2"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=1 -->
-          <LangSysRecord index="0">
-            <LangSysTag value="URD "/>
-            <LangSys>
-              <ReqFeatureIndex value="65535"/>
-              <!-- FeatureCount=2 -->
-              <FeatureIndex index="0" value="1"/>
-              <FeatureIndex index="1" value="2"/>
-            </LangSys>
-          </LangSysRecord>
-        </Script>
-      </ScriptRecord>
-      <ScriptRecord index="1">
-        <ScriptTag value="latn"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="2"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=1 -->
-          <LangSysRecord index="0">
-            <LangSysTag value="TRK "/>
-            <LangSys>
-              <ReqFeatureIndex value="65535"/>
-              <!-- FeatureCount=2 -->
-              <FeatureIndex index="0" value="0"/>
-              <FeatureIndex index="1" value="2"/>
-            </LangSys>
-          </LangSysRecord>
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=3 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="locl"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="2"/>
-        </Feature>
-      </FeatureRecord>
-      <FeatureRecord index="1">
-        <FeatureTag value="locl"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="0"/>
-        </Feature>
-      </FeatureRecord>
-      <FeatureRecord index="2">
-        <FeatureTag value="numr"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="1"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=3 -->
-      <Lookup index="0">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="uni06F4" out="uni06F4.urd"/>
-          <Substitution in="uni06F6" out="uni06F6.urd"/>
-          <Substitution in="uni06F7" out="uni06F7.urd"/>
-        </SingleSubst>
-      </Lookup>
-      <Lookup index="1">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="uni06F0" out="uni06F0.numr"/>
-          <Substitution in="uni06F1" out="uni06F1.numr"/>
-          <Substitution in="uni06F2" out="uni06F2.numr"/>
-          <Substitution in="uni06F3" out="uni06F3.numr"/>
-          <Substitution in="uni06F4" out="uni06F4.numr"/>
-          <Substitution in="uni06F4.urd" out="uni06F4.urd.numr"/>
-          <Substitution in="uni06F5" out="uni06F5.numr"/>
-          <Substitution in="uni06F6" out="uni06F6.numr"/>
-          <Substitution in="uni06F6.urd" out="uni06F6.urd.numr"/>
-          <Substitution in="uni06F7" out="uni06F7.numr"/>
-          <Substitution in="uni06F7.urd" out="uni06F7.urd.numr"/>
-          <Substitution in="uni06F8" out="uni06F8.numr"/>
-          <Substitution in="uni06F9" out="uni06F9.numr"/>
-        </SingleSubst>
-      </Lookup>
-      <Lookup index="2">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="i" out="i.TRK"/>
-        </SingleSubst>
-      </Lookup>
-    </LookupList>
-  </GSUB>
-
-</ttFont>
diff --git a/Tests/subset/data/layout_scripts.ttx b/Tests/subset/data/layout_scripts.ttx
deleted file mode 100644
index ddf0cd6..0000000
--- a/Tests/subset/data/layout_scripts.ttx
+++ /dev/null
@@ -1,997 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="OTTO" ttLibVersion="4.17">
-
-  <GlyphOrder>
-    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="i"/>
-    <GlyphID id="2" name="uni06F0"/>
-    <GlyphID id="3" name="uni06F1"/>
-    <GlyphID id="4" name="uni06F2"/>
-    <GlyphID id="5" name="uni06F3"/>
-    <GlyphID id="6" name="uni06F4"/>
-    <GlyphID id="7" name="uni06F5"/>
-    <GlyphID id="8" name="uni06F6"/>
-    <GlyphID id="9" name="uni06F7"/>
-    <GlyphID id="10" name="uni06F8"/>
-    <GlyphID id="11" name="uni06F9"/>
-    <GlyphID id="12" name="uni06F4.urd"/>
-    <GlyphID id="13" name="uni06F6.urd"/>
-    <GlyphID id="14" name="uni06F7.urd"/>
-    <GlyphID id="15" name="uni06F0.numr"/>
-    <GlyphID id="16" name="uni06F1.numr"/>
-    <GlyphID id="17" name="uni06F2.numr"/>
-    <GlyphID id="18" name="uni06F3.numr"/>
-    <GlyphID id="19" name="uni06F4.numr"/>
-    <GlyphID id="20" name="uni06F5.numr"/>
-    <GlyphID id="21" name="uni06F6.numr"/>
-    <GlyphID id="22" name="uni06F7.numr"/>
-    <GlyphID id="23" name="uni06F8.numr"/>
-    <GlyphID id="24" name="uni06F9.numr"/>
-    <GlyphID id="25" name="uni06F4.urd.numr"/>
-    <GlyphID id="26" name="uni06F6.urd.numr"/>
-    <GlyphID id="27" name="uni06F7.urd.numr"/>
-    <GlyphID id="28" name="i.TRK"/>
-  </GlyphOrder>
-
-  <head>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="1.0"/>
-    <fontRevision value="0.114"/>
-    <checkSumAdjustment value="0xe87b6e18"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00000011"/>
-    <unitsPerEm value="1000"/>
-    <created value="Fri May  7 21:08:01 2010"/>
-    <modified value="Thu Jan  1 00:00:00 1970"/>
-    <xMin value="-581"/>
-    <yMin value="-898"/>
-    <xMax value="11462"/>
-    <yMax value="1814"/>
-    <macStyle value="00000000 00000000"/>
-    <lowestRecPPEM value="6"/>
-    <fontDirectionHint value="2"/>
-    <indexToLocFormat value="0"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="1124"/>
-    <descent value="-634"/>
-    <lineGap value="0"/>
-    <advanceWidthMax value="11435"/>
-    <minLeftSideBearing value="-581"/>
-    <minRightSideBearing value="-970"/>
-    <xMaxExtent value="11462"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfHMetrics value="29"/>
-  </hhea>
-
-  <maxp>
-    <tableVersion value="0x5000"/>
-    <numGlyphs value="29"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="4"/>
-    <xAvgCharWidth value="456"/>
-    <usWeightClass value="400"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00000000"/>
-    <ySubscriptXSize value="650"/>
-    <ySubscriptYSize value="600"/>
-    <ySubscriptXOffset value="0"/>
-    <ySubscriptYOffset value="75"/>
-    <ySuperscriptXSize value="650"/>
-    <ySuperscriptYSize value="600"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="350"/>
-    <yStrikeoutSize value="50"/>
-    <yStrikeoutPosition value="260"/>
-    <sFamilyClass value="0"/>
-    <panose>
-      <bFamilyType value="0"/>
-      <bSerifStyle value="0"/>
-      <bWeight value="5"/>
-      <bProportion value="0"/>
-      <bContrast value="0"/>
-      <bStrokeVariation value="0"/>
-      <bArmStyle value="0"/>
-      <bLetterForm value="0"/>
-      <bMidline value="0"/>
-      <bXHeight value="0"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00100000 00000001"/>
-    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="ALIF"/>
-    <fsSelection value="00000000 11000000"/>
-    <usFirstCharIndex value="105"/>
-    <usLastCharIndex value="1785"/>
-    <sTypoAscender value="1124"/>
-    <sTypoDescender value="-634"/>
-    <sTypoLineGap value="0"/>
-    <usWinAscent value="1814"/>
-    <usWinDescent value="897"/>
-    <ulCodePageRange1 value="00000000 00000000 00000000 11010011"/>
-    <ulCodePageRange2 value="00000000 00001000 00000000 00000000"/>
-    <sxHeight value="433"/>
-    <sCapHeight value="646"/>
-    <usDefaultChar value="0"/>
-    <usBreakChar value="32"/>
-    <usMaxContext value="8"/>
-  </OS_2>
-
-  <name>
-    <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
-      Copyright 2010-2020 The Amiri Project Authors (https://github.com/alif-type/amiri).
-    </namerecord>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      Amiri
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      0.114;ALIF;Amiri-Regular
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      Amiri Regular
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version 0.114
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      Amiri-Regular
-    </namerecord>
-  </name>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_4 platformID="0" platEncID="3" language="0">
-      <map code="0x69" name="i"/><!-- LATIN SMALL LETTER I -->
-      <map code="0x6f0" name="uni06F0"/><!-- EXTENDED ARABIC-INDIC DIGIT ZERO -->
-      <map code="0x6f1" name="uni06F1"/><!-- EXTENDED ARABIC-INDIC DIGIT ONE -->
-      <map code="0x6f2" name="uni06F2"/><!-- EXTENDED ARABIC-INDIC DIGIT TWO -->
-      <map code="0x6f3" name="uni06F3"/><!-- EXTENDED ARABIC-INDIC DIGIT THREE -->
-      <map code="0x6f4" name="uni06F4"/><!-- EXTENDED ARABIC-INDIC DIGIT FOUR -->
-      <map code="0x6f5" name="uni06F5"/><!-- EXTENDED ARABIC-INDIC DIGIT FIVE -->
-      <map code="0x6f6" name="uni06F6"/><!-- EXTENDED ARABIC-INDIC DIGIT SIX -->
-      <map code="0x6f7" name="uni06F7"/><!-- EXTENDED ARABIC-INDIC DIGIT SEVEN -->
-      <map code="0x6f8" name="uni06F8"/><!-- EXTENDED ARABIC-INDIC DIGIT EIGHT -->
-      <map code="0x6f9" name="uni06F9"/><!-- EXTENDED ARABIC-INDIC DIGIT NINE -->
-    </cmap_format_4>
-    <cmap_format_12 platformID="0" platEncID="4" format="12" reserved="0" length="40" language="0" nGroups="2">
-      <map code="0x69" name="i"/><!-- LATIN SMALL LETTER I -->
-      <map code="0x6f0" name="uni06F0"/><!-- EXTENDED ARABIC-INDIC DIGIT ZERO -->
-      <map code="0x6f1" name="uni06F1"/><!-- EXTENDED ARABIC-INDIC DIGIT ONE -->
-      <map code="0x6f2" name="uni06F2"/><!-- EXTENDED ARABIC-INDIC DIGIT TWO -->
-      <map code="0x6f3" name="uni06F3"/><!-- EXTENDED ARABIC-INDIC DIGIT THREE -->
-      <map code="0x6f4" name="uni06F4"/><!-- EXTENDED ARABIC-INDIC DIGIT FOUR -->
-      <map code="0x6f5" name="uni06F5"/><!-- EXTENDED ARABIC-INDIC DIGIT FIVE -->
-      <map code="0x6f6" name="uni06F6"/><!-- EXTENDED ARABIC-INDIC DIGIT SIX -->
-      <map code="0x6f7" name="uni06F7"/><!-- EXTENDED ARABIC-INDIC DIGIT SEVEN -->
-      <map code="0x6f8" name="uni06F8"/><!-- EXTENDED ARABIC-INDIC DIGIT EIGHT -->
-      <map code="0x6f9" name="uni06F9"/><!-- EXTENDED ARABIC-INDIC DIGIT NINE -->
-    </cmap_format_12>
-    <cmap_format_4 platformID="3" platEncID="1" language="0">
-      <map code="0x69" name="i"/><!-- LATIN SMALL LETTER I -->
-      <map code="0x6f0" name="uni06F0"/><!-- EXTENDED ARABIC-INDIC DIGIT ZERO -->
-      <map code="0x6f1" name="uni06F1"/><!-- EXTENDED ARABIC-INDIC DIGIT ONE -->
-      <map code="0x6f2" name="uni06F2"/><!-- EXTENDED ARABIC-INDIC DIGIT TWO -->
-      <map code="0x6f3" name="uni06F3"/><!-- EXTENDED ARABIC-INDIC DIGIT THREE -->
-      <map code="0x6f4" name="uni06F4"/><!-- EXTENDED ARABIC-INDIC DIGIT FOUR -->
-      <map code="0x6f5" name="uni06F5"/><!-- EXTENDED ARABIC-INDIC DIGIT FIVE -->
-      <map code="0x6f6" name="uni06F6"/><!-- EXTENDED ARABIC-INDIC DIGIT SIX -->
-      <map code="0x6f7" name="uni06F7"/><!-- EXTENDED ARABIC-INDIC DIGIT SEVEN -->
-      <map code="0x6f8" name="uni06F8"/><!-- EXTENDED ARABIC-INDIC DIGIT EIGHT -->
-      <map code="0x6f9" name="uni06F9"/><!-- EXTENDED ARABIC-INDIC DIGIT NINE -->
-    </cmap_format_4>
-    <cmap_format_12 platformID="3" platEncID="10" format="12" reserved="0" length="40" language="0" nGroups="2">
-      <map code="0x69" name="i"/><!-- LATIN SMALL LETTER I -->
-      <map code="0x6f0" name="uni06F0"/><!-- EXTENDED ARABIC-INDIC DIGIT ZERO -->
-      <map code="0x6f1" name="uni06F1"/><!-- EXTENDED ARABIC-INDIC DIGIT ONE -->
-      <map code="0x6f2" name="uni06F2"/><!-- EXTENDED ARABIC-INDIC DIGIT TWO -->
-      <map code="0x6f3" name="uni06F3"/><!-- EXTENDED ARABIC-INDIC DIGIT THREE -->
-      <map code="0x6f4" name="uni06F4"/><!-- EXTENDED ARABIC-INDIC DIGIT FOUR -->
-      <map code="0x6f5" name="uni06F5"/><!-- EXTENDED ARABIC-INDIC DIGIT FIVE -->
-      <map code="0x6f6" name="uni06F6"/><!-- EXTENDED ARABIC-INDIC DIGIT SIX -->
-      <map code="0x6f7" name="uni06F7"/><!-- EXTENDED ARABIC-INDIC DIGIT SEVEN -->
-      <map code="0x6f8" name="uni06F8"/><!-- EXTENDED ARABIC-INDIC DIGIT EIGHT -->
-      <map code="0x6f9" name="uni06F9"/><!-- EXTENDED ARABIC-INDIC DIGIT NINE -->
-    </cmap_format_12>
-  </cmap>
-
-  <post>
-    <formatType value="3.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-512"/>
-    <underlineThickness value="50"/>
-    <isFixedPitch value="0"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="0"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="0"/>
-  </post>
-
-  <CFF>
-    <major value="1"/>
-    <minor value="0"/>
-    <CFFFont name="Amiri-Regular">
-      <version value="0.114"/>
-      <Copyright value="Copyright 2010-2020 The Amiri Project Authors https:github.comalif-typeamiri."/>
-      <FullName value="Amiri"/>
-      <FamilyName value="Amiri"/>
-      <Weight value="Regular"/>
-      <isFixedPitch value="0"/>
-      <ItalicAngle value="0"/>
-      <UnderlinePosition value="-512"/>
-      <UnderlineThickness value="50"/>
-      <PaintType value="0"/>
-      <CharstringType value="2"/>
-      <FontMatrix value="0.001 0 0 0.001 0 0"/>
-      <FontBBox value="-581 -898 11462 1814"/>
-      <StrokeWidth value="0"/>
-      <!-- charset is dumped separately as the 'GlyphOrder' element -->
-      <Encoding name="StandardEncoding"/>
-      <Private>
-        <BlueScale value="0.039625"/>
-        <BlueShift value="7"/>
-        <BlueFuzz value="1"/>
-        <ForceBold value="0"/>
-        <LanguageGroup value="0"/>
-        <ExpansionFactor value="0.06"/>
-        <initialRandomSeed value="0"/>
-        <defaultWidthX value="0"/>
-        <nominalWidthX value="253"/>
-        <Subrs>
-          <!-- The 'index' attribute is only for humans; it is ignored when parsed. -->
-          <CharString index="0">
-            3 2 3 1 vhcurveto
-            endchar
-          </CharString>
-          <CharString index="1">
-            177 113 -106 callgsubr
-            return
-          </CharString>
-          <CharString index="2">
-            487 531 rmoveto
-            -5 -82 -21 -36 -38 10 -36 10 -16 18 5 25 5 25 1 18 -2 8 -2 8 -5 5 -8 1 -8 1 -4 -7 -3 -13 -14 -69 -26 -36 -40 -4 -29 -3 -23 4 -19 11 rrcurveto
-            -8 5 -24 31 -39 57 -17 26 -12 0 -6 -23 -25 -101 rcurveline
-            -3 -13 5 -16 14 -20 79 -117 45 -148 11 -178 1 -8 2 -6 4 -3 4 -3 4 0 6 2 6 2 3 4 2 7 20 79 -11 123 -42 169 39 -3 35 16 32 35 rrcurveto
-            14 -11 17 -9 20 -6 63 -20 40 23 18 65 13 49 7 46 2 41 rrcurveto
-            20 1 -6 9 -10 hhcurveto
-            -10 -5 -6 -12 -1 hvcurveto
-            endchar
-          </CharString>
-          <CharString index="3">
-            rmoveto
-            -45 13 -33 20 -23 28 -3 4 0 3 3 3 27 30 33 15 38 -1 rrcurveto
-            28 20 -8 -13 13 hvcurveto
-            5 -5 3 0 4 2 3 1 0 3 -1 6 -6 13 -11 16 -15 16 rrcurveto
-            14 -13 -14 7 -14 hhcurveto
-            -30 -33 -21 -43 -37 hvcurveto
-            -15 -19 -12 -20 -7 -23 -3 -7 1 -9 3 -8 11 -25 31 -23 53 -19 -51 -45 -38 -53 -24 -60 -5 -12 -1 -6 5 -1 6 -3 7 4 7 10 26 40 32 36 34 30 rrcurveto
-            37 33 37 24 37 16 10 4 7 8 4 13 16 50 rcurveline
-            4 10 -5 3 -12 -4 -18 -7 -23 -14 -28 -22 -7 -5 -9 -2 -9 3 rrcurveto
-            endchar
-          </CharString>
-          <CharString index="4">
-            311 -77 rmoveto
-            21 89 26 81 29 73 29 73 39 74 45 76 rrcurveto
-            6 11 2 9 8 vvcurveto
-            -6 97 rlineto
-            9 -1 -2 4 -5 hhcurveto
-            -5 -5 -6 -10 -5 hvcurveto
-            -79 -149 -53 -135 -27 -121 -4 -19 -7 2 -7 21 -55 159 -61 140 -70 124 -11 20 -8 -8 -5 -35 -13 -81 rcurveline
-            -2 -10 1 -8 3 -6 57 -95 46 -93 38 -90 38 -90 20 -68 2 -45 rrcurveto
-            -7 3 -4 4 -3 vhcurveto
-            4 -3 4 0 5 2 5 2 2 5 2 7 rrcurveto
-            endchar
-          </CharString>
-          <CharString index="5">
-            rmoveto
-            19 69 -12 87 -41 106 -10 24 -4 14 2 3 rrcurveto
-            10 10 11 5 12 hhcurveto
-            31 25 -26 -51 20 hvcurveto
-            2 -3 1 -2 3 -1 rrcurveto
-            2 2 1 3 2 hvcurveto
-            12 34 21 34 28 35 2 2 2 4 1 4 14 51 rcurveline
-            3 0 2 -3 1 vhcurveto
-            -3 1 -2 -1 -4 -3 -24 -22 -21 -32 -16 -43 -22 49 -28 24 -36 -2 -32 -1 -21 -19 -12 -38 -12 -39 2 -39 13 -38 29 -80 17 -68 4 -55 rrcurveto
-            -6 3 -2 4 5 -107 callsubr
-          </CharString>
-          <CharString index="6">
-            158 296 -95 callgsubr
-          </CharString>
-          <CharString index="7">
-            136 657 rmoveto
-            -13 -53 -16 -49 -17 -44 -18 -43 -22 -44 -27 -46 rrcurveto
-            -4 -6 -1 -6 -5 vvcurveto
-            3 -58 rlineto
-            -6 2 -2 3 3 3 3 6 3 vhcurveto
-            48 90 31 81 17 72 2 12 4 -1 4 -13 33 -95 37 -84 42 -75 7 -12 4 5 3 21 8 49 rcurveline
-            1 6 0 4 -2 4 -34 57 -28 56 -23 54 -22 54 -12 41 -2 27 rrcurveto
-            4 -1 3 -3 2 vhcurveto
-            -2 1 -3 0 -3 -1 -3 -1 -1 -4 -1 -4 rrcurveto
-            endchar
-          </CharString>
-          <CharString index="8">
-            220 500 rmoveto
-            -67 -86 -32 -66 2 -47 4 -86 75 -35 146 14 5 -82 22 -87 39 -91 15 -35 9 -2 6 33 18 105 rcurveline
-            3 15 -3 16 -10 18 -32 59 -18 73 -3 86 -3 87 -16 66 -32 45 -39 56 -43 0 -46 -56 rrcurveto
-            102 -152 rmoveto
-            6 -19 -1 -13 -6 -6 rrcurveto
-            -2 -3 -3 -2 -5 hhcurveto
-            -50 -3 -36 6 -22 14 -16 10 -5 16 7 21 12 39 24 15 36 -10 30 -9 21 -22 11 -35 rrcurveto
-            endchar
-          </CharString>
-          <CharString index="9">
-            53 654 -94 callgsubr
-          </CharString>
-          <CharString index="10">
-            38 655 -88 callgsubr
-          </CharString>
-          <CharString index="11">
-            hhcurveto
-            54 3 49 -4 45 -12 5 -1 4 0 2 1 54 31 rcurveline
-            10 6 0 4 -10 3 -61 14 -61 3 -60 -9 57 83 42 104 25 126 1 7 0 5 -2 2 -2 2 -3 -1 -4 -4 -40 -41 rcurveline
-            -4 -3 -3 -6 -1 -7 -25 -113 -35 -98 -45 -84 rrcurveto
-            endchar
-          </CharString>
-          <CharString index="12">
-            119 655 -85 callgsubr
-          </CharString>
-          <CharString index="13">
-            4 -4 5 0 6 2 6 2 3 5 1 7 20 return
-          </CharString>
-          <CharString index="14">
-            -3 -13 4 -15 12 -19 return
-          </CharString>
-        </Subrs>
-      </Private>
-      <CharStrings>
-        <CharString name=".notdef">
-          111 endchar
-        </CharString>
-        <CharString name="i">
-          10 -106 callsubr
-          -94 466 -80 callgsubr
-        </CharString>
-        <CharString name="i.TRK">
-          10 -106 callsubr
-          -94 466 -80 callgsubr
-        </CharString>
-        <CharString name="uni06F0">
-          332 -84 callgsubr
-        </CharString>
-        <CharString name="uni06F0.numr">
-          39 -82 callgsubr
-        </CharString>
-        <CharString name="uni06F1">
-          332 -87 callgsubr
-        </CharString>
-        <CharString name="uni06F1.numr">
-          39 -95 callsubr
-        </CharString>
-        <CharString name="uni06F2">
-          332 -97 callgsubr
-        </CharString>
-        <CharString name="uni06F2.numr">
-          39 -98 callsubr
-        </CharString>
-        <CharString name="uni06F3">
-          332 -105 callsubr
-        </CharString>
-        <CharString name="uni06F3.numr">
-          39 263 662 -107 callgsubr
-        </CharString>
-        <CharString name="uni06F4">
-          332 175 515 rmoveto
-          -12 19 -10 8 -7 -1 -4 -2 -4 -5 -2 -10 -25 -105 rcurveline
-          -93 callsubr
-          83 -128 46 -149 7 -168 rrcurveto
-          -7 3 -5 4 -4 vhcurveto
-          -94 callsubr
-          98 -4 110 -26 122 26 -13 33 -5 38 3 63 5 49 28 34 54 9 14 1 10 -7 7 -6 5 -9 -3 -13 -11 rrcurveto
-          -21 -18 -39 -7 -56 3 -38 2 -39 18 -40 34 20 66 50 34 83 1 rrcurveto
-          26 35 -15 -31 42 hvcurveto
-          10 -7 6 0 5 7 3 5 -2 9 -7 14 -35 66 -40 33 -44 -3 -76 -5 -57 -50 -40 -93 -4 -11 -5 0 -5 11 -11 28 -19 35 -27 42 rrcurveto
-          endchar
-        </CharString>
-        <CharString name="uni06F4.numr">
-          39 76 651 rmoveto
-          -12 19 -8 1 -3 -15 -15 -63 rcurveline
-          -2 -7 2 -9 7 -12 50 -77 28 -89 4 -101 rrcurveto
-          -4 2 -3 2 -2 vhcurveto
-          3 -3 3 0 3 1 rrcurveto
-          4 2 2 3 4 vvcurveto
-          12 59 -2 66 -16 73 16 -8 20 -3 22 2 38 3 30 17 20 32 5 8 1 6 -4 5 -4 3 -5 -2 -8 -7 -13 -11 -23 -4 -34 2 -22 1 -24 11 -24 20 rrcurveto
-          12 40 30 20 50 1 rrcurveto
-          16 21 -9 -19 25 hvcurveto
-          6 -4 3 0 3 4 2 3 -1 6 -4 8 -21 40 -24 20 -27 -2 -45 -3 -34 -30 -24 -56 -3 -7 -3 0 -3 7 -6 17 -12 21 -16 25 rrcurveto
-          endchar
-        </CharString>
-        <CharString name="uni06F4.urd">
-          332 229 -83 rmoveto
-          31 115 -20 145 -69 177 -16 40 -6 23 3 4 rrcurveto
-          18 16 19 8 19 hhcurveto
-          52 -1 42 -43 34 -84 2 -6 3 -3 5 -1 3 -1 3 2 3 5 21 57 34 57 47 57 3 4 3 6 2 7 23 85 rcurveline
-          1 6 -1 3 -5 2 -4 1 -4 -2 -6 -5 -41 -36 -34 -53 -27 -73 -36 82 -48 40 -59 -3 -53 -2 -36 -32 -19 -62 -20 -65 2 -65 22 -64 49 -133 28 -114 6 -92 rrcurveto
-          -9 1 4 -4 8 hhcurveto
-          8 5 3 6 2 hvcurveto
-          endchar
-        </CharString>
-        <CharString name="uni06F4.urd.numr">
-          39 108 303 -102 callsubr
-        </CharString>
-        <CharString name="uni06F5">
-          332 235 526 rmoveto
-          -12 12 -8 -2 -2 -16 -17 -121 rcurveline
-          -2 -15 3 -8 7 -4 8 -4 8 -5 7 -5 -75 -103 -42 -88 -8 -76 -11 -105 29 -55 68 -6 39 -3 34 17 31 36 16 -26 28 -10 40 7 54 9 33 60 13 110 rrcurveto
-          5 39 -17 59 -39 78 -29 58 -63 75 -98 92 rrcurveto
-          16 -184 rmoveto
-          76 -52 58 -68 42 -83 6 -12 2 -10 -4 -10 -10 -27 -17 -15 -23 -3 -17 -2 -14 3 -12 8 -1 7 1 6 3 5 -1 6 -3 4 -4 2 -5 2 -5 -3 -6 -6 rrcurveto
-          -64 -62 -52 -8 -40 45 -20 23 2 44 25 64 15 38 27 48 41 56 rrcurveto
-          endchar
-        </CharString>
-        <CharString name="uni06F5.numr">
-          39 112 656 -99 callgsubr
-        </CharString>
-        <CharString name="uni06F6">
-          332 331 285 rmoveto
-          -74 21 -56 34 -37 47 -5 6 0 5 5 5 45 50 54 25 63 -1 47 -1 34 -12 22 -23 7 -7 6 -1 6 3 5 3 1 5 -3 9 -9 22 -18 26 -26 28 rrcurveto
-          23 -22 -22 11 -24 hhcurveto
-          -50 -55 -35 -72 -61 hvcurveto
-          -26 -31 -20 -33 -12 -38 -4 -13 1 -14 5 -13 18 -43 52 -37 88 -32 -85 -75 -62 -88 -41 -100 -8 -20 -1 -10 8 -3 10 -4 12 7 11 16 44 66 52 60 58 51 rrcurveto
-          61 54 61 41 62 26 17 7 12 14 7 21 26 83 rcurveline
-          6 17 -8 5 -20 -7 -30 -11 -38 -24 -47 -36 -12 -9 -14 -3 -16 5 rrcurveto
-          endchar
-        </CharString>
-        <CharString name="uni06F6.numr">
-          39 170 512 -104 callsubr
-        </CharString>
-        <CharString name="uni06F6.urd">
-          332 -90 callgsubr
-        </CharString>
-        <CharString name="uni06F6.urd.numr">
-          39 -97 callsubr
-        </CharString>
-        <CharString name="uni06F7">
-          332 -103 callsubr
-        </CharString>
-        <CharString name="uni06F7.numr">
-          39 -101 callsubr
-        </CharString>
-        <CharString name="uni06F7.urd">
-          332 104 -50 rmoveto
-          -3 -6 -1 -5 2 -3 2 -3 4 -2 8 1 90 5 83 -7 75 -20 8 -2 6 0 4 2 89 51 rcurveline
-          18 10 0 8 -18 4 -101 23 -101 5 -100 -15 95 139 69 174 42 210 2 11 0 8 -3 3 -4 4 -5 -2 -6 -6 -68 -68 rcurveline
-          -6 -6 -5 -10 -2 -12 -42 -188 -58 -163 -74 -140 rrcurveto
-          endchar
-        </CharString>
-        <CharString name="uni06F7.urd.numr">
-          39 33 312 rmoveto
-          -8 -4 3 -3 9 -96 callsubr
-        </CharString>
-        <CharString name="uni06F8">
-          332 -98 callgsubr
-        </CharString>
-        <CharString name="uni06F8.numr">
-          39 -100 callsubr
-        </CharString>
-        <CharString name="uni06F9">
-          332 -99 callsubr
-        </CharString>
-        <CharString name="uni06F9.numr">
-          39 -93 callgsubr
-        </CharString>
-      </CharStrings>
-    </CFFFont>
-
-    <GlobalSubrs>
-      <!-- The 'index' attribute is only for humans; it is ignored when parsed. -->
-      <CharString index="0">
-        rmoveto
-        -3 -50 -12 -21 -23 6 -22 6 -9 11 3 15 3 15 0 10 -1 5 -1 5 -3 3 -5 1 rrcurveto
-        -5 -2 -4 -8 -2 hvcurveto
-        -8 -41 -16 -22 -24 -2 -17 -2 -14 2 -12 7 -4 3 -15 19 -23 34 -10 15 -8 0 -3 -13 -15 -61 rcurveline
-        -2 -8 3 -9 8 -12 48 -71 27 -88 6 -107 1 -5 1 -4 3 -1 2 -2 2 0 4 1 4 1 1 3 2 4 12 47 -7 74 -25 101 23 -1 21 9 19 21 rrcurveto
-        9 -6 10 -6 12 -3 38 -12 24 13 11 39 7 30 5 27 1 25 rrcurveto
-        12 -3 5 -6 -6 -3 -3 -7 -1 vhcurveto
-        endchar
-      </CharString>
-      <CharString index="1">
-        rmoveto
-        237 vlineto
-        -92 callgsubr
-        return
-      </CharString>
-      <CharString index="2">
-        vlineto
-        -29 0 -27 -5 -16 -102 callgsubr
-        -46 -77 callgsubr
-        vvcurveto
-        return
-      </CharString>
-      <CharString index="3">
-        rmoveto
-        -100 callgsubr
-        return
-      </CharString>
-      <CharString index="4">
-        -81 callgsubr
-        49 0 -17 7 hvcurveto
-        5 -12 0 return
-      </CharString>
-      <CharString index="5">
-        vhcurveto
-        -11 -3 -47 -74 callgsubr
-        26 -79 callgsubr
-        26 -78 callgsubr
-        return
-      </CharString>
-      <CharString index="6">
-        5 5 -1 18 -4 5 rrcurveto
-        -12 return
-      </CharString>
-      <CharString index="7">
-        -27 22 -22 27 27 22 22 27 27 -22 22 -27 -27 -22 -22 -27 vhcurveto
-        return
-      </CharString>
-      <CharString index="8">
-        rmoveto
-        -7 7 -5 -1 -1 -10 -10 -73 rcurveline
-        -2 -9 2 -4 4 -3 5 -2 5 -3 4 -3 -45 -62 -25 -53 -5 -45 -6 -63 17 -33 41 -4 23 -2 21 10 18 22 10 -16 17 -6 24 5 32 5 20 36 8 66 rrcurveto
-        3 23 -11 36 -23 47 -17 34 -38 45 -59 56 rrcurveto
-        10 -111 rmoveto
-        45 -31 35 -41 25 -50 4 -7 1 -6 -2 -6 -6 -16 -11 -9 -13 -2 -11 -1 -8 2 -7 5 -1 4 1 3 2 3 -1 4 -2 2 -2 2 -3 1 -3 -2 -4 -4 rrcurveto
-        -38 -37 -31 -5 -24 27 -12 14 1 27 15 38 9 23 16 29 25 33 rrcurveto
-        endchar
-      </CharString>
-      <CharString index="9">
-        275 527 rmoveto
-        -21 -89 -27 -81 -29 -73 -29 -73 -38 -73 -45 -76 rrcurveto
-        -6 -11 -2 -10 -8 vvcurveto
-        5 -97 rlineto
-        -9 1 3 -3 5 hhcurveto
-        5 5 5 10 5 hvcurveto
-        79 149 53 135 27 121 4 19 7 -2 7 -21 55 -159 61 -140 70 -124 11 -20 8 8 5 35 13 81 rcurveline
-        2 10 -1 8 -3 6 -57 95 -46 93 -38 90 -38 90 -20 68 -2 45 rrcurveto
-        7 -3 5 -4 3 vhcurveto
-        -4 3 -4 0 -5 -2 -5 -2 -2 -6 -2 -7 rrcurveto
-        endchar
-      </CharString>
-      <CharString index="10">
-        137 -96 callgsubr
-      </CharString>
-      <CharString index="11">
-        521 rmoveto
-        -25 -102 -3 -13 4 -15 12 -19 rlinecurve
-        79 -124 46 -149 11 -172 1 -7 2 -5 4 -4 4 -4 5 0 6 2 6 2 3 5 1 7 20 99 -12 128 -42 158 79 -13 57 18 33 49 21 30 13 33 6 37 rrcurveto
-        6 37 3 24 -3 7 rrcurveto
-        7 -3 -6 4 -9 hhcurveto
-        -9 -6 -6 -12 -2 hvcurveto
-        -69 -9 -43 -36 -79 hhcurveto
-        -55 -44 32 62 -33 hvcurveto
-        -11 21 -9 10 -7 -2 -5 -1 -4 -6 -3 -13 rrcurveto
-        endchar
-      </CharString>
-      <CharString index="12">
-        rmoveto
-        12 53 16 49 17 44 18 43 23 45 27 45 rrcurveto
-        4 7 1 5 5 vvcurveto
-        -4 58 rlineto
-        6 -2 2 -3 -3 -3 -3 -6 -3 vhcurveto
-        -47 -90 -32 -81 -16 -72 -2 -12 -5 1 -4 13 -33 95 -36 84 -42 75 -7 12 -5 -5 -3 -21 -8 -49 rcurveline
-        -1 -6 1 -4 2 -4 34 -57 27 -56 23 -54 23 -54 12 -41 1 -27 rrcurveto
-        -4 2 -2 2 -2 vhcurveto
-        3 -2 2 0 3 1 3 2 1 3 2 4 rrcurveto
-        endchar
-      </CharString>
-      <CharString index="13">
-        rmoveto
-        -15 -62 -2 -7 3 -9 7 -12 rlinecurve
-        47 -74 28 -90 7 -103 rrcurveto
-        -4 1 -3 3 -2 vhcurveto
-        2 -3 3 0 4 1 3 2 2 3 1 4 12 59 -7 77 -26 95 48 -8 34 11 20 29 12 18 8 20 4 22 3 22 2 15 -2 4 rrcurveto
-        4 -1 -4 3 -5 hhcurveto
-        -6 -3 -4 -7 -2 hvcurveto
-        -42 -5 -26 -21 -47 hhcurveto
-        -33 -27 19 37 -19 hvcurveto
-        -7 13 -5 6 -5 -1 -3 -1 -2 -4 -2 -7 rrcurveto
-        endchar
-      </CharString>
-      <CharString index="14">
-        103 641 -91 callgsubr
-      </CharString>
-      <CharString index="15">
-        10 6 47 1 7 vhcurveto
-        5 -6 11 -5 vhcurveto
-        -39 -21 -50 -103 callgsubr
-        -26 -13 vvcurveto
-        -182 -105 callgsubr
-        return
-      </CharString>
-      <CharString index="16">
-        rmoveto
-        -40 -52 -19 -39 1 -28 2 -52 45 -21 88 8 3 -49 13 -52 23 -55 9 -21 6 -1 3 20 11 63 rcurveline
-        2 9 -2 10 -6 10 -19 36 -11 44 -2 51 -1 52 -10 40 -19 27 -24 34 -25 0 -28 -34 rrcurveto
-        61 -91 rmoveto
-        -16 5 -2 -9 -10 hhcurveto
-        -30 -2 -22 3 -13 9 -9 6 -3 9 4 13 7 23 14 9 22 -6 18 -5 13 -13 6 -21 rrcurveto
-        endchar
-      </CharString>
-      <CharString index="17">
-        111 -89 callgsubr
-      </CharString>
-      <CharString index="18">
-        522 rmoveto
-        -15 -79 -3 -13 4 -12 9 -10 rlinecurve
-        50 -56 78 -14 105 27 rrcurveto
-        1 1 0 0 hvcurveto
-        3 -1 1 -4 -7 vvcurveto
-        -5 -150 31 -142 70 -132 15 -29 11 3 6 32 17 95 rcurveline
-        3 17 -4 18 -9 17 -71 128 -29 128 13 130 2 16 -8 6 -18 -5 -109 -33 -75 12 -38 57 -19 28 -12 0 -5 -27 rrcurveto
-        endchar
-      </CharString>
-      <CharString index="19">
-        rmoveto
-        -9 -47 -2 -8 2 -7 6 -6 rlinecurve
-        30 -34 46 -8 63 16 rrcurveto
-        3 1 1 -3 -5 vvcurveto
-        -3 -90 19 -85 42 -80 9 -17 6 2 4 19 10 57 rcurveline
-        2 10 -3 11 -5 10 -43 77 -17 77 8 78 1 9 -5 4 -11 -3 -65 -20 -45 7 -23 35 -11 16 -7 0 -3 -16 rrcurveto
-        endchar
-      </CharString>
-      <CharString index="20">
-        246 -86 callgsubr
-      </CharString>
-      <CharString index="21">
-        524 rmoveto
-        -34 -100 -5 -14 3 -17 11 -20 rlinecurve
-        71 -126 35 -148 -2 -171 rrcurveto
-        -12 4 -6 9 -2 vhcurveto
-        9 -2 5 5 4 10 23 69 4 99 -18 129 -13 92 -27 96 -39 100 -17 40 -14 6 -9 -28 rrcurveto
-        endchar
-      </CharString>
-      <CharString index="22">
-        rmoveto
-        -21 -60 -3 -8 2 -10 7 -12 rlinecurve
-        42 -76 21 -89 -1 -102 rrcurveto
-        -7 2 -4 6 -1 vhcurveto
-        5 -1 3 3 3 6 13 41 3 59 -11 78 -8 55 -16 58 -23 60 -11 24 -8 3 -5 -17 rrcurveto
-        endchar
-      </CharString>
-      <CharString index="23">
-        251 -83 callgsubr
-      </CharString>
-      <CharString index="24">
-        312 rmoveto
-        -38 -106 -5 -15 1 -10 8 -5 rlinecurve
-        91 -53 17 -10 11 2 6 17 rlinecurve
-        32 99 5 15 -3 11 -12 8 rlinecurve
-        -83 53 -9 6 -7 2 -5 -3 rlinecurve
-        -4 -1 -3 -4 -2 -6 rrcurveto
-        endchar
-      </CharString>
-      <CharString index="25">
-        122 527 rmoveto
-        -23 -63 -3 -9 0 -6 5 -3 rlinecurve
-        55 -32 10 -6 7 1 3 10 rlinecurve
-        19 60 3 9 -1 6 -8 5 rlinecurve
-        -49 32 -9 6 -6 -1 -3 -9 rlinecurve
-        endchar
-      </CharString>
-      <CharString index="26">
-        -13 -50 -7 -4 -5 2 -19 2 -2 rrcurveto
-        7 return
-      </CharString>
-      <CharString index="27">
-        -104 callgsubr
-        endchar
-      </CharString>
-      <CharString index="28">
-        3 38 hhcurveto
-        38 return
-      </CharString>
-      <CharString index="29">
-        -3 -2 40 hvcurveto
-        -101 callgsubr
-        return
-      </CharString>
-      <CharString index="30">
-        5 11 -3 hvcurveto
-        -5 16 0 27 29 return
-      </CharString>
-      <CharString index="31">
-        5 -5 rrcurveto
-        2 40 return
-      </CharString>
-      <CharString index="32">
-        -5 -12 hhcurveto
-        -4 -5 -1 return
-      </CharString>
-      <CharString index="33">
-        -75 callgsubr
-        -18 -76 callgsubr
-        return
-      </CharString>
-    </GlobalSubrs>
-  </CFF>
-
-  <GDEF>
-    <Version value="0x00010000"/>
-    <GlyphClassDef>
-      <ClassDef glyph="i" class="1"/>
-      <ClassDef glyph="i.TRK" class="1"/>
-      <ClassDef glyph="uni06F0" class="1"/>
-      <ClassDef glyph="uni06F0.numr" class="1"/>
-      <ClassDef glyph="uni06F1" class="1"/>
-      <ClassDef glyph="uni06F1.numr" class="1"/>
-      <ClassDef glyph="uni06F2" class="1"/>
-      <ClassDef glyph="uni06F2.numr" class="1"/>
-      <ClassDef glyph="uni06F3" class="1"/>
-      <ClassDef glyph="uni06F3.numr" class="1"/>
-      <ClassDef glyph="uni06F4" class="1"/>
-      <ClassDef glyph="uni06F4.numr" class="1"/>
-      <ClassDef glyph="uni06F4.urd" class="1"/>
-      <ClassDef glyph="uni06F4.urd.numr" class="1"/>
-      <ClassDef glyph="uni06F5" class="1"/>
-      <ClassDef glyph="uni06F5.numr" class="1"/>
-      <ClassDef glyph="uni06F6" class="1"/>
-      <ClassDef glyph="uni06F6.numr" class="1"/>
-      <ClassDef glyph="uni06F6.urd" class="1"/>
-      <ClassDef glyph="uni06F6.urd.numr" class="1"/>
-      <ClassDef glyph="uni06F7" class="1"/>
-      <ClassDef glyph="uni06F7.numr" class="1"/>
-      <ClassDef glyph="uni06F7.urd" class="1"/>
-      <ClassDef glyph="uni06F7.urd.numr" class="1"/>
-      <ClassDef glyph="uni06F8" class="1"/>
-      <ClassDef glyph="uni06F8.numr" class="1"/>
-      <ClassDef glyph="uni06F9" class="1"/>
-      <ClassDef glyph="uni06F9.numr" class="1"/>
-    </GlyphClassDef>
-  </GDEF>
-
-  <GPOS>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=0 -->
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=0 -->
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=0 -->
-    </LookupList>
-  </GPOS>
-
-  <GSUB>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=3 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="4"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-      <ScriptRecord index="1">
-        <ScriptTag value="arab"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="4"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=3 -->
-          <LangSysRecord index="0">
-            <LangSysTag value="KSH "/>
-            <LangSys>
-              <ReqFeatureIndex value="65535"/>
-              <!-- FeatureCount=2 -->
-              <FeatureIndex index="0" value="0"/>
-              <FeatureIndex index="1" value="4"/>
-            </LangSys>
-          </LangSysRecord>
-          <LangSysRecord index="1">
-            <LangSysTag value="SND "/>
-            <LangSys>
-              <ReqFeatureIndex value="65535"/>
-              <!-- FeatureCount=2 -->
-              <FeatureIndex index="0" value="1"/>
-              <FeatureIndex index="1" value="4"/>
-            </LangSys>
-          </LangSysRecord>
-          <LangSysRecord index="2">
-            <LangSysTag value="URD "/>
-            <LangSys>
-              <ReqFeatureIndex value="65535"/>
-              <!-- FeatureCount=2 -->
-              <FeatureIndex index="0" value="3"/>
-              <FeatureIndex index="1" value="4"/>
-            </LangSys>
-          </LangSysRecord>
-        </Script>
-      </ScriptRecord>
-      <ScriptRecord index="2">
-        <ScriptTag value="latn"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="4"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=1 -->
-          <LangSysRecord index="0">
-            <LangSysTag value="TRK "/>
-            <LangSys>
-              <ReqFeatureIndex value="65535"/>
-              <!-- FeatureCount=2 -->
-              <FeatureIndex index="0" value="2"/>
-              <FeatureIndex index="1" value="4"/>
-            </LangSys>
-          </LangSysRecord>
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=5 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="locl"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="1"/>
-        </Feature>
-      </FeatureRecord>
-      <FeatureRecord index="1">
-        <FeatureTag value="locl"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="2"/>
-        </Feature>
-      </FeatureRecord>
-      <FeatureRecord index="2">
-        <FeatureTag value="locl"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="4"/>
-        </Feature>
-      </FeatureRecord>
-      <FeatureRecord index="3">
-        <FeatureTag value="locl"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="0"/>
-        </Feature>
-      </FeatureRecord>
-      <FeatureRecord index="4">
-        <FeatureTag value="numr"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="3"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=5 -->
-      <Lookup index="0">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="uni06F4" out="uni06F4.urd"/>
-          <Substitution in="uni06F6" out="uni06F6.urd"/>
-          <Substitution in="uni06F7" out="uni06F7.urd"/>
-        </SingleSubst>
-      </Lookup>
-      <Lookup index="1">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="uni06F4" out="uni06F4.urd"/>
-          <Substitution in="uni06F6" out="uni06F6.urd"/>
-          <Substitution in="uni06F7" out="uni06F7.urd"/>
-        </SingleSubst>
-      </Lookup>
-      <Lookup index="2">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="uni06F6" out="uni06F6.urd"/>
-          <Substitution in="uni06F7" out="uni06F7.urd"/>
-        </SingleSubst>
-      </Lookup>
-      <Lookup index="3">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="uni06F0" out="uni06F0.numr"/>
-          <Substitution in="uni06F1" out="uni06F1.numr"/>
-          <Substitution in="uni06F2" out="uni06F2.numr"/>
-          <Substitution in="uni06F3" out="uni06F3.numr"/>
-          <Substitution in="uni06F4" out="uni06F4.numr"/>
-          <Substitution in="uni06F4.urd" out="uni06F4.urd.numr"/>
-          <Substitution in="uni06F5" out="uni06F5.numr"/>
-          <Substitution in="uni06F6" out="uni06F6.numr"/>
-          <Substitution in="uni06F6.urd" out="uni06F6.urd.numr"/>
-          <Substitution in="uni06F7" out="uni06F7.numr"/>
-          <Substitution in="uni06F7.urd" out="uni06F7.urd.numr"/>
-          <Substitution in="uni06F8" out="uni06F8.numr"/>
-          <Substitution in="uni06F9" out="uni06F9.numr"/>
-        </SingleSubst>
-      </Lookup>
-      <Lookup index="4">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="i" out="i.TRK"/>
-        </SingleSubst>
-      </Lookup>
-    </LookupList>
-  </GSUB>
-
-  <hmtx>
-    <mtx name=".notdef" width="364" lsb="33"/>
-    <mtx name="i" width="263" lsb="32"/>
-    <mtx name="i.TRK" width="263" lsb="32"/>
-    <mtx name="uni06F0" width="585" lsb="210"/>
-    <mtx name="uni06F0.numr" width="292" lsb="97"/>
-    <mtx name="uni06F1" width="585" lsb="210"/>
-    <mtx name="uni06F1.numr" width="292" lsb="97"/>
-    <mtx name="uni06F2" width="585" lsb="111"/>
-    <mtx name="uni06F2.numr" width="292" lsb="37"/>
-    <mtx name="uni06F3" width="585" lsb="67"/>
-    <mtx name="uni06F3.numr" width="292" lsb="11"/>
-    <mtx name="uni06F4" width="585" lsb="110"/>
-    <mtx name="uni06F4.numr" width="292" lsb="37"/>
-    <mtx name="uni06F4.urd" width="585" lsb="100"/>
-    <mtx name="uni06F4.urd.numr" width="292" lsb="31"/>
-    <mtx name="uni06F5" width="585" lsb="100"/>
-    <mtx name="uni06F5.numr" width="292" lsb="31"/>
-    <mtx name="uni06F6" width="585" lsb="71"/>
-    <mtx name="uni06F6.numr" width="292" lsb="14"/>
-    <mtx name="uni06F6.urd" width="585" lsb="95"/>
-    <mtx name="uni06F6.urd.numr" width="292" lsb="28"/>
-    <mtx name="uni06F7" width="585" lsb="78"/>
-    <mtx name="uni06F7.numr" width="292" lsb="18"/>
-    <mtx name="uni06F7.urd" width="585" lsb="101"/>
-    <mtx name="uni06F7.urd.numr" width="292" lsb="31"/>
-    <mtx name="uni06F8" width="585" lsb="78"/>
-    <mtx name="uni06F8.numr" width="292" lsb="18"/>
-    <mtx name="uni06F9" width="585" lsb="123"/>
-    <mtx name="uni06F9.numr" width="292" lsb="45"/>
-  </hmtx>
-
-</ttFont>
diff --git a/Tests/subset/data/test_cntrmask_CFF.ttx b/Tests/subset/data/test_cntrmask_CFF.ttx
index 9e7d205..5ab6268 100644
--- a/Tests/subset/data/test_cntrmask_CFF.ttx
+++ b/Tests/subset/data/test_cntrmask_CFF.ttx
@@ -237,13 +237,13 @@
 
   <GDEF>
     <Version value="0x00010002"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="1">
       <ClassDef glyph="Idieresis" class="1"/>
     </GlyphClassDef>
     <MarkGlyphSetsDef>
       <MarkSetTableFormat value="1"/>
       <!-- MarkSetCount=1 -->
-      <Coverage index="0">
+      <Coverage index="0" Format="1">
       </Coverage>
     </MarkGlyphSetsDef>
   </GDEF>
@@ -335,15 +335,15 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="Idieresis"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="1">
             <ClassDef glyph="Idieresis" class="1"/>
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="2">
           </ClassDef2>
           <!-- Class1Count=2 -->
           <!-- Class2Count=1 -->
diff --git a/Tests/subset/subset_test.py b/Tests/subset/subset_test.py
index 6fa1bf6..9495f32 100644
--- a/Tests/subset/subset_test.py
+++ b/Tests/subset/subset_test.py
@@ -1,11 +1,7 @@
-import io
-from fontTools.misc.py23 import tobytes, tostr
-from fontTools.misc.testTools import getXML
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools import subset
-from fontTools.fontBuilder import FontBuilder
-from fontTools.pens.ttGlyphPen import TTGlyphPen
 from fontTools.ttLib import TTFont, newTable
-from fontTools.ttLib.tables import otTables as ot
 from fontTools.misc.loggingTools import CapturingLogHandler
 import difflib
 import logging
@@ -14,8 +10,6 @@
 import sys
 import tempfile
 import unittest
-import pathlib
-import pytest
 
 
 class SubsetTest(unittest.TestCase):
@@ -58,7 +52,7 @@
                     lines.append(line.rstrip() + os.linesep)
         return lines
 
-    def expect_ttx(self, font, expected_ttx, tables=None):
+    def expect_ttx(self, font, expected_ttx, tables):
         path = self.temp_path(suffix=".ttx")
         font.saveXML(path, tables=tables)
         actual = self.read_ttx(path)
@@ -80,16 +74,6 @@
 # Tests
 # -----
 
-    def test_layout_scripts(self):
-        _, fontpath = self.compile_font(self.getpath("layout_scripts.ttx"), ".otf")
-        subsetpath = self.temp_path(".otf")
-        subset.main([fontpath, "--glyphs=*", "--layout-features=*",
-                     "--layout-scripts=latn,arab.URD,arab.dflt",
-                     "--output-file=%s" % subsetpath])
-        subsetfont = TTFont(subsetpath)
-        self.expect_ttx(subsetfont, self.getpath("expect_layout_scripts.ttx"),
-                        ["GPOS", "GSUB"])
-
     def test_no_notdef_outline_otf(self):
         _, fontpath = self.compile_font(self.getpath("TestOTF-Regular.ttx"), ".otf")
         subsetpath = self.temp_path(".otf")
@@ -744,475 +728,6 @@
 
         self.assertEqual(ttf.flavor, None)
 
-    def test_subset_context_subst_format_3(self):
-        # https://github.com/fonttools/fonttools/issues/1879
-        # Test font contains 'calt' feature with Format 3 ContextSubst lookup subtables
-        ttx = self.getpath("TestContextSubstFormat3.ttx")
-        font, fontpath = self.compile_font(ttx, ".ttf")
-        subsetpath = self.temp_path(".ttf")
-        subset.main([fontpath, "--unicodes=*", "--output-file=%s" % subsetpath])
-        subsetfont = TTFont(subsetpath)
-        # check all glyphs are kept via GSUB closure, no changes expected
-        self.expect_ttx(subsetfont, ttx)
-
-    def test_cmap_prune_format12(self):
-        _, fontpath = self.compile_font(self.getpath("CmapSubsetTest.ttx"), ".ttf")
-        subsetpath = self.temp_path(".ttf")
-        subset.main([fontpath, "--glyphs=a", "--output-file=%s" % subsetpath])
-        subsetfont = TTFont(subsetpath)
-        self.expect_ttx(subsetfont, self.getpath("CmapSubsetTest.subset.ttx"), ["cmap"])
-
-    def test_GPOS_PairPos_Format2_useClass0(self):
-        # Check two things related to class 0 ('every other glyph'):
-        # 1) that it's reused for ClassDef1 when it becomes empty as the subset glyphset
-        #    is intersected with the table's Coverage
-        # 2) that it is never reused for ClassDef2 even when it happens to become empty
-        #    because of the subset glyphset. In this case, we don't keep a PairPosClass2
-        #    subtable if only ClassDef2's class0 survived subsetting.
-        # The test font (from Harfbuzz test suite) is constructed to trigger these two
-        # situations depending on the input subset --text.
-        # https://github.com/fonttools/fonttools/pull/2221
-        _, fontpath = self.compile_font(
-            self.getpath("GPOS_PairPos_Format2_PR_2221.ttx"), ".ttf"
-        )
-        subsetpath = self.temp_path(".ttf")
-
-        for n, text in enumerate("!#", start=1):
-            expected_ttx = self.getpath(
-                f"GPOS_PairPos_Format2_ClassDef{n}_useClass0.subset.ttx"
-            )
-            with self.subTest(text=text, expected_ttx=expected_ttx):
-                subset.main(
-                    [
-                        fontpath,
-                        f"--text='{text}'",
-                        "--layout-features+=test",
-                        "--output-file=%s" % subsetpath,
-                    ]
-                )
-                subsetfont = TTFont(subsetpath)
-                self.expect_ttx(subsetfont, expected_ttx, ["GPOS"])
-
-
-@pytest.fixture
-def featureVarsTestFont():
-    fb = FontBuilder(unitsPerEm=100)
-    fb.setupGlyphOrder([".notdef", "f", "f_f", "dollar", "dollar.rvrn"])
-    fb.setupCharacterMap({ord("f"): "f", ord("$"): "dollar"})
-    fb.setupNameTable({"familyName": "TestFeatureVars", "styleName": "Regular"})
-    fb.setupPost()
-    fb.setupFvar(axes=[("wght", 100, 400, 900, "Weight")], instances=[])
-    fb.addOpenTypeFeatures("""\
-        feature dlig {
-            sub f f by f_f;
-        } dlig;
-    """)
-    fb.addFeatureVariations(
-        [([{"wght": (0.20886, 1.0)}], {"dollar": "dollar.rvrn"})],
-        featureTag="rvrn"
-    )
-    buf = io.BytesIO()
-    fb.save(buf)
-    buf.seek(0)
-
-    return TTFont(buf)
-
-
-def test_subset_feature_variations_keep_all(featureVarsTestFont):
-    font = featureVarsTestFont
-
-    options = subset.Options()
-    subsetter = subset.Subsetter(options)
-    subsetter.populate(unicodes=[ord("f"), ord("$")])
-    subsetter.subset(font)
-
-    featureTags = {
-        r.FeatureTag for r in font["GSUB"].table.FeatureList.FeatureRecord
-    }
-    # 'dlig' is discretionary so it is dropped by default
-    assert "dlig" not in featureTags
-    assert "f_f" not in font.getGlyphOrder()
-    # 'rvrn' is required so it is kept by default
-    assert "rvrn" in featureTags
-    assert "dollar.rvrn" in font.getGlyphOrder()
-
-
-def test_subset_feature_variations_drop_all(featureVarsTestFont):
-    font = featureVarsTestFont
-
-    options = subset.Options()
-    options.layout_features.remove("rvrn")  # drop 'rvrn'
-    subsetter = subset.Subsetter(options)
-    subsetter.populate(unicodes=[ord("f"), ord("$")])
-    subsetter.subset(font)
-
-    featureTags = {
-        r.FeatureTag for r in font["GSUB"].table.FeatureList.FeatureRecord
-    }
-    glyphs = set(font.getGlyphOrder())
-
-    assert "rvrn" not in featureTags
-    assert glyphs == {".notdef", "f", "dollar"}
-    # all FeatureVariationRecords were dropped
-    assert font["GSUB"].table.FeatureVariations is None
-    assert font["GSUB"].table.Version == 0x00010000
-
-
-# TODO test_subset_feature_variations_drop_from_end_empty_records
-# https://github.com/fonttools/fonttools/issues/1881#issuecomment-619415044
-
-
-def test_subset_single_pos_format():
-    fb = FontBuilder(unitsPerEm=1000)
-    fb.setupGlyphOrder([".notdef", "a", "b", "c"])
-    fb.setupCharacterMap({ord("a"): "a", ord("b"): "b", ord("c"): "c"})
-    fb.setupNameTable({"familyName": "TestSingePosFormat", "styleName": "Regular"})
-    fb.setupPost()
-    fb.addOpenTypeFeatures("""
-        feature kern {
-            pos a -50;
-            pos b -40;
-            pos c -50;
-        } kern;
-    """)
-
-    buf = io.BytesIO()
-    fb.save(buf)
-    buf.seek(0)
-
-    font = TTFont(buf)
-
-    # The input font has a SinglePos Format 2 subtable where each glyph has
-    # different ValueRecords
-    assert getXML(font["GPOS"].table.LookupList.Lookup[0].toXML, font) == [
-        '<Lookup>',
-        '  <LookupType value="1"/>',
-        '  <LookupFlag value="0"/>',
-        '  <!-- SubTableCount=1 -->',
-        '  <SinglePos index="0" Format="2">',
-        '    <Coverage>',
-        '      <Glyph value="a"/>',
-        '      <Glyph value="b"/>',
-        '      <Glyph value="c"/>',
-        '    </Coverage>',
-        '    <ValueFormat value="4"/>',
-        '    <!-- ValueCount=3 -->',
-        '    <Value index="0" XAdvance="-50"/>',
-        '    <Value index="1" XAdvance="-40"/>',
-        '    <Value index="2" XAdvance="-50"/>',
-        '  </SinglePos>',
-        '</Lookup>',
-    ]
-
-    options = subset.Options()
-    subsetter = subset.Subsetter(options)
-    subsetter.populate(unicodes=[ord("a"), ord("c")])
-    subsetter.subset(font)
-
-    # All the subsetted glyphs from the original SinglePos Format2 subtable
-    # now have the same ValueRecord, so we use a more compact Format 1 subtable.
-    assert getXML(font["GPOS"].table.LookupList.Lookup[0].toXML, font) == [
-        '<Lookup>',
-        '  <LookupType value="1"/>',
-        '  <LookupFlag value="0"/>',
-        '  <!-- SubTableCount=1 -->',
-        '  <SinglePos index="0" Format="1">',
-        '    <Coverage>',
-        '      <Glyph value="a"/>',
-        '      <Glyph value="c"/>',
-        '    </Coverage>',
-        '    <ValueFormat value="4"/>',
-        '    <Value XAdvance="-50"/>',
-        '  </SinglePos>',
-        '</Lookup>',
-    ]
-
-
-@pytest.fixture
-def ttf_path(tmp_path):
-    # $(dirname $0)/../ttLib/data
-    ttLib_data = pathlib.Path(__file__).parent.parent / "ttLib" / "data"
-    font = TTFont()
-    font.importXML(ttLib_data / "TestTTF-Regular.ttx")
-    font_path = tmp_path / "TestTTF-Regular.ttf"
-    font.save(font_path)
-    return font_path
-
-
-def test_subset_empty_glyf(tmp_path, ttf_path):
-    subset_path = tmp_path / (ttf_path.name + ".subset")
-    # only keep empty .notdef and space glyph, resulting in an empty glyf table
-    subset.main(
-        [
-            str(ttf_path),
-            "--no-notdef-outline",
-            "--glyph-names",
-            f"--output-file={subset_path}",
-            "--glyphs=.notdef space",
-        ]
-    )
-    subset_font = TTFont(subset_path)
-
-    assert subset_font.getGlyphOrder() == [".notdef", "space"]
-    assert subset_font.reader['glyf'] == b"\x00"
-
-    glyf = subset_font["glyf"]
-    assert all(glyf[g].numberOfContours == 0 for g in subset_font.getGlyphOrder())
-
-    loca = subset_font["loca"]
-    assert all(loc == 0 for loc in loca)
-
-
-@pytest.fixture
-def colrv1_path(tmp_path):
-    base_glyph_names = ["uni%04X" % i for i in range(0xE000, 0xE000 + 10)]
-    layer_glyph_names = ["glyph%05d" % i for i in range(10, 20)]
-    glyph_order = [".notdef"] + base_glyph_names + layer_glyph_names
-
-    pen = TTGlyphPen(glyphSet=None)
-    pen.moveTo((0, 0))
-    pen.lineTo((0, 500))
-    pen.lineTo((500, 500))
-    pen.lineTo((500, 0))
-    pen.closePath()
-    glyph = pen.glyph()
-    glyphs = {g: glyph for g in glyph_order}
-
-    fb = FontBuilder(unitsPerEm=1024, isTTF=True)
-    fb.setupGlyphOrder(glyph_order)
-    fb.setupCharacterMap({int(name[3:], 16): name for name in base_glyph_names})
-    fb.setupGlyf(glyphs)
-    fb.setupHorizontalMetrics({g: (500, 0) for g in glyph_order})
-    fb.setupHorizontalHeader()
-    fb.setupOS2()
-    fb.setupPost()
-    fb.setupNameTable({"familyName": "TestCOLRv1", "styleName": "Regular"})
-
-    fb.setupCOLR(
-        {
-            "uniE000": (
-                ot.PaintFormat.PaintColrLayers,
-                [
-                    {
-                        "Format": ot.PaintFormat.PaintGlyph,
-                        "Paint": (ot.PaintFormat.PaintSolid, 0),
-                        "Glyph": "glyph00010",
-                    },
-                    {
-                        "Format": ot.PaintFormat.PaintGlyph,
-                        "Paint": (ot.PaintFormat.PaintSolid, (2, 0.3)),
-                        "Glyph": "glyph00011",
-                    },
-                ],
-            ),
-            "uniE001": (
-                ot.PaintFormat.PaintColrLayers,
-                [
-                    {
-                        "Format": ot.PaintFormat.PaintTransform,
-                        "Paint": {
-                            "Format": ot.PaintFormat.PaintGlyph,
-                            "Paint": {
-                                "Format": ot.PaintFormat.PaintRadialGradient,
-                                "x0": 250,
-                                "y0": 250,
-                                "r0": 250,
-                                "x1": 200,
-                                "y1": 200,
-                                "r1": 0,
-                                "ColorLine": {
-                                    "ColorStop": [(0.0, 1), (1.0, 2)],
-                                    "Extend": "repeat",
-                                },
-                            },
-                            "Glyph": "glyph00012",
-                        },
-                        "Transform": (0.7071, 0.7071, -0.7071, 0.7071, 0, 0),
-                    },
-                    {
-                        "Format": ot.PaintFormat.PaintGlyph,
-                        "Paint": (ot.PaintFormat.PaintSolid, (1, 0.5)),
-                        "Glyph": "glyph00013",
-                    },
-                ],
-            ),
-            "uniE002": (
-                ot.PaintFormat.PaintColrLayers,
-                [
-                    {
-                        "Format": ot.PaintFormat.PaintGlyph,
-                        "Paint": {
-                            "Format": ot.PaintFormat.PaintLinearGradient,
-                            "x0": 0,
-                            "y0": 0,
-                            "x1": 500,
-                            "y1": 500,
-                            "x2": -500,
-                            "y2": 500,
-                            "ColorLine": {"ColorStop": [(0.0, 1), (1.0, 2)]},
-                        },
-                        "Glyph": "glyph00014",
-                    },
-                    {
-                        "Format": ot.PaintFormat.PaintTransform,
-                        "Paint": {
-                            "Format": ot.PaintFormat.PaintGlyph,
-                            "Paint": (ot.PaintFormat.PaintSolid, 1),
-                            "Glyph": "glyph00015",
-                        },
-                        "Transform": (1, 0, 0, 1, 400, 400),
-                    },
-                ],
-            ),
-            "uniE003": {
-                "Format": ot.PaintFormat.PaintRotate,
-                "Paint": {
-                    "Format": ot.PaintFormat.PaintColrGlyph,
-                    "Glyph": "uniE001",
-                },
-                "angle": 45,
-                "centerX": 250,
-                "centerY": 250,
-            },
-            "uniE004": [
-                ("glyph00016", 1),
-                ("glyph00017", 2),
-            ],
-        },
-    )
-    fb.setupCPAL(
-        [
-            [
-                (1.0, 0.0, 0.0, 1.0),  # red
-                (0.0, 1.0, 0.0, 1.0),  # green
-                (0.0, 0.0, 1.0, 1.0),  # blue
-            ],
-        ],
-    )
-
-    output_path = tmp_path / "TestCOLRv1.ttf"
-    fb.save(output_path)
-
-    return output_path
-
-
-def test_subset_COLRv1_and_CPAL(colrv1_path):
-    subset_path = colrv1_path.parent / (colrv1_path.name + ".subset")
-
-    subset.main(
-        [
-            str(colrv1_path),
-            "--glyph-names",
-            f"--output-file={subset_path}",
-            "--unicodes=E002,E003,E004",
-        ]
-    )
-    subset_font = TTFont(subset_path)
-
-    glyph_set = set(subset_font.getGlyphOrder())
-
-    # uniE000 and its children are excluded from subset
-    assert "uniE000" not in glyph_set
-    assert "glyph00010" not in glyph_set
-    assert "glyph00011" not in glyph_set
-
-    # uniE001 and children are pulled in indirectly as PaintColrGlyph by uniE003
-    assert "uniE001" in glyph_set
-    assert "glyph00012" in glyph_set
-    assert "glyph00013" in glyph_set
-
-    assert "uniE002" in glyph_set
-    assert "glyph00014" in glyph_set
-    assert "glyph00015" in glyph_set
-
-    assert "uniE003" in glyph_set
-
-    assert "uniE004" in glyph_set
-    assert "glyph00016" in glyph_set
-    assert "glyph00017" in glyph_set
-
-    assert "COLR" in subset_font
-    colr = subset_font["COLR"].table
-    assert colr.Version == 1
-    assert len(colr.BaseGlyphRecordArray.BaseGlyphRecord) == 1
-    assert len(colr.BaseGlyphV1List.BaseGlyphV1Record) == 3  # was 4
-
-    base = colr.BaseGlyphV1List.BaseGlyphV1Record[0]
-    assert base.BaseGlyph == "uniE001"
-    layers = colr.LayerV1List.Paint[
-        base.Paint.FirstLayerIndex: base.Paint.FirstLayerIndex + base.Paint.NumLayers
-    ]
-    assert len(layers) == 2
-    # check v1 palette indices were remapped
-    assert layers[0].Paint.Paint.ColorLine.ColorStop[0].Color.PaletteIndex == 0
-    assert layers[0].Paint.Paint.ColorLine.ColorStop[1].Color.PaletteIndex == 1
-    assert layers[1].Paint.Color.PaletteIndex == 0
-
-    baseRecV0 = colr.BaseGlyphRecordArray.BaseGlyphRecord[0]
-    assert baseRecV0.BaseGlyph == "uniE004"
-    layersV0 = colr.LayerRecordArray.LayerRecord
-    assert len(layersV0) == 2
-    # check v0 palette indices were remapped
-    assert layersV0[0].PaletteIndex == 0
-    assert layersV0[1].PaletteIndex == 1
-
-    assert "CPAL" in subset_font
-    cpal = subset_font["CPAL"]
-    assert [
-        tuple(v / 255 for v in (c.red, c.green, c.blue, c.alpha))
-        for c in cpal.palettes[0]
-    ] == [
-        # the first color 'red' was pruned
-        (0.0, 1.0, 0.0, 1.0),  # green
-        (0.0, 0.0, 1.0, 1.0),  # blue
-    ]
-
-
-def test_subset_COLRv1_and_CPAL_drop_empty(colrv1_path):
-    subset_path = colrv1_path.parent / (colrv1_path.name + ".subset")
-
-    subset.main(
-        [
-            str(colrv1_path),
-            "--glyph-names",
-            f"--output-file={subset_path}",
-            "--glyphs=glyph00010",
-        ]
-    )
-    subset_font = TTFont(subset_path)
-
-    glyph_set = set(subset_font.getGlyphOrder())
-
-    assert "glyph00010" in glyph_set
-    assert "uniE000" not in glyph_set
-
-    assert "COLR" not in subset_font
-    assert "CPAL" not in subset_font
-
-
-def test_subset_COLRv1_downgrade_version(colrv1_path):
-    subset_path = colrv1_path.parent / (colrv1_path.name + ".subset")
-
-    subset.main(
-        [
-            str(colrv1_path),
-            "--glyph-names",
-            f"--output-file={subset_path}",
-            "--unicodes=E004",
-        ]
-    )
-    subset_font = TTFont(subset_path)
-
-    assert set(subset_font.getGlyphOrder()) == {
-        ".notdef",
-        "uniE004",
-        "glyph00016",
-        "glyph00017",
-    }
-
-    assert "COLR" in subset_font
-    assert subset_font["COLR"].version == 0
-
 
 if __name__ == "__main__":
     sys.exit(unittest.main())
diff --git a/Tests/svgLib/path/parser_test.py b/Tests/svgLib/path/parser_test.py
index b533dd8..eada14e 100644
--- a/Tests/svgLib/path/parser_test.py
+++ b/Tests/svgLib/path/parser_test.py
@@ -1,3 +1,6 @@
+from __future__ import print_function, absolute_import, division
+
+from fontTools.misc.py23 import *
 from fontTools.pens.recordingPen import RecordingPen
 from fontTools.svgLib import parse_path
 
@@ -351,86 +354,3 @@
     ]
 
     assert pen.value == expected
-
-
-@pytest.mark.parametrize(
-    "path, expected",
-    [
-        (
-            "M1-2A3-4-1.0 01.5.7",
-            [
-                ("moveTo", ((1.0, -2.0),)),
-                ("arcTo", (3.0, -4.0, -1.0, False, True, (0.5, 0.7))),
-                ("endPath", ()),
-            ],
-        ),
-        (
-            "M21.58 7.19a2.51 2.51 0 10-1.77-1.77",
-            [
-                ("moveTo", ((21.58, 7.19),)),
-                ("arcTo", (2.51, 2.51, 0.0, True, False, (19.81, 5.42))),
-                ("endPath", ()),
-            ],
-        ),
-        (
-            "M22 12a25.87 25.87 0 00-.42-4.81",
-            [
-                ("moveTo", ((22.0, 12.0),)),
-                ("arcTo", (25.87, 25.87, 0.0, False, False, (21.58, 7.19))),
-                ("endPath", ()),
-            ],
-        ),
-        (
-            "M0,0 A1.2 1.2 0 012 15.8",
-            [
-                ("moveTo", ((0.0, 0.0),)),
-                ("arcTo", (1.2, 1.2, 0.0, False, True, (2.0, 15.8))),
-                ("endPath", ()),
-            ],
-        ),
-        (
-            "M12 7a5 5 0 105 5 5 5 0 00-5-5",
-            [
-
-                ("moveTo", ((12.0, 7.0),)),
-                ("arcTo", (5.0, 5.0, 0.0, True, False, (17.0, 12.0))),
-                ("arcTo", (5.0, 5.0, 0.0, False, False, (12.0, 7.0))),
-                ("endPath", ()),
-            ],
-        )
-    ],
-)
-def test_arc_flags_without_spaces(path, expected):
-    pen = ArcRecordingPen()
-    parse_path(path, pen)
-    assert pen.value == expected
-
-
-@pytest.mark.parametrize(
-    "path", ["A", "A0,0,0,0,0,0", "A 0 0 0 0 0 0 0 0 0 0 0 0 0"]
-)
-def test_invalid_arc_not_enough_args(path):
-    pen = ArcRecordingPen()
-    with pytest.raises(ValueError, match="Invalid arc command") as e:
-        parse_path(path, pen)
-
-    assert isinstance(e.value.__cause__, ValueError)
-    assert "Not enough arguments" in str(e.value.__cause__)
-
-
-def test_invalid_arc_argument_value():
-    pen = ArcRecordingPen()
-    with pytest.raises(ValueError, match="Invalid arc command") as e:
-        parse_path("M0,0 A0,0,0,2,0,0,0", pen)
-
-    cause = e.value.__cause__
-    assert isinstance(cause, ValueError)
-    assert "Invalid argument for 'large-arc-flag' parameter: '2'" in str(cause)
-
-    pen = ArcRecordingPen()
-    with pytest.raises(ValueError, match="Invalid arc command") as e:
-        parse_path("M0,0 A0,0,0,0,-2.0,0,0", pen)
-
-    cause = e.value.__cause__
-    assert isinstance(cause, ValueError)
-    assert "Invalid argument for 'sweep-flag' parameter: '-2.0'" in str(cause)
diff --git a/Tests/svgLib/path/path_test.py b/Tests/svgLib/path/path_test.py
index 8ee334a..09b9447 100644
--- a/Tests/svgLib/path/path_test.py
+++ b/Tests/svgLib/path/path_test.py
@@ -1,4 +1,6 @@
-from fontTools.misc.py23 import tobytes
+from __future__ import print_function, absolute_import, division
+
+from fontTools.misc.py23 import *
 from fontTools.pens.recordingPen import RecordingPen
 from fontTools.svgLib import SVGPath
 
diff --git a/Tests/svgLib/path/shapes_test.py b/Tests/svgLib/path/shapes_test.py
index 24e3dd2..99c70fd 100644
--- a/Tests/svgLib/path/shapes_test.py
+++ b/Tests/svgLib/path/shapes_test.py
@@ -1,3 +1,6 @@
+from __future__ import print_function, absolute_import, division
+
+from fontTools.misc.py23 import *
 from fontTools.svgLib.path import shapes
 from fontTools.misc import etree
 import pytest
diff --git a/Tests/t1Lib/t1Lib_test.py b/Tests/t1Lib/t1Lib_test.py
index 92b3e9e..153254d 100644
--- a/Tests/t1Lib/t1Lib_test.py
+++ b/Tests/t1Lib/t1Lib_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 import unittest
 import os
 import sys
diff --git a/Tests/ttLib/data/woff2_overlap_offcurve_in.ttx b/Tests/ttLib/data/woff2_overlap_offcurve_in.ttx
deleted file mode 100644
index a36dbf5..0000000
--- a/Tests/ttLib/data/woff2_overlap_offcurve_in.ttx
+++ /dev/null
@@ -1,306 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.18">
-
-  <GlyphOrder>
-    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="A"/>
-  </GlyphOrder>
-
-  <head>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="1.0"/>
-    <fontRevision value="1.0"/>
-    <checkSumAdjustment value="0x9aec19bb"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00000010"/>
-    <unitsPerEm value="1000"/>
-    <created value="Thu Jan 28 15:17:57 2021"/>
-    <modified value="Thu Jan 28 15:52:10 2021"/>
-    <xMin value="178"/>
-    <yMin value="72"/>
-    <xMax value="586"/>
-    <yMax value="480"/>
-    <macStyle value="00000000 00000000"/>
-    <lowestRecPPEM value="6"/>
-    <fontDirectionHint value="2"/>
-    <indexToLocFormat value="0"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="750"/>
-    <descent value="-250"/>
-    <lineGap value="100"/>
-    <advanceWidthMax value="639"/>
-    <minLeftSideBearing value="178"/>
-    <minRightSideBearing value="53"/>
-    <xMaxExtent value="586"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfHMetrics value="2"/>
-  </hhea>
-
-  <maxp>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="0x10000"/>
-    <numGlyphs value="2"/>
-    <maxPoints value="20"/>
-    <maxContours value="1"/>
-    <maxCompositePoints value="0"/>
-    <maxCompositeContours value="0"/>
-    <maxZones value="1"/>
-    <maxTwilightPoints value="0"/>
-    <maxStorage value="0"/>
-    <maxFunctionDefs value="0"/>
-    <maxInstructionDefs value="0"/>
-    <maxStackElements value="0"/>
-    <maxSizeOfInstructions value="0"/>
-    <maxComponentElements value="0"/>
-    <maxComponentDepth value="0"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="4"/>
-    <xAvgCharWidth value="445"/>
-    <usWeightClass value="400"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00000100"/>
-    <ySubscriptXSize value="650"/>
-    <ySubscriptYSize value="600"/>
-    <ySubscriptXOffset value="0"/>
-    <ySubscriptYOffset value="75"/>
-    <ySuperscriptXSize value="650"/>
-    <ySuperscriptYSize value="600"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="350"/>
-    <yStrikeoutSize value="50"/>
-    <yStrikeoutPosition value="300"/>
-    <sFamilyClass value="0"/>
-    <panose>
-      <bFamilyType value="0"/>
-      <bSerifStyle value="0"/>
-      <bWeight value="0"/>
-      <bProportion value="0"/>
-      <bContrast value="0"/>
-      <bStrokeVariation value="0"/>
-      <bArmStyle value="0"/>
-      <bLetterForm value="0"/>
-      <bMidline value="0"/>
-      <bXHeight value="0"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="NONE"/>
-    <fsSelection value="00000000 11000000"/>
-    <usFirstCharIndex value="65"/>
-    <usLastCharIndex value="65"/>
-    <sTypoAscender value="750"/>
-    <sTypoDescender value="-250"/>
-    <sTypoLineGap value="100"/>
-    <usWinAscent value="750"/>
-    <usWinDescent value="250"/>
-    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
-    <sxHeight value="500"/>
-    <sCapHeight value="700"/>
-    <usDefaultChar value="0"/>
-    <usBreakChar value="32"/>
-    <usMaxContext value="0"/>
-  </OS_2>
-
-  <hmtx>
-    <mtx name=".notdef" width="250" lsb="0"/>
-    <mtx name="A" width="639" lsb="178"/>
-  </hmtx>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_4 platformID="0" platEncID="3" language="0">
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-    </cmap_format_4>
-    <cmap_format_4 platformID="3" platEncID="1" language="0">
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-    </cmap_format_4>
-  </cmap>
-
-  <loca>
-    <!-- The 'loca' table will be calculated by the compiler -->
-  </loca>
-
-  <glyf>
-
-    <!-- The xMin, yMin, xMax and yMax values
-         will be recalculated by the compiler. -->
-
-    <TTGlyph name=".notdef"/><!-- contains no outline data -->
-
-    <TTGlyph name="A" xMin="178" yMin="72" xMax="586" yMax="480">
-      <contour>
-        <pt x="382" y="72" on="0" overlap="1"/>
-        <pt x="336" y="72" on="1"/>
-        <pt x="261" y="101" on="0"/>
-        <pt x="207" y="155" on="0"/>
-        <pt x="178" y="230" on="0"/>
-        <pt x="178" y="276" on="1"/>
-        <pt x="178" y="322" on="0"/>
-        <pt x="207" y="397" on="0"/>
-        <pt x="261" y="451" on="0"/>
-        <pt x="336" y="480" on="0"/>
-        <pt x="382" y="480" on="1"/>
-        <pt x="428" y="480" on="0"/>
-        <pt x="503" y="451" on="0"/>
-        <pt x="557" y="397" on="0"/>
-        <pt x="586" y="322" on="0"/>
-        <pt x="586" y="276" on="1"/>
-        <pt x="586" y="230" on="0"/>
-        <pt x="557" y="155" on="0"/>
-        <pt x="503" y="101" on="0"/>
-        <pt x="428" y="72" on="0"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-  </glyf>
-
-  <name>
-    <namerecord nameID="256" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Weight
-    </namerecord>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      Unnamed
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      1.000;NONE;Unnamed-Regular
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      Unnamed Regular
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version 1.000
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      Unnamed-Regular
-    </namerecord>
-    <namerecord nameID="256" platformID="3" platEncID="1" langID="0x409">
-      Weight
-    </namerecord>
-  </name>
-
-  <post>
-    <formatType value="2.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-100"/>
-    <underlineThickness value="50"/>
-    <isFixedPitch value="0"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="0"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="0"/>
-    <psNames>
-      <!-- This file uses unique glyph names based on the information
-           found in the 'post' table. Since these names might not be unique,
-           we have to invent artificial names in case of clashes. In order to
-           be able to retain the original information, we need a name to
-           ps name mapping for those cases where they differ. That's what
-           you see below.
-            -->
-    </psNames>
-    <extraNames>
-      <!-- following are the name that are not taken from the standard Mac glyph order -->
-    </extraNames>
-  </post>
-
-  <gasp>
-    <gaspRange rangeMaxPPEM="65535" rangeGaspBehavior="15"/>
-  </gasp>
-
-  <HVAR>
-    <Version value="0x00010000"/>
-    <VarStore Format="1">
-      <Format value="1"/>
-      <VarRegionList>
-        <!-- RegionAxisCount=1 -->
-        <!-- RegionCount=1 -->
-        <Region index="0">
-          <VarRegionAxis index="0">
-            <StartCoord value="0.0"/>
-            <PeakCoord value="1.0"/>
-            <EndCoord value="1.0"/>
-          </VarRegionAxis>
-        </Region>
-      </VarRegionList>
-      <!-- VarDataCount=1 -->
-      <VarData index="0">
-        <!-- ItemCount=2 -->
-        <NumShorts value="0"/>
-        <!-- VarRegionCount=0 -->
-        <Item index="0" value="[]"/>
-        <Item index="1" value="[]"/>
-      </VarData>
-    </VarStore>
-  </HVAR>
-
-  <STAT>
-    <Version value="0x00010001"/>
-    <DesignAxisRecordSize value="8"/>
-    <!-- DesignAxisCount=1 -->
-    <DesignAxisRecord>
-      <Axis index="0">
-        <AxisTag value="wght"/>
-        <AxisNameID value="256"/>  <!-- Weight -->
-        <AxisOrdering value="0"/>
-      </Axis>
-    </DesignAxisRecord>
-    <!-- AxisValueCount=0 -->
-    <ElidedFallbackNameID value="2"/>  <!-- Regular -->
-  </STAT>
-
-  <fvar>
-
-    <!-- Weight -->
-    <Axis>
-      <AxisTag>wght</AxisTag>
-      <Flags>0x0</Flags>
-      <MinValue>400.0</MinValue>
-      <DefaultValue>400.0</DefaultValue>
-      <MaxValue>700.0</MaxValue>
-      <AxisNameID>256</AxisNameID>
-    </Axis>
-  </fvar>
-
-  <gvar>
-    <version value="1"/>
-    <reserved value="0"/>
-    <glyphVariations glyph="A">
-      <tuple>
-        <coord axis="wght" value="1.0"/>
-        <delta pt="0" x="-64" y="-44"/>
-        <delta pt="5" x="-138" y="30"/>
-        <delta pt="7" x="-127" y="73"/>
-        <delta pt="8" x="-108" y="92"/>
-        <delta pt="10" x="-64" y="103"/>
-        <delta pt="12" x="-21" y="92"/>
-        <delta pt="13" x="-2" y="73"/>
-        <delta pt="16" x="9" y="13"/>
-        <delta pt="17" x="-2" y="-14"/>
-        <delta pt="18" x="-21" y="-33"/>
-      </tuple>
-    </glyphVariations>
-  </gvar>
-
-</ttFont>
diff --git a/Tests/ttLib/sfnt_test.py b/Tests/ttLib/sfnt_test.py
index 9f81744..2119351 100644
--- a/Tests/ttLib/sfnt_test.py
+++ b/Tests/ttLib/sfnt_test.py
@@ -1,59 +1,8 @@
-import io
-import copy
-import pickle
-from fontTools.ttLib.sfnt import calcChecksum, SFNTReader
-import pytest
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools.ttLib.sfnt import calcChecksum
 
 
 def test_calcChecksum():
     assert calcChecksum(b"abcd") == 1633837924
     assert calcChecksum(b"abcdxyz") == 3655064932
-
-
-EMPTY_SFNT = b"\x00\x01\x00\x00" + b"\x00" * 8
-
-
-def pickle_unpickle(obj):
-    return pickle.loads(pickle.dumps(obj))
-
-
-class SFNTReaderTest:
-    @pytest.mark.parametrize("deepcopy", [copy.deepcopy, pickle_unpickle])
-    def test_pickle_protocol_FileIO(self, deepcopy, tmp_path):
-        fontfile = tmp_path / "test.ttf"
-        fontfile.write_bytes(EMPTY_SFNT)
-        reader = SFNTReader(fontfile.open("rb"))
-
-        reader2 = deepcopy(reader)
-
-        assert reader2 is not reader
-        assert reader2.file is not reader.file
-
-        assert isinstance(reader2.file, io.BufferedReader)
-        assert isinstance(reader2.file.raw, io.FileIO)
-        assert reader2.file.name == reader.file.name
-        assert reader2.file.tell() == reader.file.tell()
-
-        for k, v in reader.__dict__.items():
-            if k == "file":
-                continue
-            assert getattr(reader2, k) == v
-
-    @pytest.mark.parametrize("deepcopy", [copy.deepcopy, pickle_unpickle])
-    def test_pickle_protocol_BytesIO(self, deepcopy, tmp_path):
-        buf = io.BytesIO(EMPTY_SFNT)
-        reader = SFNTReader(buf)
-
-        reader2 = deepcopy(reader)
-
-        assert reader2 is not reader
-        assert reader2.file is not reader.file
-
-        assert isinstance(reader2.file, io.BytesIO)
-        assert reader2.file.tell() == reader.file.tell()
-        assert reader2.file.getvalue() == reader.file.getvalue()
-
-        for k, v in reader.__dict__.items():
-            if k == "file":
-                continue
-            assert getattr(reader2, k) == v
diff --git a/Tests/ttLib/tables/C_B_L_C_test.py b/Tests/ttLib/tables/C_B_L_C_test.py
deleted file mode 100644
index fed25f9..0000000
--- a/Tests/ttLib/tables/C_B_L_C_test.py
+++ /dev/null
@@ -1,80 +0,0 @@
-import base64
-import io
-import os
-
-from fontTools.misc.testTools import getXML
-from fontTools.ttLib import TTFont
-
-
-DATA_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), "data")
-
-# This is a subset from NotoColorEmoji.ttf which contains an IndexTable format=3
-INDEX_FORMAT_3_TTX = os.path.join(DATA_DIR, "NotoColorEmoji.subset.index_format_3.ttx")
-# The CLBC table was compiled with Harfbuzz' hb-subset and contains the correct padding
-CBLC_INDEX_FORMAT_3 = base64.b64decode(
-    "AAMAAAAAAAEAAAA4AAAALAAAAAIAAAAAZeWIAAAAAAAAAAAAZeWIAAAAAAAAAAAAAAEAA"
-    "21tIAEAAQACAAAAEAADAAMAAAAgAAMAEQAAAAQAAAOmEQ0AAAADABEAABERAAAIUg=="
-)
-
-
-def test_compile_decompile_index_table_format_3():
-    font = TTFont()
-    font.importXML(INDEX_FORMAT_3_TTX)
-    buf = io.BytesIO()
-    font.save(buf)
-    buf.seek(0)
-    font = TTFont(buf)
-
-    assert font.reader["CBLC"] == CBLC_INDEX_FORMAT_3
-
-    assert getXML(font["CBLC"].toXML, font) == [
-        '<header version="3.0"/>',
-        '<strike index="0">',
-        "  <bitmapSizeTable>",
-        '    <sbitLineMetrics direction="hori">',
-        '      <ascender value="101"/>',
-        '      <descender value="-27"/>',
-        '      <widthMax value="136"/>',
-        '      <caretSlopeNumerator value="0"/>',
-        '      <caretSlopeDenominator value="0"/>',
-        '      <caretOffset value="0"/>',
-        '      <minOriginSB value="0"/>',
-        '      <minAdvanceSB value="0"/>',
-        '      <maxBeforeBL value="0"/>',
-        '      <minAfterBL value="0"/>',
-        '      <pad1 value="0"/>',
-        '      <pad2 value="0"/>',
-        "    </sbitLineMetrics>",
-        '    <sbitLineMetrics direction="vert">',
-        '      <ascender value="101"/>',
-        '      <descender value="-27"/>',
-        '      <widthMax value="136"/>',
-        '      <caretSlopeNumerator value="0"/>',
-        '      <caretSlopeDenominator value="0"/>',
-        '      <caretOffset value="0"/>',
-        '      <minOriginSB value="0"/>',
-        '      <minAdvanceSB value="0"/>',
-        '      <maxBeforeBL value="0"/>',
-        '      <minAfterBL value="0"/>',
-        '      <pad1 value="0"/>',
-        '      <pad2 value="0"/>',
-        "    </sbitLineMetrics>",
-        '    <colorRef value="0"/>',
-        '    <startGlyphIndex value="1"/>',
-        '    <endGlyphIndex value="3"/>',
-        '    <ppemX value="109"/>',
-        '    <ppemY value="109"/>',
-        '    <bitDepth value="32"/>',
-        '    <flags value="1"/>',
-        "  </bitmapSizeTable>",
-        "  <!-- GlyphIds are written but not read. The firstGlyphIndex and",
-        "       lastGlyphIndex values will be recalculated by the compiler. -->",
-        '  <eblc_index_sub_table_3 imageFormat="17" firstGlyphIndex="1" lastGlyphIndex="2">',
-        '    <glyphLoc id="1" name="eight"/>',
-        '    <glyphLoc id="2" name="registered"/>',
-        "  </eblc_index_sub_table_3>",
-        '  <eblc_index_sub_table_3 imageFormat="17" firstGlyphIndex="3" lastGlyphIndex="3">',
-        '    <glyphLoc id="3" name="uni2049"/>',
-        "  </eblc_index_sub_table_3>",
-        "</strike>",
-    ]
diff --git a/Tests/ttLib/tables/C_F_F__2_test.py b/Tests/ttLib/tables/C_F_F__2_test.py
index 10f9b2f..191f60b 100644
--- a/Tests/ttLib/tables/C_F_F__2_test.py
+++ b/Tests/ttLib/tables/C_F_F__2_test.py
@@ -1,7 +1,9 @@
 """cff2Lib_test.py -- unit test for Adobe CFF fonts."""
 
-from fontTools.ttLib import TTFont
-from io import StringIO
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
+from fontTools.misc.py23 import *
+from fontTools.ttLib import TTFont, newTable
 import re
 import os
 import unittest
@@ -39,7 +41,7 @@
         font = TTFont(file=CFF_BIN)
         cffTable = font['CFF2']
         cffData = cffTable.compile(font)
-        out = StringIO()
+        out = UnicodeIO()
         font.saveXML(out)
         cff2XML = out.getvalue()
         cff2XML = strip_VariableItems(cff2XML)
diff --git a/Tests/ttLib/tables/C_F_F_test.py b/Tests/ttLib/tables/C_F_F_test.py
index cb8d8c5..63f767c 100644
--- a/Tests/ttLib/tables/C_F_F_test.py
+++ b/Tests/ttLib/tables/C_F_F_test.py
@@ -1,7 +1,9 @@
 """cffLib_test.py -- unit test for Adobe CFF fonts."""
 
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.ttLib import TTFont, newTable
-from io import StringIO
 import re
 import os
 import unittest
@@ -31,7 +33,7 @@
         font = TTFont(sfntVersion='OTTO')
         cffTable = font['CFF '] = newTable('CFF ')
         cffTable.decompile(self.cffData, font)
-        out = StringIO()
+        out = UnicodeIO()
         font.saveXML(out)
         cffXML = strip_ttLibVersion(out.getvalue()).splitlines()
         self.assertEqual(cffXML, self.cffXML)
diff --git a/Tests/ttLib/tables/C_O_L_R_test.py b/Tests/ttLib/tables/C_O_L_R_test.py
deleted file mode 100644
index 4855f58..0000000
--- a/Tests/ttLib/tables/C_O_L_R_test.py
+++ /dev/null
@@ -1,512 +0,0 @@
-from fontTools import ttLib
-from fontTools.misc.testTools import getXML, parseXML
-from fontTools.ttLib.tables.C_O_L_R_ import table_C_O_L_R_
-
-import binascii
-import pytest
-
-
-COLR_V0_SAMPLE = (
-    (b"\x00\x00", "Version (0)"),
-    (b"\x00\x01", "BaseGlyphRecordCount (1)"),
-    (
-        b"\x00\x00\x00\x0e",
-        "Offset to BaseGlyphRecordArray from beginning of table (14)",
-    ),
-    (b"\x00\x00\x00\x14", "Offset to LayerRecordArray from beginning of table (20)"),
-    (b"\x00\x03", "LayerRecordCount (3)"),
-    (b"\x00\x06", "BaseGlyphRecord[0].BaseGlyph (6)"),
-    (b"\x00\x00", "BaseGlyphRecord[0].FirstLayerIndex (0)"),
-    (b"\x00\x03", "BaseGlyphRecord[0].NumLayers (3)"),
-    (b"\x00\x07", "LayerRecord[0].LayerGlyph (7)"),
-    (b"\x00\x00", "LayerRecord[0].PaletteIndex (0)"),
-    (b"\x00\x08", "LayerRecord[1].LayerGlyph (8)"),
-    (b"\x00\x01", "LayerRecord[1].PaletteIndex (1)"),
-    (b"\x00\t", "LayerRecord[2].LayerGlyph (9)"),
-    (b"\x00\x02", "LayerRecord[3].PaletteIndex (2)"),
-)
-
-COLR_V0_DATA = b"".join(t[0] for t in COLR_V0_SAMPLE)
-
-
-COLR_V0_XML = [
-    '<version value="0"/>',
-    '<ColorGlyph name="glyph00006">',
-    '  <layer colorID="0" name="glyph00007"/>',
-    '  <layer colorID="1" name="glyph00008"/>',
-    '  <layer colorID="2" name="glyph00009"/>',
-    "</ColorGlyph>",
-]
-
-
-def dump(table, ttFont=None):
-    print("\n".join(getXML(table.toXML, ttFont)))
-
-
-def diff_binary_fragments(font_bytes, expected_fragments):
-    pos = 0
-    prev_desc = ""
-    errors = 0
-    for expected_bytes, description in expected_fragments:
-        actual_bytes = font_bytes[pos : pos + len(expected_bytes)]
-        if actual_bytes != expected_bytes:
-            print(f'{description} (previous "{prev_desc}", actual_bytes: {"".join("%02x" % v for v in actual_bytes)} bytes: {str(font_bytes[pos:pos+16])}')
-            errors += 1
-        pos += len(expected_bytes)
-        prev_desc = description
-    assert errors == 0
-    assert pos == len(
-        font_bytes
-    ), f"Leftover font bytes, used {pos} of {len(font_bytes)}"
-
-
-@pytest.fixture
-def font():
-    font = ttLib.TTFont()
-    font.setGlyphOrder(["glyph%05d" % i for i in range(30)])
-    return font
-
-
-class COLR_V0_Test(object):
-    def test_decompile_and_compile(self, font):
-        colr = table_C_O_L_R_()
-        colr.decompile(COLR_V0_DATA, font)
-        diff_binary_fragments(colr.compile(font), COLR_V0_SAMPLE)
-
-    def test_decompile_and_dump_xml(self, font):
-        colr = table_C_O_L_R_()
-        colr.decompile(COLR_V0_DATA, font)
-
-        dump(colr, font)
-        assert getXML(colr.toXML, font) == COLR_V0_XML
-
-    def test_load_from_xml_and_compile(self, font):
-        colr = table_C_O_L_R_()
-        for name, attrs, content in parseXML(COLR_V0_XML):
-            colr.fromXML(name, attrs, content, font)
-
-        diff_binary_fragments(colr.compile(font), COLR_V0_SAMPLE)
-
-    def test_round_trip_xml(self, font):
-        colr = table_C_O_L_R_()
-        for name, attrs, content in parseXML(COLR_V0_XML):
-            colr.fromXML(name, attrs, content, font)
-        compiled = colr.compile(font)
-
-        colr = table_C_O_L_R_()
-        colr.decompile(compiled, font)
-        assert getXML(colr.toXML, font) == COLR_V0_XML
-
-
-COLR_V1_SAMPLE = (
-    (b"\x00\x01", "Version (1)"),
-    (b"\x00\x01", "BaseGlyphRecordCount (1)"),
-    (
-        b"\x00\x00\x00\x1a",
-        "Offset to BaseGlyphRecordArray from beginning of table (26)",
-    ),
-    (b"\x00\x00\x00 ", "Offset to LayerRecordArray from beginning of table (32)"),
-    (b"\x00\x03", "LayerRecordCount (3)"),
-    (b"\x00\x00\x00,", "Offset to BaseGlyphV1List from beginning of table (44)"),
-    (b"\x00\x00\x00\xac", "Offset to LayerV1List from beginning of table (172)"),
-    (b"\x00\x00\x00\x00", "Offset to VarStore (NULL)"),
-    (b"\x00\x06", "BaseGlyphRecord[0].BaseGlyph (6)"),
-    (b"\x00\x00", "BaseGlyphRecord[0].FirstLayerIndex (0)"),
-    (b"\x00\x03", "BaseGlyphRecord[0].NumLayers (3)"),
-    (b"\x00\x07", "LayerRecord[0].LayerGlyph (7)"),
-    (b"\x00\x00", "LayerRecord[0].PaletteIndex (0)"),
-    (b"\x00\x08", "LayerRecord[1].LayerGlyph (8)"),
-    (b"\x00\x01", "LayerRecord[1].PaletteIndex (1)"),
-    (b"\x00\t", "LayerRecord[2].LayerGlyph (9)"),
-    (b"\x00\x02", "LayerRecord[2].PaletteIndex (2)"),
-    # BaseGlyphV1List
-    (b"\x00\x00\x00\x03", "BaseGlyphV1List.BaseGlyphCount (3)"),
-    (b"\x00\n", "BaseGlyphV1List.BaseGlyphV1Record[0].BaseGlyph (10)"),
-    (
-        b"\x00\x00\x00\x16",
-        "Offset to Paint table from beginning of BaseGlyphV1List (22)",
-    ),
-    (b"\x00\x0e", "BaseGlyphV1List.BaseGlyphV1Record[1].BaseGlyph (14)"),
-    (
-        b"\x00\x00\x00\x1c",
-        "Offset to Paint table from beginning of BaseGlyphV1List (28)",
-    ),
-    (b"\x00\x0f", "BaseGlyphV1List.BaseGlyphV1Record[2].BaseGlyph (15)"),
-    (
-        b"\x00\x00\x00\x5b",
-        "Offset to Paint table from beginning of BaseGlyphV1List (91)",
-    ),
-    # BaseGlyphV1Record[0]
-    (b"\x01", "BaseGlyphV1Record[0].Paint.Format (1)"),
-    (b"\x04", "BaseGlyphV1Record[0].Paint.NumLayers (4)"),
-    (b"\x00\x00\x00\x00", "BaseGlyphV1Record[0].Paint.FirstLayerIndex (0)"),
-    # BaseGlyphV1Record[1]
-    (b"\x14", "BaseGlyphV1Record[1].Paint.Format (20)"),
-    (b"\x00\x00<", "Offset to SourcePaint from beginning of PaintComposite (60)"),
-    (b"\x03", "BaseGlyphV1Record[1].Paint.CompositeMode [SRC_OVER] (3)"),
-    (b"\x00\x00\x08", "Offset to BackdropPaint from beginning of PaintComposite (8)"),
-    (b"\x0d", "BaseGlyphV1Record[1].Paint.BackdropPaint.Format (13)"),
-    (b"\x00\x00\x34", "Offset to Paint from beginning of PaintVarTransform (52)"),
-    (b"\x00\x01\x00\x00\x00\x00\x00\x00", "Affine2x3.xx.value (1.0)"),
-    (b"\x00\x00\x00\x00\x00\x00\x00\x00", "Affine2x3.xy.value (0.0)"),
-    (b"\x00\x00\x00\x00\x00\x00\x00\x00", "Affine2x3.yx.value (0.0)"),
-    (b"\x00\x01\x00\x00\x00\x00\x00\x00", "Affine2x3.yy.value (1.0)"),
-    (b"\x01\x2c\x00\x00\x00\x00\x00\x00", "Affine2x3.dx.value (300.0)"),
-    (b"\x00\x00\x00\x00\x00\x00\x00\x00", "Affine2x3.dy.value (0.0)"),
-    (b"\x0b", "BaseGlyphV1Record[1].Paint.SourcePaint.Format (11)"),
-    (b"\x00\n", "BaseGlyphV1Record[1].Paint.SourcePaint.Glyph (10)"),
-    # BaseGlyphV1Record[2]
-    (b"\x0a", "BaseGlyphV1Record[2].Paint.Format (10)"),
-    (b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
-    (b"\x00\x0b", "BaseGlyphV1Record[2].Paint.Glyph (11)"),
-    (b"\x08", "BaseGlyphV1Record[2].Paint.Paint.Format (8)"),
-    (b"\x00\x00\x10", "Offset to ColorLine from beginning of PaintSweepGradient (16)"),
-    (b"\x01\x03", "centerX (259)"),
-    (b"\x01\x2c", "centerY (300)"),
-    (b"\x00\x2d\x00\x00", "startAngle (45.0)"),
-    (b"\x00\x87\x00\x00", "endAngle (135.0)"),
-    (b"\x00", "ColorLine.Extend (0; pad)"),
-    (b"\x00\x02", "ColorLine.StopCount (2)"),
-    (b"\x00\x00", "ColorLine.ColorStop[0].StopOffset (0.0)"),
-    (b"\x00\x03", "ColorLine.ColorStop[0].Color.PaletteIndex (3)"),
-    (b"@\x00", "ColorLine.ColorStop[0].Color.Alpha (1.0)"),
-    (b"@\x00", "ColorLine.ColorStop[1].StopOffset (1.0)"),
-    (b"\x00\x05", "ColorLine.ColorStop[1].Color.PaletteIndex (5)"),
-    (b"@\x00", "ColorLine.ColorStop[1].Color.Alpha (1.0)"),
-    # LayerV1List
-    (b"\x00\x00\x00\x04", "LayerV1List.LayerCount (4)"),
-    (
-        b"\x00\x00\x00\x14",
-        "First Offset to Paint table from beginning of LayerV1List (20)",
-    ),
-    (
-        b"\x00\x00\x00\x23",
-        "Second Offset to Paint table from beginning of LayerV1List (35)",
-    ),
-    (
-        b"\x00\x00\x00\x4e",
-        "Third Offset to Paint table from beginning of LayerV1List (78)",
-    ),
-    (
-        b"\x00\x00\x00\xb7",
-        "Fourth Offset to Paint table from beginning of LayerV1List (183)",
-    ),
-    # PaintGlyph glyph00011
-    (b"\x0a", "LayerV1List.Paint[0].Format (10)"),
-    (b"\x00\x00\x06", "Offset24 to Paint subtable from beginning of PaintGlyph (6)"),
-    (b"\x00\x0b", "LayerV1List.Paint[0].Glyph (glyph00011)"),
-    # PaintVarSolid
-    (b"\x03", "LayerV1List.Paint[0].Paint.Format (3)"),
-    (b"\x00\x02", "Paint.Color.PaletteIndex (2)"),
-    (b" \x00", "Paint.Color.Alpha.value (0.5)"),
-    (b"\x00\x00\x00\x00", "Paint.Color.Alpha.varIdx (0)"),
-    # PaintGlyph glyph00012
-    (b"\x0a", "LayerV1List.Paint[1].Format (10)"),
-    (b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
-    (b"\x00\x0c", "LayerV1List.Paint[1].Glyph (glyph00012)"),
-    (b"\x04", "LayerV1List.Paint[1].Paint.Format (4)"),
-    (b"\x00\x00\x10", "Offset to ColorLine from beginning of PaintLinearGradient (16)"),
-    (b"\x00\x01", "Paint.x0 (1)"),
-    (b"\x00\x02", "Paint.y0 (2)"),
-    (b"\xff\xfd", "Paint.x1 (-3)"),
-    (b"\xff\xfc", "Paint.y1 (-4)"),
-    (b"\x00\x05", "Paint.x2 (5)"),
-    (b"\x00\x06", "Paint.y2 (6)"),
-    (b"\x01", "ColorLine.Extend (1; repeat)"),
-    (b"\x00\x03", "ColorLine.StopCount (3)"),
-    (b"\x00\x00", "ColorLine.ColorStop[0].StopOffset (0.0)"),
-    (b"\x00\x03", "ColorLine.ColorStop[0].Color.PaletteIndex (3)"),
-    (b"@\x00", "ColorLine.ColorStop[0].Color.Alpha (1.0)"),
-    (b" \x00", "ColorLine.ColorStop[1].StopOffset (0.5)"),
-    (b"\x00\x04", "ColorLine.ColorStop[1].Color.PaletteIndex (4)"),
-    (b"@\x00", "ColorLine.ColorStop[1].Color.Alpha (1.0)"),
-    (b"@\x00", "ColorLine.ColorStop[2].StopOffset (1.0)"),
-    (b"\x00\x05", "ColorLine.ColorStop[2].Color.PaletteIndex (5)"),
-    (b"@\x00", "ColorLine.ColorStop[2].Color.Alpha (1.0)"),
-    # PaintGlyph glyph00013
-    (b"\x0a", "LayerV1List.Paint[2].Format (10)"),
-    (b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
-    (b"\x00\r", "LayerV1List.Paint[2].Glyph (13)"),
-    (b"\x0c", "LayerV1List.Paint[2].Paint.Format (12)"),
-    (b"\x00\x00\x1c", "Offset to Paint subtable from beginning of PaintTransform (28)"),
-    (b"\xff\xf3\x00\x00", "Affine2x3.xx (-13)"),
-    (b"\x00\x0e\x00\x00", "Affine2x3.xy (14)"),
-    (b"\x00\x0f\x00\x00", "Affine2x3.yx (15)"),
-    (b"\xff\xef\x00\x00", "Affine2x3.yy (-17)"),
-    (b"\x00\x12\x00\x00", "Affine2x3.yy (18)"),
-    (b"\x00\x13\x00\x00", "Affine2x3.yy (19)"),
-    (b"\x07", "LayerV1List.Paint[2].Paint.Paint.Format (7)"),
-    (b"\x00\x00(", "Offset to ColorLine from beginning of PaintVarRadialGradient (40)"),
-    (b"\x00\x07\x00\x00\x00\x00", "Paint.x0.value (7)"),
-    (b"\x00\x08\x00\x00\x00\x00", "Paint.y0.value (8)"),
-    (b"\x00\t\x00\x00\x00\x00", "Paint.r0.value (9)"),
-    (b"\x00\n\x00\x00\x00\x00", "Paint.x1.value (10)"),
-    (b"\x00\x0b\x00\x00\x00\x00", "Paint.y1.value (11)"),
-    (b"\x00\x0c\x00\x00\x00\x00", "Paint.r1.value (12)"),
-    (b"\x00", "ColorLine.Extend (0; pad)"),
-    (b"\x00\x02", "ColorLine.StopCount (2)"),
-    (b"\x00\x00\x00\x00\x00\x00", "ColorLine.ColorStop[0].StopOffset.value (0.0)"),
-    (b"\x00\x06", "ColorLine.ColorStop[0].Color.PaletteIndex (6)"),
-    (b"@\x00\x00\x00\x00\x00", "ColorLine.ColorStop[0].Color.Alpha.value (1.0)"),
-    (b"@\x00\x00\x00\x00\x00", "ColorLine.ColorStop[1].StopOffset.value (1.0)"),
-    (b"\x00\x07", "ColorLine.ColorStop[1].Color.PaletteIndex (7)"),
-    (b"\x19\x9a\x00\x00\x00\x00", "ColorLine.ColorStop[1].Color.Alpha.value (0.4)"),
-    # PaintTranslate
-    (b"\x0e", "LayerV1List.Paint[3].Format (14)"),
-    (b"\x00\x00\x0c", "Offset to Paint subtable from beginning of PaintTranslate (12)"),
-    (b"\x01\x01\x00\x00", "dx (257)"),
-    (b"\x01\x02\x00\x00", "dy (258)"),
-    # PaintRotate
-    (b"\x10", "LayerV1List.Paint[3].Paint.Format (16)"),
-    (b"\x00\x00\x10", "Offset to Paint subtable from beginning of PaintRotate (16)"),
-    (b"\x00\x2d\x00\x00", "angle (45)"),
-    (b"\x00\xff\x00\x00", "centerX (255)"),
-    (b"\x01\x00\x00\x00", "centerY (256)"),
-    # PaintSkew
-    (b"\x12", "LayerV1List.Paint[3].Paint.Paint.Format (18)"),
-    (b"\x00\x00\x14", "Offset to Paint subtable from beginning of PaintSkew (20)"),
-    (b"\xff\xf5\x00\x00", "xSkewAngle (-11)"),
-    (b"\x00\x05\x00\x00", "ySkewAngle (5)"),
-    (b"\x00\xfd\x00\x00", "centerX.value (253)"),
-    (b"\x00\xfe\x00\x00", "centerY.value (254)"),
-    # PaintGlyph
-    (b"\x0a", "LayerV1List.Paint[3].Paint.Paint.Paint.Format (10)"),
-    (b"\x00\x00\x06", "Offset to Paint subtable from beginning of PaintGlyph (6)"),
-    (b"\x00\x0b", "LayerV1List.Paint[2].Glyph (11)"),
-    # PaintSolid
-    (b"\x02", "LayerV1List.Paint[0].Paint.Paint.Paint.Paint.Format (2)"),
-    (b"\x00\x02", "Paint.Color.PaletteIndex (2)"),
-    (b" \x00", "Paint.Color.Alpha (0.5)"),
-)
-
-COLR_V1_DATA = b"".join(t[0] for t in COLR_V1_SAMPLE)
-
-COLR_V1_XML = [
-    '<Version value="1"/>',
-    "<!-- BaseGlyphRecordCount=1 -->",
-    "<BaseGlyphRecordArray>",
-    '  <BaseGlyphRecord index="0">',
-    '    <BaseGlyph value="glyph00006"/>',
-    '    <FirstLayerIndex value="0"/>',
-    '    <NumLayers value="3"/>',
-    "  </BaseGlyphRecord>",
-    "</BaseGlyphRecordArray>",
-    "<LayerRecordArray>",
-    '  <LayerRecord index="0">',
-    '    <LayerGlyph value="glyph00007"/>',
-    '    <PaletteIndex value="0"/>',
-    "  </LayerRecord>",
-    '  <LayerRecord index="1">',
-    '    <LayerGlyph value="glyph00008"/>',
-    '    <PaletteIndex value="1"/>',
-    "  </LayerRecord>",
-    '  <LayerRecord index="2">',
-    '    <LayerGlyph value="glyph00009"/>',
-    '    <PaletteIndex value="2"/>',
-    "  </LayerRecord>",
-    "</LayerRecordArray>",
-    "<!-- LayerRecordCount=3 -->",
-    "<BaseGlyphV1List>",
-    "  <!-- BaseGlyphCount=3 -->",
-    '  <BaseGlyphV1Record index="0">',
-    '    <BaseGlyph value="glyph00010"/>',
-    '    <Paint Format="1"><!-- PaintColrLayers -->',
-    '      <NumLayers value="4"/>',
-    '      <FirstLayerIndex value="0"/>',
-    "    </Paint>",
-    "  </BaseGlyphV1Record>",
-    '  <BaseGlyphV1Record index="1">',
-    '    <BaseGlyph value="glyph00014"/>',
-    '    <Paint Format="20"><!-- PaintComposite -->',
-    '      <SourcePaint Format="11"><!-- PaintColrGlyph -->',
-    '        <Glyph value="glyph00010"/>',
-    "      </SourcePaint>",
-    '      <CompositeMode value="src_over"/>',
-    '      <BackdropPaint Format="13"><!-- PaintVarTransform -->',
-    '        <Paint Format="11"><!-- PaintColrGlyph -->',
-    '          <Glyph value="glyph00010"/>',
-    "        </Paint>",
-    "        <Transform>",
-    '          <xx value="1.0"/>',
-    '          <yx value="0.0"/>',
-    '          <xy value="0.0"/>',
-    '          <yy value="1.0"/>',
-    '          <dx value="300.0"/>',
-    '          <dy value="0.0"/>',
-    "        </Transform>",
-    "      </BackdropPaint>",
-    "    </Paint>",
-    "  </BaseGlyphV1Record>",
-    '  <BaseGlyphV1Record index="2">',
-    '    <BaseGlyph value="glyph00015"/>',
-    '    <Paint Format="10"><!-- PaintGlyph -->',
-    '      <Paint Format="8"><!-- PaintSweepGradient -->',
-    "        <ColorLine>",
-    '          <Extend value="pad"/>',
-    "          <!-- StopCount=2 -->",
-    '          <ColorStop index="0">',
-    '            <StopOffset value="0.0"/>',
-    "            <Color>",
-    '              <PaletteIndex value="3"/>',
-    '              <Alpha value="1.0"/>',
-    "            </Color>",
-    "          </ColorStop>",
-    '          <ColorStop index="1">',
-    '            <StopOffset value="1.0"/>',
-    "            <Color>",
-    '              <PaletteIndex value="5"/>',
-    '              <Alpha value="1.0"/>',
-    "            </Color>",
-    "          </ColorStop>",
-    "        </ColorLine>",
-    '        <centerX value="259"/>',
-    '        <centerY value="300"/>',
-    '        <startAngle value="45.0"/>',
-    '        <endAngle value="135.0"/>',
-    "      </Paint>",
-    '      <Glyph value="glyph00011"/>',
-    "    </Paint>",
-    "  </BaseGlyphV1Record>",
-    "</BaseGlyphV1List>",
-    "<LayerV1List>",
-    "  <!-- LayerCount=4 -->",
-    '  <Paint index="0" Format="10"><!-- PaintGlyph -->',
-    '    <Paint Format="3"><!-- PaintVarSolid -->',
-    "      <Color>",
-    '        <PaletteIndex value="2"/>',
-    '        <Alpha value="0.5"/>',
-    "      </Color>",
-    "    </Paint>",
-    '    <Glyph value="glyph00011"/>',
-    "  </Paint>",
-    '  <Paint index="1" Format="10"><!-- PaintGlyph -->',
-    '    <Paint Format="4"><!-- PaintLinearGradient -->',
-    "      <ColorLine>",
-    '        <Extend value="repeat"/>',
-    "        <!-- StopCount=3 -->",
-    '        <ColorStop index="0">',
-    '          <StopOffset value="0.0"/>',
-    "          <Color>",
-    '            <PaletteIndex value="3"/>',
-    '            <Alpha value="1.0"/>',
-    "          </Color>",
-    "        </ColorStop>",
-    '        <ColorStop index="1">',
-    '          <StopOffset value="0.5"/>',
-    "          <Color>",
-    '            <PaletteIndex value="4"/>',
-    '            <Alpha value="1.0"/>',
-    "          </Color>",
-    "        </ColorStop>",
-    '        <ColorStop index="2">',
-    '          <StopOffset value="1.0"/>',
-    "          <Color>",
-    '            <PaletteIndex value="5"/>',
-    '            <Alpha value="1.0"/>',
-    "          </Color>",
-    "        </ColorStop>",
-    "      </ColorLine>",
-    '      <x0 value="1"/>',
-    '      <y0 value="2"/>',
-    '      <x1 value="-3"/>',
-    '      <y1 value="-4"/>',
-    '      <x2 value="5"/>',
-    '      <y2 value="6"/>',
-    "    </Paint>",
-    '    <Glyph value="glyph00012"/>',
-    "  </Paint>",
-    '  <Paint index="2" Format="10"><!-- PaintGlyph -->',
-    '    <Paint Format="12"><!-- PaintTransform -->',
-    '      <Paint Format="7"><!-- PaintVarRadialGradient -->',
-    "        <ColorLine>",
-    '          <Extend value="pad"/>',
-    "          <!-- StopCount=2 -->",
-    '          <ColorStop index="0">',
-    '            <StopOffset value="0.0"/>',
-    "            <Color>",
-    '              <PaletteIndex value="6"/>',
-    '              <Alpha value="1.0"/>',
-    "            </Color>",
-    "          </ColorStop>",
-    '          <ColorStop index="1">',
-    '            <StopOffset value="1.0"/>',
-    "            <Color>",
-    '              <PaletteIndex value="7"/>',
-    '              <Alpha value="0.4"/>',
-    "            </Color>",
-    "          </ColorStop>",
-    "        </ColorLine>",
-    '        <x0 value="7"/>',
-    '        <y0 value="8"/>',
-    '        <r0 value="9"/>',
-    '        <x1 value="10"/>',
-    '        <y1 value="11"/>',
-    '        <r1 value="12"/>',
-    "      </Paint>",
-    "      <Transform>",
-    '        <xx value="-13.0"/>',
-    '        <yx value="14.0"/>',
-    '        <xy value="15.0"/>',
-    '        <yy value="-17.0"/>',
-    '        <dx value="18.0"/>',
-    '        <dy value="19.0"/>',
-    "      </Transform>",
-    "    </Paint>",
-    '    <Glyph value="glyph00013"/>',
-    "  </Paint>",
-    '  <Paint index="3" Format="14"><!-- PaintTranslate -->',
-    '    <Paint Format="16"><!-- PaintRotate -->',
-    '      <Paint Format="18"><!-- PaintSkew -->',
-    '        <Paint Format="10"><!-- PaintGlyph -->',
-    '          <Paint Format="2"><!-- PaintSolid -->',
-    "            <Color>",
-    '              <PaletteIndex value="2"/>',
-    '              <Alpha value="0.5"/>',
-    "            </Color>",
-    "          </Paint>",
-    '          <Glyph value="glyph00011"/>',
-    "        </Paint>",
-    '        <xSkewAngle value="-11.0"/>',
-    '        <ySkewAngle value="5.0"/>',
-    '        <centerX value="253.0"/>',
-    '        <centerY value="254.0"/>',
-    "      </Paint>",
-    '      <angle value="45.0"/>',
-    '      <centerX value="255.0"/>',
-    '      <centerY value="256.0"/>',
-    "    </Paint>",
-    '    <dx value="257.0"/>',
-    '    <dy value="258.0"/>',
-    "  </Paint>",
-    "</LayerV1List>",
-]
-
-
-class COLR_V1_Test(object):
-    def test_decompile_and_compile(self, font):
-        colr = table_C_O_L_R_()
-        colr.decompile(COLR_V1_DATA, font)
-        diff_binary_fragments(colr.compile(font), COLR_V1_SAMPLE)
-
-    def test_decompile_and_dump_xml(self, font):
-        colr = table_C_O_L_R_()
-        colr.decompile(COLR_V1_DATA, font)
-
-        dump(colr, font)
-        assert getXML(colr.toXML, font) == COLR_V1_XML
-
-    def test_load_from_xml_and_compile(self, font):
-        colr = table_C_O_L_R_()
-        for name, attrs, content in parseXML(COLR_V1_XML):
-            colr.fromXML(name, attrs, content, font)
-        diff_binary_fragments(colr.compile(font), COLR_V1_SAMPLE)
-
-    def test_round_trip_xml(self, font):
-        colr = table_C_O_L_R_()
-        for name, attrs, content in parseXML(COLR_V1_XML):
-            colr.fromXML(name, attrs, content, font)
-        compiled = colr.compile(font)
-
-        colr = table_C_O_L_R_()
-        colr.decompile(compiled, font)
-        assert getXML(colr.toXML, font) == COLR_V1_XML
diff --git a/Tests/ttLib/tables/C_P_A_L_test.py b/Tests/ttLib/tables/C_P_A_L_test.py
index 10c8ea0..bacd4a8 100644
--- a/Tests/ttLib/tables/C_P_A_L_test.py
+++ b/Tests/ttLib/tables/C_P_A_L_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import getXML, parseXML
 from fontTools.misc.textTools import deHexStr
 from fontTools.ttLib import getTableModule, newTable
@@ -65,6 +67,9 @@
         self.assertEqual(cpal.numPaletteEntries, 2)
         self.assertEqual(repr(cpal.palettes),
                          '[[#000000FF, #66CCFFFF], [#000000FF, #800000FF]]')
+        self.assertEqual(cpal.paletteLabels, [0, 0])
+        self.assertEqual(cpal.paletteTypes, [0, 0])
+        self.assertEqual(cpal.paletteEntryLabels, [0, 0])
 
     def test_decompile_v0_sharingColors(self):
         cpal = newTable('CPAL')
@@ -76,6 +81,9 @@
             '[#223344FF, #99887711, #55555555]',
             '[#223344FF, #99887711, #FFFFFFFF]',
             '[#223344FF, #99887711, #55555555]'])
+        self.assertEqual(cpal.paletteLabels, [0, 0, 0, 0])
+        self.assertEqual(cpal.paletteTypes, [0, 0, 0, 0])
+        self.assertEqual(cpal.paletteEntryLabels, [0, 0, 0])
 
     def test_decompile_v1_noLabelsNoTypes(self):
         cpal = newTable('CPAL')
@@ -85,10 +93,9 @@
         self.assertEqual([repr(p) for p in cpal.palettes], [
             '[#CAFECAFE, #22110033, #66554477]',  # RGBA
             '[#59413127, #42424242, #13330037]'])
-        self.assertEqual(cpal.paletteLabels, [cpal.NO_NAME_ID] * len(cpal.palettes))
+        self.assertEqual(cpal.paletteLabels, [0, 0])
         self.assertEqual(cpal.paletteTypes, [0, 0])
-        self.assertEqual(cpal.paletteEntryLabels,
-                        [cpal.NO_NAME_ID] * cpal.numPaletteEntries)
+        self.assertEqual(cpal.paletteEntryLabels, [0, 0, 0])
 
     def test_decompile_v1(self):
         cpal = newTable('CPAL')
@@ -188,6 +195,9 @@
         self.assertEqual(cpal.version, 0)
         self.assertEqual(cpal.numPaletteEntries, 2)
         self.assertEqual(repr(cpal.palettes), '[[#12345678, #FEDCBA98]]')
+        self.assertEqual(cpal.paletteLabels, [0])
+        self.assertEqual(cpal.paletteTypes, [0])
+        self.assertEqual(cpal.paletteEntryLabels, [0, 0])
 
     def test_fromXML_v1(self):
         cpal = newTable('CPAL')
@@ -209,8 +219,7 @@
                          '[[#12345678, #FEDCBA98, #CAFECAFE]]')
         self.assertEqual(cpal.paletteLabels, [259])
         self.assertEqual(cpal.paletteTypes, [2])
-        self.assertEqual(cpal.paletteEntryLabels,
-                        [cpal.NO_NAME_ID, 262, cpal.NO_NAME_ID])
+        self.assertEqual(cpal.paletteEntryLabels, [0, 262, 0])
 
 
 if __name__ == "__main__":
diff --git a/Tests/ttLib/tables/M_V_A_R_test.py b/Tests/ttLib/tables/M_V_A_R_test.py
index 3972d8c..05a92e8 100644
--- a/Tests/ttLib/tables/M_V_A_R_test.py
+++ b/Tests/ttLib/tables/M_V_A_R_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import FakeFont, getXML, parseXML
 from fontTools.misc.textTools import deHexStr, hexStr
 from fontTools.ttLib.tables._f_v_a_r import Axis
diff --git a/Tests/ttLib/tables/O_S_2f_2_test.py b/Tests/ttLib/tables/O_S_2f_2_test.py
index 1f12309..116e82e 100644
--- a/Tests/ttLib/tables/O_S_2f_2_test.py
+++ b/Tests/ttLib/tables/O_S_2f_2_test.py
@@ -1,3 +1,4 @@
+from __future__ import print_function, division, absolute_import
 from fontTools.ttLib import TTFont, newTable, getTableModule
 from fontTools.ttLib.tables.O_S_2f_2 import *
 import unittest
diff --git a/Tests/ttLib/tables/S_T_A_T_test.py b/Tests/ttLib/tables/S_T_A_T_test.py
index c5c1234..e851f98 100644
--- a/Tests/ttLib/tables/S_T_A_T_test.py
+++ b/Tests/ttLib/tables/S_T_A_T_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import FakeFont, getXML, parseXML
 from fontTools.misc.textTools import deHexStr
 from fontTools.ttLib import newTable
@@ -146,7 +148,7 @@
     '<AxisValueArray>',
     '  <AxisValue index="0" Format="3">',
     '    <AxisIndex value="0"/>',
-    '    <Flags value="2"/>  <!-- ElidableAxisValueName -->',
+    '    <Flags value="2"/>',
     '    <ValueNameID value="2"/>',
     '    <Value value="400.0"/>',
     '    <LinkedValue value="700.0"/>',
@@ -190,7 +192,7 @@
     '<AxisValueArray>',
     '  <AxisValue index="0" Format="3">',
     '    <AxisIndex value="0"/>',
-    '    <Flags value="2"/>  <!-- ElidableAxisValueName -->',
+    '    <Flags value="2"/>',
     '    <ValueNameID value="2"/>',
     '    <Value value="400.0"/>',
     '    <LinkedValue value="700.0"/>',
diff --git a/Tests/ttLib/tables/T_S_I__0_test.py b/Tests/ttLib/tables/T_S_I__0_test.py
index 44ca44e..1de6b34 100644
--- a/Tests/ttLib/tables/T_S_I__0_test.py
+++ b/Tests/ttLib/tables/T_S_I__0_test.py
@@ -1,4 +1,5 @@
-from types import SimpleNamespace
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import SimpleNamespace
 from fontTools.misc.textTools import deHexStr
 from fontTools.misc.testTools import getXML
 from fontTools.ttLib.tables.T_S_I__0 import table_T_S_I__0
diff --git a/Tests/ttLib/tables/T_S_I__1_test.py b/Tests/ttLib/tables/T_S_I__1_test.py
index 3a565ad..e529425 100644
--- a/Tests/ttLib/tables/T_S_I__1_test.py
+++ b/Tests/ttLib/tables/T_S_I__1_test.py
@@ -1,4 +1,7 @@
-from fontTools.misc.py23 import tobytes
+from __future__ import (
+    print_function, division, absolute_import, unicode_literals
+)
+from fontTools.misc.py23 import unichr, tobytes
 from fontTools.misc.loggingTools import CapturingLogHandler
 from fontTools.ttLib import TTFont, TTLibError
 from fontTools.ttLib.tables.T_S_I__0 import table_T_S_I__0
@@ -33,7 +36,7 @@
     # ['a', 'b', 'c', ...]
     ch = 0x61
     n = len(indextable.indices)
-    font.glyphOrder = [chr(i) for i in range(ch, ch+n)]
+    font.glyphOrder = [unichr(i) for i in range(ch, ch+n)]
     font['TSI0'] = indextable
     return font
 
diff --git a/Tests/ttLib/tables/TupleVariation_test.py b/Tests/ttLib/tables/TupleVariation_test.py
index d7a0bc8..d78810a 100644
--- a/Tests/ttLib/tables/TupleVariation_test.py
+++ b/Tests/ttLib/tables/TupleVariation_test.py
@@ -1,3 +1,6 @@
+from __future__ import \
+	print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.loggingTools import CapturingLogHandler
 from fontTools.misc.testTools import parseXML
 from fontTools.misc.textTools import deHexStr, hexStr
@@ -5,7 +8,6 @@
 from fontTools.ttLib.tables.TupleVariation import \
 	log, TupleVariation, compileSharedTuples, decompileSharedTuples, \
 	compileTupleVariationStore, decompileTupleVariationStore, inferRegion_
-from io import BytesIO
 import random
 import unittest
 
@@ -16,9 +18,9 @@
 
 
 AXES = {
-	"wdth": (0.25, 0.375, 0.5),
+	"wdth": (0.3, 0.4, 0.5),
 	"wght": (0.0, 1.0, 1.0),
-	"opsz": (-0.75, -0.75, 0.0)
+	"opsz": (-0.7, -0.7, 0.0)
 }
 
 
@@ -112,7 +114,7 @@
 		self.assertIn("bad delta format", [r.msg for r in captor.records])
 		self.assertEqual([
 			'<tuple>',
-			  '<coord axis="wdth" min="0.25" value="0.375" max="0.5"/>',
+			  '<coord axis="wdth" min="0.3" value="0.4" max="0.5"/>',
 			  '<!-- bad delta #0 -->',
 			'</tuple>',
 		], TupleVariationTest.xml_lines(writer))
@@ -123,9 +125,9 @@
 		g.toXML(writer, ["wdth", "wght", "opsz"])
 		self.assertEqual([
 			'<tuple>',
-			  '<coord axis="wdth" min="0.25" value="0.375" max="0.5"/>',
+			  '<coord axis="wdth" min="0.3" value="0.4" max="0.5"/>',
 			  '<coord axis="wght" value="1.0"/>',
-			  '<coord axis="opsz" value="-0.75"/>',
+			  '<coord axis="opsz" value="-0.7"/>',
 			  '<delta cvt="0" value="42"/>',
 			  '<delta cvt="2" value="23"/>',
 			  '<delta cvt="3" value="0"/>',
@@ -139,9 +141,9 @@
 		g.toXML(writer, ["wdth", "wght", "opsz"])
 		self.assertEqual([
 			'<tuple>',
-			  '<coord axis="wdth" min="0.25" value="0.375" max="0.5"/>',
+			  '<coord axis="wdth" min="0.3" value="0.4" max="0.5"/>',
 			  '<coord axis="wght" value="1.0"/>',
-			  '<coord axis="opsz" value="-0.75"/>',
+			  '<coord axis="opsz" value="-0.7"/>',
 			  '<delta pt="0" x="9" y="8"/>',
 			  '<delta pt="2" x="7" y="6"/>',
 			  '<delta pt="3" x="0" y="0"/>',
@@ -161,22 +163,6 @@
 			'</tuple>'
 		], TupleVariationTest.xml_lines(writer))
 
-	def test_toXML_axes_floats(self):
-		writer = XMLWriter(BytesIO())
-		axes = {
-			"wght": (0.0, 0.2999878, 0.7000122),
-			"wdth": (0.0, 0.4000244, 0.4000244),
-		}
-		g = TupleVariation(axes, [None] * 5)
-		g.toXML(writer, ["wght", "wdth"])
-		self.assertEqual(
-			[
-				'<coord axis="wght" min="0.0" value="0.3" max="0.7"/>',
-				'<coord axis="wdth" value="0.4"/>',
-			],
-			TupleVariationTest.xml_lines(writer)[1:3]
-		)
-
 	def test_fromXML_badDeltaFormat(self):
 		g = TupleVariation({}, [])
 		with CapturingLogHandler(log, "WARNING") as captor:
@@ -188,9 +174,9 @@
 	def test_fromXML_constants(self):
 		g = TupleVariation({}, [None] * 4)
 		for name, attrs, content in parseXML(
-				'<coord axis="wdth" min="0.25" value="0.375" max="0.5"/>'
+				'<coord axis="wdth" min="0.3" value="0.4" max="0.5"/>'
 				'<coord axis="wght" value="1.0"/>'
-				'<coord axis="opsz" value="-0.75"/>'
+				'<coord axis="opsz" value="-0.7"/>'
 				'<delta cvt="1" value="42"/>'
 				'<delta cvt="2" value="-23"/>'):
 			g.fromXML(name, attrs, content)
@@ -200,31 +186,15 @@
 	def test_fromXML_points(self):
 		g = TupleVariation({}, [None] * 4)
 		for name, attrs, content in parseXML(
-				'<coord axis="wdth" min="0.25" value="0.375" max="0.5"/>'
+				'<coord axis="wdth" min="0.3" value="0.4" max="0.5"/>'
 				'<coord axis="wght" value="1.0"/>'
-				'<coord axis="opsz" value="-0.75"/>'
+				'<coord axis="opsz" value="-0.7"/>'
 				'<delta pt="1" x="33" y="44"/>'
 				'<delta pt="2" x="-2" y="170"/>'):
 			g.fromXML(name, attrs, content)
 		self.assertEqual(AXES, g.axes)
 		self.assertEqual([None, (33, 44), (-2, 170), None], g.coordinates)
 
-	def test_fromXML_axes_floats(self):
-		g = TupleVariation({}, [None] * 4)
-		for name, attrs, content in parseXML(
-			'<coord axis="wght" min="0.0" value="0.3" max="0.7"/>'
-			'<coord axis="wdth" value="0.4"/>'
-		):
-			g.fromXML(name, attrs, content)
-
-		self.assertEqual(g.axes["wght"][0], 0)
-		self.assertAlmostEqual(g.axes["wght"][1], 0.2999878)
-		self.assertAlmostEqual(g.axes["wght"][2], 0.7000122)
-
-		self.assertEqual(g.axes["wdth"][0], 0)
-		self.assertAlmostEqual(g.axes["wdth"][1], 0.4000244)
-		self.assertAlmostEqual(g.axes["wdth"][2], 0.4000244)
-
 	def test_compile_sharedPeaks_nonIntermediate_sharedPoints(self):
 		var = TupleVariation(
 			{"wght": (0.0, 0.5, 0.5), "wdth": (0.0, 0.8, 0.8)},
diff --git a/Tests/ttLib/tables/_a_n_k_r_test.py b/Tests/ttLib/tables/_a_n_k_r_test.py
index 6c9be16..0327e46 100644
--- a/Tests/ttLib/tables/_a_n_k_r_test.py
+++ b/Tests/ttLib/tables/_a_n_k_r_test.py
@@ -1,4 +1,6 @@
 # coding: utf-8
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import FakeFont, getXML, parseXML
 from fontTools.misc.textTools import deHexStr, hexStr
 from fontTools.ttLib import newTable
diff --git a/Tests/ttLib/tables/_a_v_a_r_test.py b/Tests/ttLib/tables/_a_v_a_r_test.py
index 429ca2e..7b92118 100644
--- a/Tests/ttLib/tables/_a_v_a_r_test.py
+++ b/Tests/ttLib/tables/_a_v_a_r_test.py
@@ -1,10 +1,13 @@
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import parseXML
 from fontTools.misc.textTools import deHexStr
 from fontTools.misc.xmlWriter import XMLWriter
 from fontTools.ttLib import TTLibError
 from fontTools.ttLib.tables._a_v_a_r import table__a_v_a_r
 from fontTools.ttLib.tables._f_v_a_r import table__f_v_a_r, Axis
-from io import BytesIO
+import collections
+import logging
 import unittest
 
 
@@ -15,17 +18,6 @@
 
 
 class AxisVariationTableTest(unittest.TestCase):
-    def assertAvarAlmostEqual(self, segments1, segments2):
-        self.assertSetEqual(set(segments1.keys()), set(segments2.keys()))
-        for axisTag, mapping1 in segments1.items():
-            mapping2 = segments2[axisTag]
-            self.assertEqual(len(mapping1), len(mapping2))
-            for (k1, v1), (k2, v2) in zip(
-                sorted(mapping1.items()), sorted(mapping2.items())
-            ):
-                self.assertAlmostEqual(k1, k2)
-                self.assertAlmostEqual(v1, v2)
-
     def test_compile(self):
         avar = table__a_v_a_r()
         avar.segments["wdth"] = {-1.0: -1.0, 0.0: 0.0, 0.3: 0.8, 1.0: 1.0}
@@ -35,8 +27,8 @@
     def test_decompile(self):
         avar = table__a_v_a_r()
         avar.decompile(TEST_DATA, self.makeFont(["wdth", "wght"]))
-        self.assertAvarAlmostEqual({
-            "wdth": {-1.0: -1.0, 0.0: 0.0, 0.2999878: 0.7999878, 1.0: 1.0},
+        self.assertEqual({
+            "wdth": {-1.0: -1.0, 0.0: 0.0, 0.3: 0.8, 1.0: 1.0},
             "wght": {-1.0: -1.0, 0.0: 0.0, 1.0: 1.0}
         }, avar.segments)
 
@@ -47,7 +39,7 @@
 
     def test_toXML(self):
         avar = table__a_v_a_r()
-        avar.segments["opsz"] = {-1.0: -1.0, 0.0: 0.0, 0.2999878: 0.7999878, 1.0: 1.0}
+        avar.segments["opsz"] = {-1.0: -1.0, 0.0: 0.0, 0.3: 0.8, 1.0: 1.0}
         writer = XMLWriter(BytesIO())
         avar.toXML(writer, self.makeFont(["opsz"]))
         self.assertEqual([
@@ -69,10 +61,8 @@
                 '    <mapping from="1.0" to="1.0"/>'
                 '</segment>'):
             avar.fromXML(name, attrs, content, ttFont=None)
-        self.assertAvarAlmostEqual(
-            {"wdth": {-1: -1, 0: 0, 0.7000122: 0.2000122, 1.0: 1.0}},
-            avar.segments
-        )
+        self.assertEqual({"wdth": {-1: -1, 0: 0, 0.7: 0.2, 1.0: 1.0}},
+                         avar.segments)
 
     @staticmethod
     def makeFont(axisTags):
diff --git a/Tests/ttLib/tables/_b_s_l_n_test.py b/Tests/ttLib/tables/_b_s_l_n_test.py
index e40c1bd..97ffa6a 100644
--- a/Tests/ttLib/tables/_b_s_l_n_test.py
+++ b/Tests/ttLib/tables/_b_s_l_n_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import FakeFont, getXML, parseXML
 from fontTools.misc.textTools import deHexStr, hexStr
 from fontTools.ttLib import newTable
diff --git a/Tests/ttLib/tables/_c_i_d_g_test.py b/Tests/ttLib/tables/_c_i_d_g_test.py
index 11c1fc0..c6e8d3c 100644
--- a/Tests/ttLib/tables/_c_i_d_g_test.py
+++ b/Tests/ttLib/tables/_c_i_d_g_test.py
@@ -1,3 +1,6 @@
+# coding: utf-8
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import FakeFont, getXML, parseXML
 from fontTools.misc.textTools import deHexStr, hexStr
 from fontTools.ttLib import newTable
diff --git a/Tests/ttLib/tables/_c_m_a_p_test.py b/Tests/ttLib/tables/_c_m_a_p_test.py
index 6328504..233cd14 100644
--- a/Tests/ttLib/tables/_c_m_a_p_test.py
+++ b/Tests/ttLib/tables/_c_m_a_p_test.py
@@ -1,6 +1,8 @@
+from __future__ import print_function, division, absolute_import, unicode_literals
 import io
 import os
 import re
+from fontTools.misc.py23 import *
 from fontTools import ttLib
 from fontTools.fontBuilder import FontBuilder
 import unittest
diff --git a/Tests/ttLib/tables/_c_v_a_r_test.py b/Tests/ttLib/tables/_c_v_a_r_test.py
index 31c1953..0fd5531 100644
--- a/Tests/ttLib/tables/_c_v_a_r_test.py
+++ b/Tests/ttLib/tables/_c_v_a_r_test.py
@@ -1,3 +1,6 @@
+from __future__ import \
+    print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import getXML, parseXML
 from fontTools.misc.textTools import deHexStr, hexStr
 from fontTools.ttLib import TTLibError, getTableModule, newTable
@@ -50,23 +53,12 @@
 
 CVAR_VARIATIONS = [
     TupleVariation({"wght": (0.0, 1.0, 1.0)}, [None, None, 3, 1, 4]),
-    TupleVariation({"wght": (-1, -1.0, 0.0), "wdth": (0.0, 0.7999878, 0.7999878)},
+    TupleVariation({"wght": (-1, -1.0, 0.0), "wdth": (0.0, 0.8, 0.8)},
                    [None, None, 9, 7, 8]),
 ]
 
 
 class CVARTableTest(unittest.TestCase):
-    def assertVariationsAlmostEqual(self, variations1, variations2):
-        self.assertEqual(len(variations1), len(variations2))
-        for (v1, v2) in zip(variations1, variations2):
-            self.assertSetEqual(set(v1.axes), set(v2.axes))
-            for axisTag, support1 in v1.axes.items():
-                support2 = v2.axes[axisTag]
-                self.assertEqual(len(support1), len(support2))
-                for s1, s2 in zip(support1, support2):
-                    self.assertAlmostEqual(s1, s2)
-                self.assertEqual(v1.coordinates, v2.coordinates)
-
     def makeFont(self):
         cvt, cvar, fvar = newTable("cvt "), newTable("cvar"), newTable("fvar")
         font = {"cvt ": cvt, "cvar": cvar, "fvar": fvar}
@@ -91,14 +83,14 @@
         cvar.decompile(CVAR_PRIVATE_POINT_DATA, font)
         self.assertEqual(cvar.majorVersion, 1)
         self.assertEqual(cvar.minorVersion, 0)
-        self.assertVariationsAlmostEqual(cvar.variations, CVAR_VARIATIONS)
+        self.assertEqual(cvar.variations, CVAR_VARIATIONS)
 
     def test_decompile_shared_points(self):
         font, cvar = self.makeFont()
         cvar.decompile(CVAR_DATA, font)
         self.assertEqual(cvar.majorVersion, 1)
         self.assertEqual(cvar.minorVersion, 0)
-        self.assertVariationsAlmostEqual(cvar.variations, CVAR_VARIATIONS)
+        self.assertEqual(cvar.variations, CVAR_VARIATIONS)
 
     def test_fromXML(self):
         font, cvar = self.makeFont()
@@ -106,7 +98,7 @@
             cvar.fromXML(name, attrs, content, ttFont=font)
         self.assertEqual(cvar.majorVersion, 1)
         self.assertEqual(cvar.minorVersion, 0)
-        self.assertVariationsAlmostEqual(cvar.variations, CVAR_VARIATIONS)
+        self.assertEqual(cvar.variations, CVAR_VARIATIONS)
 
     def test_toXML(self):
         font, cvar = self.makeFont()
diff --git a/Tests/ttLib/tables/_f_p_g_m_test.py b/Tests/ttLib/tables/_f_p_g_m_test.py
index ff233dd..71fec48 100644
--- a/Tests/ttLib/tables/_f_p_g_m_test.py
+++ b/Tests/ttLib/tables/_f_p_g_m_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.ttLib.tables._f_p_g_m import table__f_p_g_m
 from fontTools.ttLib.tables import ttProgram
 
diff --git a/Tests/ttLib/tables/_f_v_a_r_test.py b/Tests/ttLib/tables/_f_v_a_r_test.py
index 2ac5237..4a8e767 100644
--- a/Tests/ttLib/tables/_f_v_a_r_test.py
+++ b/Tests/ttLib/tables/_f_v_a_r_test.py
@@ -1,10 +1,11 @@
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import parseXML
 from fontTools.misc.textTools import deHexStr
 from fontTools.misc.xmlWriter import XMLWriter
 from fontTools.ttLib import TTLibError
 from fontTools.ttLib.tables._f_v_a_r import table__f_v_a_r, Axis, NamedInstance
 from fontTools.ttLib.tables._n_a_m_e import table__n_a_m_e, NameRecord
-from io import BytesIO
 import unittest
 
 
@@ -119,7 +120,7 @@
         self.assertEqual("opsz", axis.axisTag)
         self.assertEqual(345, axis.axisNameID)
         self.assertEqual(-0.5, axis.minValue)
-        self.assertAlmostEqual(1.3000031, axis.defaultValue)
+        self.assertEqual(1.3, axis.defaultValue)
         self.assertEqual(1.5, axis.maxValue)
 
     def test_toXML(self):
@@ -165,11 +166,6 @@
 
 
 class NamedInstanceTest(unittest.TestCase):
-    def assertDictAlmostEqual(self, dict1, dict2):
-        self.assertEqual(set(dict1.keys()), set(dict2.keys()))
-        for key in dict1:
-            self.assertAlmostEqual(dict1[key], dict2[key])
-
     def test_compile_withPostScriptName(self):
         inst = NamedInstance()
         inst.subfamilyNameID = 345
@@ -191,14 +187,14 @@
         inst.decompile(FVAR_INSTANCE_DATA_WITH_PSNAME, ["wght", "wdth"])
         self.assertEqual(564, inst.postscriptNameID)
         self.assertEqual(345, inst.subfamilyNameID)
-        self.assertDictAlmostEqual({"wght": 0.6999969, "wdth": 0.5}, inst.coordinates)
+        self.assertEqual({"wght": 0.7, "wdth": 0.5}, inst.coordinates)
 
     def test_decompile_withoutPostScriptName(self):
         inst = NamedInstance()
         inst.decompile(FVAR_INSTANCE_DATA_WITHOUT_PSNAME, ["wght", "wdth"])
         self.assertEqual(0xFFFF, inst.postscriptNameID)
         self.assertEqual(345, inst.subfamilyNameID)
-        self.assertDictAlmostEqual({"wght": 0.6999969, "wdth": 0.5}, inst.coordinates)
+        self.assertEqual({"wght": 0.7, "wdth": 0.5}, inst.coordinates)
 
     def test_toXML_withPostScriptName(self):
         font = MakeFont()
@@ -248,7 +244,7 @@
             inst.fromXML(name, attrs, content, ttFont=MakeFont())
         self.assertEqual(257, inst.postscriptNameID)
         self.assertEqual(345, inst.subfamilyNameID)
-        self.assertDictAlmostEqual({"wght": 0.6999969, "wdth": 0.5}, inst.coordinates)
+        self.assertEqual({"wght": 0.7, "wdth": 0.5}, inst.coordinates)
 
     def test_fromXML_withoutPostScriptName(self):
         inst = NamedInstance()
@@ -260,7 +256,7 @@
             inst.fromXML(name, attrs, content, ttFont=MakeFont())
         self.assertEqual(0x123ABC, inst.flags)
         self.assertEqual(345, inst.subfamilyNameID)
-        self.assertDictAlmostEqual({"wght": 0.6999969, "wdth": 0.5}, inst.coordinates)
+        self.assertEqual({"wght": 0.7, "wdth": 0.5}, inst.coordinates)
 
 
 if __name__ == "__main__":
diff --git a/Tests/ttLib/tables/_g_c_i_d_test.py b/Tests/ttLib/tables/_g_c_i_d_test.py
index e766677..1ec92fb 100644
--- a/Tests/ttLib/tables/_g_c_i_d_test.py
+++ b/Tests/ttLib/tables/_g_c_i_d_test.py
@@ -1,3 +1,6 @@
+# coding: utf-8
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import FakeFont, getXML, parseXML
 from fontTools.misc.textTools import deHexStr, hexStr
 from fontTools.ttLib import newTable
diff --git a/Tests/ttLib/tables/_g_l_y_f_test.py b/Tests/ttLib/tables/_g_l_y_f_test.py
index 531bb82..b30528a 100644
--- a/Tests/ttLib/tables/_g_l_y_f_test.py
+++ b/Tests/ttLib/tables/_g_l_y_f_test.py
@@ -1,25 +1,12 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.fixedTools import otRound
-from fontTools.misc.testTools import getXML, parseXML
 from fontTools.pens.ttGlyphPen import TTGlyphPen
-from fontTools.pens.recordingPen import RecordingPen, RecordingPointPen
-from fontTools.pens.pointPen import PointToSegmentPen
 from fontTools.ttLib import TTFont, newTable, TTLibError
-from fontTools.ttLib.tables._g_l_y_f import (
-    Glyph,
-    GlyphCoordinates,
-    GlyphComponent,
-    ARGS_ARE_XY_VALUES,
-    SCALED_COMPONENT_OFFSET,
-    UNSCALED_COMPONENT_OFFSET,
-    WE_HAVE_A_SCALE,
-    WE_HAVE_A_TWO_BY_TWO,
-    WE_HAVE_AN_X_AND_Y_SCALE,
-)
+from fontTools.ttLib.tables._g_l_y_f import GlyphCoordinates
 from fontTools.ttLib.tables import ttProgram
 import sys
 import array
-from io import StringIO
-import itertools
 import pytest
 import re
 import os
@@ -193,7 +180,7 @@
     return re.sub(' ttLibVersion=".*"', '', string)
 
 
-class GlyfTableTest(unittest.TestCase):
+class glyfTableTest(unittest.TestCase):
 
     def __init__(self, methodName):
         unittest.TestCase.__init__(self, methodName)
@@ -225,7 +212,7 @@
         font['head'].decompile(self.headData, font)
         font['loca'].decompile(self.locaData, font)
         glyfTable.decompile(self.glyfData, font)
-        out = StringIO()
+        out = UnicodeIO()
         font.saveXML(out)
         glyfXML = strip_ttLibVersion(out.getvalue()).splitlines()
         self.assertEqual(glyfXML, self.glyfXML)
@@ -289,353 +276,6 @@
 
         composite.compact(glyfTable)
 
-    def test_bit6_draw_to_pen_issue1771(self):
-        # https://github.com/fonttools/fonttools/issues/1771
-        font = TTFont(sfntVersion="\x00\x01\x00\x00")
-        # glyph00003 contains a bit 6 flag on the first point,
-        # which triggered the issue
-        font.importXML(GLYF_TTX)
-        glyfTable = font['glyf']
-        pen = RecordingPen()
-        glyfTable["glyph00003"].draw(pen, glyfTable=glyfTable)
-        expected = [('moveTo', ((501, 1430),)),
-                    ('lineTo', ((683, 1430),)),
-                    ('lineTo', ((1172, 0),)),
-                    ('lineTo', ((983, 0),)),
-                    ('lineTo', ((591, 1193),)),
-                    ('lineTo', ((199, 0),)),
-                    ('lineTo', ((12, 0),)),
-                    ('closePath', ()),
-                    ('moveTo', ((249, 514),)),
-                    ('lineTo', ((935, 514),)),
-                    ('lineTo', ((935, 352),)),
-                    ('lineTo', ((249, 352),)),
-                    ('closePath', ())]
-        self.assertEqual(pen.value, expected)
-
-    def test_bit6_draw_to_pointpen(self):
-        # https://github.com/fonttools/fonttools/issues/1771
-        font = TTFont(sfntVersion="\x00\x01\x00\x00")
-        # glyph00003 contains a bit 6 flag on the first point
-        # which triggered the issue
-        font.importXML(GLYF_TTX)
-        glyfTable = font['glyf']
-        pen = RecordingPointPen()
-        glyfTable["glyph00003"].drawPoints(pen, glyfTable=glyfTable)
-        expected = [
-            ('beginPath', (), {}),
-            ('addPoint', ((501, 1430), 'line', False, None), {}),
-            ('addPoint', ((683, 1430), 'line', False, None), {}),
-            ('addPoint', ((1172, 0), 'line', False, None), {}),
-            ('addPoint', ((983, 0), 'line', False, None), {}),
-        ]
-        self.assertEqual(pen.value[:len(expected)], expected)
-
-    def test_draw_vs_drawpoints(self):
-        font = TTFont(sfntVersion="\x00\x01\x00\x00")
-        font.importXML(GLYF_TTX)
-        glyfTable = font['glyf']
-        pen1 = RecordingPen()
-        pen2 = RecordingPen()
-        glyfTable["glyph00003"].draw(pen1, glyfTable)
-        glyfTable["glyph00003"].drawPoints(PointToSegmentPen(pen2), glyfTable)
-        self.assertEqual(pen1.value, pen2.value)
-
-    def test_compile_empty_table(self):
-        font = TTFont(sfntVersion="\x00\x01\x00\x00")
-        font.importXML(GLYF_TTX)
-        glyfTable = font['glyf']
-        # set all glyphs to zero contours
-        glyfTable.glyphs = {glyphName: Glyph() for glyphName in font.getGlyphOrder()}
-        glyfData = glyfTable.compile(font)
-        self.assertEqual(glyfData, b"\x00")
-        self.assertEqual(list(font["loca"]), [0] * (font["maxp"].numGlyphs+1))
-
-    def test_decompile_empty_table(self):
-        font = TTFont()
-        glyphNames = [".notdef", "space"]
-        font.setGlyphOrder(glyphNames)
-        font["loca"] = newTable("loca")
-        font["loca"].locations = [0] * (len(glyphNames) + 1)
-        font["glyf"] = newTable("glyf")
-        font["glyf"].decompile(b"\x00", font)
-        self.assertEqual(len(font["glyf"]), 2)
-        self.assertEqual(font["glyf"][".notdef"].numberOfContours, 0)
-        self.assertEqual(font["glyf"]["space"].numberOfContours, 0)
-
-
-class GlyphTest:
-
-    def test_getCoordinates(self):
-        glyphSet = {}
-        pen = TTGlyphPen(glyphSet)
-        pen.moveTo((0, 0))
-        pen.lineTo((100, 0))
-        pen.lineTo((100, 100))
-        pen.lineTo((0, 100))
-        pen.closePath()
-        # simple contour glyph
-        glyphSet["a"] = a = pen.glyph()
-
-        assert a.getCoordinates(glyphSet) == (
-            GlyphCoordinates([(0, 0), (100, 0), (100, 100), (0, 100)]),
-            [3],
-            array.array("B", [1, 1, 1, 1]),
-        )
-
-        # composite glyph with only XY offset
-        pen = TTGlyphPen(glyphSet)
-        pen.addComponent("a", (1, 0, 0, 1, 10, 20))
-        glyphSet["b"] = b = pen.glyph()
-
-        assert b.getCoordinates(glyphSet) == (
-            GlyphCoordinates([(10, 20), (110, 20), (110, 120), (10, 120)]),
-            [3],
-            array.array("B", [1, 1, 1, 1]),
-        )
-
-        # composite glyph with a scale (and referencing another composite glyph)
-        pen = TTGlyphPen(glyphSet)
-        pen.addComponent("b", (0.5, 0, 0, 0.5, 0, 0))
-        glyphSet["c"] = c = pen.glyph()
-
-        assert c.getCoordinates(glyphSet) == (
-            GlyphCoordinates([(5, 10), (55, 10), (55, 60), (5, 60)]),
-            [3],
-            array.array("B", [1, 1, 1, 1]),
-        )
-
-        # composite glyph with unscaled offset (MS-style)
-        pen = TTGlyphPen(glyphSet)
-        pen.addComponent("a", (0.5, 0, 0, 0.5, 10, 20))
-        glyphSet["d"] = d = pen.glyph()
-        d.components[0].flags |= UNSCALED_COMPONENT_OFFSET
-
-        assert d.getCoordinates(glyphSet) == (
-            GlyphCoordinates([(10, 20), (60, 20), (60, 70), (10, 70)]),
-            [3],
-            array.array("B", [1, 1, 1, 1]),
-        )
-
-        # composite glyph with a scaled offset (Apple-style)
-        pen = TTGlyphPen(glyphSet)
-        pen.addComponent("a", (0.5, 0, 0, 0.5, 10, 20))
-        glyphSet["e"] = e = pen.glyph()
-        e.components[0].flags |= SCALED_COMPONENT_OFFSET
-
-        assert e.getCoordinates(glyphSet) == (
-            GlyphCoordinates([(5, 10), (55, 10), (55, 60), (5, 60)]),
-            [3],
-            array.array("B", [1, 1, 1, 1]),
-        )
-
-        # composite glyph where the 2nd and 3rd components use anchor points
-        pen = TTGlyphPen(glyphSet)
-        pen.addComponent("a", (1, 0, 0, 1, 0, 0))
-        glyphSet["f"] = f = pen.glyph()
-
-        comp1 = GlyphComponent()
-        comp1.glyphName = "a"
-        # aling the new component's pt 0 to pt 2 of contour points added so far
-        comp1.firstPt = 2
-        comp1.secondPt = 0
-        comp1.flags = 0
-        f.components.append(comp1)
-
-        comp2 = GlyphComponent()
-        comp2.glyphName = "a"
-        # aling the new component's pt 0 to pt 6 of contour points added so far
-        comp2.firstPt = 6
-        comp2.secondPt = 0
-        comp2.transform = [[0.707107, 0.707107], [-0.707107, 0.707107]]  # rotate 45 deg
-        comp2.flags = WE_HAVE_A_TWO_BY_TWO
-        f.components.append(comp2)
-
-        coords, end_pts, flags = f.getCoordinates(glyphSet)
-        assert end_pts == [3, 7, 11]
-        assert flags == array.array("B", [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
-        assert list(sum(coords, ())) == pytest.approx(
-            [
-                0, 0,
-                100, 0,
-                100, 100,
-                0, 100,
-                100, 100,
-                200, 100,
-                200, 200,
-                100, 200,
-                200, 200,
-                270.7107, 270.7107,
-                200.0, 341.4214,
-                129.2893, 270.7107,
-            ]
-        )
-
-    def test_getCompositeMaxpValues(self):
-        # https://github.com/fonttools/fonttools/issues/2044
-        glyphSet = {}
-        pen = TTGlyphPen(glyphSet)  # empty non-composite glyph
-        glyphSet["fraction"] = pen.glyph()
-        glyphSet["zero.numr"] = pen.glyph()
-        pen = TTGlyphPen(glyphSet)
-        pen.addComponent("zero.numr", (1, 0, 0, 1, 0, 0))
-        glyphSet["zero.dnom"] = pen.glyph()
-        pen = TTGlyphPen(glyphSet)
-        pen.addComponent("zero.numr", (1, 0, 0, 1, 0, 0))
-        pen.addComponent("fraction", (1, 0, 0, 1, 0, 0))
-        pen.addComponent("zero.dnom", (1, 0, 0, 1, 0, 0))
-        glyphSet["percent"] = pen.glyph()
-        pen = TTGlyphPen(glyphSet)
-        pen.addComponent("zero.numr", (1, 0, 0, 1, 0, 0))
-        pen.addComponent("fraction", (1, 0, 0, 1, 0, 0))
-        pen.addComponent("zero.dnom", (1, 0, 0, 1, 0, 0))
-        pen.addComponent("zero.dnom", (1, 0, 0, 1, 0, 0))
-        glyphSet["perthousand"] = pen.glyph()
-        assert glyphSet["zero.dnom"].getCompositeMaxpValues(glyphSet)[2] == 1
-        assert glyphSet["percent"].getCompositeMaxpValues(glyphSet)[2] == 2
-        assert glyphSet["perthousand"].getCompositeMaxpValues(glyphSet)[2] == 2
-
-
-class GlyphComponentTest:
-
-    def test_toXML_no_transform(self):
-        comp = GlyphComponent()
-        comp.glyphName = "a"
-        comp.flags = ARGS_ARE_XY_VALUES
-        comp.x, comp.y = 1, 2
-
-        assert getXML(comp.toXML) == [
-            '<component glyphName="a" x="1" y="2" flags="0x2"/>'
-        ]
-
-    def test_toXML_transform_scale(self):
-        comp = GlyphComponent()
-        comp.glyphName = "a"
-        comp.flags = ARGS_ARE_XY_VALUES | WE_HAVE_A_SCALE
-        comp.x, comp.y = 1, 2
-
-        comp.transform = [[0.2999878, 0], [0, 0.2999878]]
-        assert getXML(comp.toXML) == [
-            '<component glyphName="a" x="1" y="2" scale="0.3" flags="0xa"/>'
-        ]
-
-    def test_toXML_transform_xy_scale(self):
-        comp = GlyphComponent()
-        comp.glyphName = "a"
-        comp.flags = ARGS_ARE_XY_VALUES | WE_HAVE_AN_X_AND_Y_SCALE
-        comp.x, comp.y = 1, 2
-
-        comp.transform = [[0.5999756, 0], [0, 0.2999878]]
-        assert getXML(comp.toXML) == [
-            '<component glyphName="a" x="1" y="2" scalex="0.6" '
-            'scaley="0.3" flags="0x42"/>'
-        ]
-
-    def test_toXML_transform_2x2_scale(self):
-        comp = GlyphComponent()
-        comp.glyphName = "a"
-        comp.flags = ARGS_ARE_XY_VALUES | WE_HAVE_A_TWO_BY_TWO
-        comp.x, comp.y = 1, 2
-
-        comp.transform = [[0.5999756, -0.2000122], [0.2000122, 0.2999878]]
-        assert getXML(comp.toXML) == [
-            '<component glyphName="a" x="1" y="2" scalex="0.6" scale01="-0.2" '
-            'scale10="0.2" scaley="0.3" flags="0x82"/>'
-        ]
-
-    def test_fromXML_no_transform(self):
-        comp = GlyphComponent()
-        for name, attrs, content in parseXML(
-            ['<component glyphName="a" x="1" y="2" flags="0x2"/>']
-        ):
-            comp.fromXML(name, attrs, content, ttFont=None)
-
-        assert comp.glyphName == "a"
-        assert comp.flags & ARGS_ARE_XY_VALUES != 0
-        assert (comp.x, comp.y) == (1, 2)
-        assert not hasattr(comp, "transform")
-
-    def test_fromXML_transform_scale(self):
-        comp = GlyphComponent()
-        for name, attrs, content in parseXML(
-            ['<component glyphName="a" x="1" y="2" scale="0.3" flags="0xa"/>']
-        ):
-            comp.fromXML(name, attrs, content, ttFont=None)
-
-        assert comp.glyphName == "a"
-        assert comp.flags & ARGS_ARE_XY_VALUES != 0
-        assert comp.flags & WE_HAVE_A_SCALE != 0
-        assert (comp.x, comp.y) == (1, 2)
-        assert hasattr(comp, "transform")
-        for value, expected in zip(
-            itertools.chain(*comp.transform), [0.2999878, 0, 0, 0.2999878]
-        ):
-            assert value == pytest.approx(expected)
-
-    def test_fromXML_transform_xy_scale(self):
-        comp = GlyphComponent()
-        for name, attrs, content in parseXML(
-            [
-                '<component glyphName="a" x="1" y="2" scalex="0.6" '
-                'scaley="0.3" flags="0x42"/>'
-            ]
-        ):
-            comp.fromXML(name, attrs, content, ttFont=None)
-
-        assert comp.glyphName == "a"
-        assert comp.flags & ARGS_ARE_XY_VALUES != 0
-        assert comp.flags & WE_HAVE_AN_X_AND_Y_SCALE != 0
-        assert (comp.x, comp.y) == (1, 2)
-        assert hasattr(comp, "transform")
-        for value, expected in zip(
-            itertools.chain(*comp.transform), [0.5999756, 0, 0, 0.2999878]
-        ):
-            assert value == pytest.approx(expected)
-
-    def test_fromXML_transform_2x2_scale(self):
-        comp = GlyphComponent()
-        for name, attrs, content in parseXML(
-            [
-                '<component glyphName="a" x="1" y="2" scalex="0.6" scale01="-0.2" '
-                'scale10="0.2" scaley="0.3" flags="0x82"/>'
-            ]
-        ):
-            comp.fromXML(name, attrs, content, ttFont=None)
-
-        assert comp.glyphName == "a"
-        assert comp.flags & ARGS_ARE_XY_VALUES != 0
-        assert comp.flags & WE_HAVE_A_TWO_BY_TWO != 0
-        assert (comp.x, comp.y) == (1, 2)
-        assert hasattr(comp, "transform")
-        for value, expected in zip(
-            itertools.chain(*comp.transform),
-            [0.5999756, -0.2000122, 0.2000122, 0.2999878]
-        ):
-            assert value == pytest.approx(expected)
-
-    def test_toXML_reference_points(self):
-        comp = GlyphComponent()
-        comp.glyphName = "a"
-        comp.flags = 0
-        comp.firstPt = 1
-        comp.secondPt = 2
-
-        assert getXML(comp.toXML) == [
-            '<component glyphName="a" firstPt="1" secondPt="2" flags="0x0"/>'
-        ]
-
-    def test_fromXML_reference_points(self):
-        comp = GlyphComponent()
-        for name, attrs, content in parseXML(
-            ['<component glyphName="a" firstPt="1" secondPt="2" flags="0x0"/>']
-        ):
-            comp.fromXML(name, attrs, content, ttFont=None)
-
-        assert comp.glyphName == "a"
-        assert comp.flags == 0
-        assert (comp.firstPt, comp.secondPt) == (1, 2)
-        assert not hasattr(comp, "transform")
-
 
 if __name__ == "__main__":
     import sys
diff --git a/Tests/ttLib/tables/_g_v_a_r_test.py b/Tests/ttLib/tables/_g_v_a_r_test.py
index 077bb63..ebae580 100644
--- a/Tests/ttLib/tables/_g_v_a_r_test.py
+++ b/Tests/ttLib/tables/_g_v_a_r_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import FakeFont, getXML, parseXML
 from fontTools.misc.textTools import deHexStr, hexStr
 from fontTools.ttLib import TTLibError, getTableClass, getTableModule, newTable
@@ -63,7 +65,7 @@
     ],
     "space": [
         TupleVariation(
-            {"wdth": (0.0, 0.7000122, 0.7000122)},
+            {"wdth": (0.0, 0.7, 0.7)},
             [(1, 11), (2, 22), (3, 33), (4, 44)]),
     ],
     "I": [
@@ -71,7 +73,7 @@
             {"wght": (0.0, 0.5, 1.0)},
             [(3,3), (1,1), (4,4), (1,1), (5,5), (9,9), (2,2), (6,6)]),
         TupleVariation(
-            {"wght": (-1.0, -1.0, 0.0), "wdth": (0.0, 0.7999878, 0.7999878)},
+            {"wght": (-1.0, -1.0, 0.0), "wdth": (0.0, 0.8, 0.8)},
             [(-8,-88), (7,77), None, None, (-4,44), (3,33), (-2,-22), (1,11)]),
     ],
 }
@@ -80,6 +82,15 @@
 GVAR_XML = [
     '<version value="1"/>',
     '<reserved value="0"/>',
+    '<glyphVariations glyph="space">',
+    '  <tuple>',
+    '    <coord axis="wdth" value="0.7"/>',
+    '    <delta pt="0" x="1" y="11"/>',
+    '    <delta pt="1" x="2" y="22"/>',
+    '    <delta pt="2" x="3" y="33"/>',
+    '    <delta pt="3" x="4" y="44"/>',
+    '  </tuple>',
+    '</glyphVariations>',
     '<glyphVariations glyph="I">',
     '  <tuple>',
     '    <coord axis="wght" min="0.0" value="0.5" max="1.0"/>',
@@ -103,15 +114,6 @@
     '    <delta pt="7" x="1" y="11"/>',
     '  </tuple>',
     '</glyphVariations>',
-    '<glyphVariations glyph="space">',
-    '  <tuple>',
-    '    <coord axis="wdth" value="0.7"/>',
-    '    <delta pt="0" x="1" y="11"/>',
-    '    <delta pt="1" x="2" y="22"/>',
-    '    <delta pt="2" x="3" y="33"/>',
-    '    <delta pt="3" x="4" y="44"/>',
-    '  </tuple>',
-    '</glyphVariations>',
 ]
 
 
@@ -131,20 +133,6 @@
 
 
 class GVARTableTest(unittest.TestCase):
-	def assertVariationsAlmostEqual(self, vars1, vars2):
-		self.assertSetEqual(set(vars1.keys()), set(vars2.keys()))
-		for glyphName, variations1 in vars1.items():
-			variations2 = vars2[glyphName]
-			self.assertEqual(len(variations1), len(variations2))
-			for (v1, v2) in zip(variations1, variations2):
-				self.assertSetEqual(set(v1.axes), set(v2.axes))
-				for axisTag, support1 in v1.axes.items():
-					support2 = v2.axes[axisTag]
-					self.assertEqual(len(support1), len(support2))
-					for s1, s2 in zip(support1, support2):
-						self.assertAlmostEqual(s1, s2)
-				self.assertEqual(v1.coordinates, v2.coordinates)
-
 	def makeFont(self, variations):
 		glyphs=[".notdef", "space", "I"]
 		Axis = getTableModule("fvar").Axis
@@ -176,7 +164,7 @@
 	def test_decompile(self):
 		font, gvar = self.makeFont({})
 		gvar.decompile(GVAR_DATA, font)
-		self.assertVariationsAlmostEqual(gvar.variations, GVAR_VARIATIONS)
+		self.assertEqual(gvar.variations, GVAR_VARIATIONS)
 
 	def test_decompile_noVariations(self):
 		font, gvar = self.makeFont({})
@@ -188,10 +176,8 @@
 		font, gvar = self.makeFont({})
 		for name, attrs, content in parseXML(GVAR_XML):
 			gvar.fromXML(name, attrs, content, ttFont=font)
-		self.assertVariationsAlmostEqual(
-			gvar.variations,
-			{g:v for g,v in GVAR_VARIATIONS.items() if v}
-		)
+		self.assertEqual(gvar.variations,
+                         {g:v for g,v in GVAR_VARIATIONS.items() if v})
 
 	def test_toXML(self):
 		font, gvar = self.makeFont(GVAR_VARIATIONS)
diff --git a/Tests/ttLib/tables/_h_h_e_a_test.py b/Tests/ttLib/tables/_h_h_e_a_test.py
index e04fd7b..64849e9 100644
--- a/Tests/ttLib/tables/_h_h_e_a_test.py
+++ b/Tests/ttLib/tables/_h_h_e_a_test.py
@@ -1,3 +1,5 @@
+from __future__ import absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.loggingTools import CapturingLogHandler
 from fontTools.misc.testTools import parseXML, getXML
 from fontTools.misc.textTools import deHexStr
@@ -125,18 +127,6 @@
             len([r for r in captor.records
                  if "Table version value is a float" in r.msg]) == 1)
 
-    def test_aliases(self):
-        hhea = self.font['hhea']
-        self.assertEqual(hhea.ascent, hhea.ascender)
-        self.assertEqual(hhea.descent, hhea.descender)
-        hhea.ascender = 800
-        self.assertEqual(hhea.ascent, 800)
-        hhea.ascent = 750
-        self.assertEqual(hhea.ascender, 750)
-        hhea.descender = -300
-        self.assertEqual(hhea.descent, -300)
-        hhea.descent = -299
-        self.assertEqual(hhea.descender, -299)
 
 class HheaDecompileOrFromXMLTest(unittest.TestCase):
 
diff --git a/Tests/ttLib/tables/_h_m_t_x_test.py b/Tests/ttLib/tables/_h_m_t_x_test.py
index 79d0cb7..5c79fb8 100644
--- a/Tests/ttLib/tables/_h_m_t_x_test.py
+++ b/Tests/ttLib/tables/_h_m_t_x_test.py
@@ -1,3 +1,6 @@
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import parseXML, getXML
 from fontTools.misc.textTools import deHexStr
 from fontTools.ttLib import TTFont, newTable, TTLibError
diff --git a/Tests/ttLib/tables/_k_e_r_n_test.py b/Tests/ttLib/tables/_k_e_r_n_test.py
index eb48bae..b37748a 100644
--- a/Tests/ttLib/tables/_k_e_r_n_test.py
+++ b/Tests/ttLib/tables/_k_e_r_n_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.ttLib import newTable
 from fontTools.ttLib.tables._k_e_r_n import (
     KernTable_format_0, KernTable_format_unkown)
diff --git a/Tests/ttLib/tables/_l_c_a_r_test.py b/Tests/ttLib/tables/_l_c_a_r_test.py
index 5837a07..4525def 100644
--- a/Tests/ttLib/tables/_l_c_a_r_test.py
+++ b/Tests/ttLib/tables/_l_c_a_r_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import FakeFont, getXML, parseXML
 from fontTools.misc.textTools import deHexStr, hexStr
 from fontTools.ttLib import newTable
diff --git a/Tests/ttLib/tables/_l_t_a_g_test.py b/Tests/ttLib/tables/_l_t_a_g_test.py
index fc9be82..a4c5a0e 100644
--- a/Tests/ttLib/tables/_l_t_a_g_test.py
+++ b/Tests/ttLib/tables/_l_t_a_g_test.py
@@ -1,6 +1,7 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import parseXML
 from fontTools.misc.xmlWriter import XMLWriter
-from io import BytesIO
 import os
 import struct
 import unittest
diff --git a/Tests/ttLib/tables/_m_e_t_a_test.py b/Tests/ttLib/tables/_m_e_t_a_test.py
index f05ff57..dc0f8cd 100644
--- a/Tests/ttLib/tables/_m_e_t_a_test.py
+++ b/Tests/ttLib/tables/_m_e_t_a_test.py
@@ -1,9 +1,10 @@
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import parseXML
 from fontTools.misc.textTools import deHexStr
 from fontTools.misc.xmlWriter import XMLWriter
 from fontTools.ttLib import TTLibError
 from fontTools.ttLib.tables._m_e_t_a import table__m_e_t_a
-from io import BytesIO
 import unittest
 
 
@@ -58,19 +59,6 @@
             '</hexdata>'
         ], [line.strip() for line in xml.splitlines()][1:])
 
-    def test_toXML_ascii_data(self):
-        table = table__m_e_t_a()
-        table.data["TEST"] = b"Hello!"
-        writer = XMLWriter(BytesIO())
-        table.toXML(writer, {"meta": table})
-        xml = writer.file.getvalue().decode("utf-8")
-        self.assertEqual([
-            '<hexdata tag="TEST">',
-                '<!-- ascii: Hello! -->',
-                '48656c6c 6f21',
-            '</hexdata>'
-        ], [line.strip() for line in xml.splitlines()][1:])
-
     def test_fromXML(self):
         table = table__m_e_t_a()
         for name, attrs, content in parseXML(
diff --git a/Tests/ttLib/tables/_m_o_r_t_test.py b/Tests/ttLib/tables/_m_o_r_t_test.py
index 3e7169b..70696e8 100644
--- a/Tests/ttLib/tables/_m_o_r_t_test.py
+++ b/Tests/ttLib/tables/_m_o_r_t_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import FakeFont, getXML, parseXML
 from fontTools.misc.textTools import deHexStr, hexStr
 from fontTools.ttLib import newTable
diff --git a/Tests/ttLib/tables/_m_o_r_x_test.py b/Tests/ttLib/tables/_m_o_r_x_test.py
index 0b807f8..f4e7fb8 100644
--- a/Tests/ttLib/tables/_m_o_r_x_test.py
+++ b/Tests/ttLib/tables/_m_o_r_x_test.py
@@ -1,4 +1,6 @@
-from fontTools.misc.py23 import bytechr, bytesjoin
+# coding: utf-8
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import FakeFont, getXML, parseXML
 from fontTools.misc.textTools import deHexStr, hexStr
 from fontTools.ttLib import newTable
diff --git a/Tests/ttLib/tables/_n_a_m_e_test.py b/Tests/ttLib/tables/_n_a_m_e_test.py
index 8e82970..136b63f 100644
--- a/Tests/ttLib/tables/_n_a_m_e_test.py
+++ b/Tests/ttLib/tables/_n_a_m_e_test.py
@@ -1,9 +1,10 @@
-from fontTools.misc.py23 import bytesjoin, tostr
+# -*- coding: utf-8 -*-
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc import sstruct
 from fontTools.misc.loggingTools import CapturingLogHandler
 from fontTools.misc.testTools import FakeFont
 from fontTools.misc.xmlWriter import XMLWriter
-from io import BytesIO
 import struct
 import unittest
 from fontTools.ttLib import newTable
@@ -53,26 +54,6 @@
 		with self.assertRaises(TypeError):
 			table.setName(1.000, 5, 1, 0, 0)
 
-	def test_names_sort_bytes_str(self):
-		# Corner case: If a user appends a name record directly to `names`, the
-		# `__lt__` method on NameRecord may run into duplicate name records where
-		# one `string` is a str and the other one bytes, leading to an exception.
-		table = table__n_a_m_e()
-		table.names = [
-			makeName("Test", 25, 3, 1, 0x409),
-			makeName("Test".encode("utf-16be"), 25, 3, 1, 0x409),
-		]
-		table.compile(None)
-
-	def test_names_sort_bytes_str_encoding_error(self):
-		table = table__n_a_m_e()
-		table.names = [
-			makeName("Test寬", 25, 1, 0, 0),
-			makeName("Test鬆鬆", 25, 1, 0, 0),
-		]
-		with self.assertRaises(TypeError):
-			table.names.sort()
-
 	def test_addName(self):
 		table = table__n_a_m_e()
 		nameIDs = []
@@ -95,111 +76,6 @@
 		with self.assertRaises(TypeError):
 			table.addName(b"abc")  # must be unicode string
 
-	def test_removeNames(self):
-		table = table__n_a_m_e()
-		table.setName("Regular", 2, 1, 0, 0)
-		table.setName("Regular", 2, 3, 1, 0x409)
-		table.removeNames(nameID=2)
-		self.assertEqual(table.names, [])
-
-		table = table__n_a_m_e()
-		table.setName("FamilyName", 1, 1, 0, 0)
-		table.setName("Regular", 2, 1, 0, 0)
-		table.setName("FamilyName", 1, 3, 1, 0x409)
-		table.setName("Regular", 2, 3, 1, 0x409)
-		table.removeNames(platformID=1)
-		self.assertEqual(len(table.names), 2)
-		self.assertIsNone(table.getName(1, 1, 0, 0))
-		self.assertIsNone(table.getName(2, 1, 0, 0))
-		rec1 = table.getName(1, 3, 1, 0x409)
-		self.assertEqual(str(rec1), "FamilyName")
-		rec2 = table.getName(2, 3, 1, 0x409)
-		self.assertEqual(str(rec2), "Regular")
-
-		table = table__n_a_m_e()
-		table.setName("FamilyName", 1, 1, 0, 0)
-		table.setName("Regular", 2, 1, 0, 0)
-		table.removeNames(nameID=1)
-		self.assertEqual(len(table.names), 1)
-		self.assertIsNone(table.getName(1, 1, 0, 0))
-		rec = table.getName(2, 1, 0, 0)
-		self.assertEqual(str(rec), "Regular")
-
-		table = table__n_a_m_e()
-		table.setName("FamilyName", 1, 1, 0, 0)
-		table.setName("Regular", 2, 1, 0, 0)
-		table.removeNames(2, 1, 0, 0)
-		self.assertEqual(len(table.names), 1)
-		self.assertIsNone(table.getName(2, 1, 0, 0))
-		rec = table.getName(1, 1, 0, 0)
-		self.assertEqual(str(rec), "FamilyName")
-
-		table = table__n_a_m_e()
-		table.setName("FamilyName", 1, 1, 0, 0)
-		table.setName("Regular", 2, 1, 0, 0)
-		table.removeNames()
-		self.assertEqual(len(table.names), 2)
-		rec1 = table.getName(1, 1, 0, 0)
-		self.assertEqual(str(rec1), "FamilyName")
-		rec2 = table.getName(2, 1, 0, 0)
-		self.assertEqual(str(rec2), "Regular")
-
-	@staticmethod
-	def _get_test_names():
-		names = {
-			"en": "Width",
-			"de-CH": "Breite",
-			"gsw-LI": "Bräiti",
-		}
-		namesSubSet = names.copy()
-		del namesSubSet["gsw-LI"]
-		namesSuperSet = names.copy()
-		namesSuperSet["nl"] = "Breedte"
-		return names, namesSubSet, namesSuperSet
-
-	def test_findMultilingualName(self):
-		table = table__n_a_m_e()
-		names, namesSubSet, namesSuperSet = self._get_test_names()
-		nameID = table.addMultilingualName(names)
-		assert nameID is not None
-		self.assertEqual(nameID, table.findMultilingualName(names))
-		self.assertEqual(nameID, table.findMultilingualName(namesSubSet))
-		self.assertEqual(None, table.findMultilingualName(namesSuperSet))
-
-	def test_findMultilingualName_compiled(self):
-		table = table__n_a_m_e()
-		names, namesSubSet, namesSuperSet = self._get_test_names()
-		nameID = table.addMultilingualName(names)
-		assert nameID is not None
-		# After compile/decompile, name.string is a bytes sequence, which
-		# findMultilingualName() should also handle
-		data = table.compile(None)
-		table = table__n_a_m_e()
-		table.decompile(data, None)
-		self.assertEqual(nameID, table.findMultilingualName(names))
-		self.assertEqual(nameID, table.findMultilingualName(namesSubSet))
-		self.assertEqual(None, table.findMultilingualName(namesSuperSet))
-
-	def test_addMultilingualNameReuse(self):
-		table = table__n_a_m_e()
-		names, namesSubSet, namesSuperSet = self._get_test_names()
-		nameID = table.addMultilingualName(names)
-		assert nameID is not None
-		self.assertEqual(nameID, table.addMultilingualName(names))
-		self.assertEqual(nameID, table.addMultilingualName(namesSubSet))
-		self.assertNotEqual(None, table.addMultilingualName(namesSuperSet))
-
-	def test_findMultilingualNameNoMac(self):
-		table = table__n_a_m_e()
-		names, namesSubSet, namesSuperSet = self._get_test_names()
-		nameID = table.addMultilingualName(names, mac=False)
-		assert nameID is not None
-		self.assertEqual(nameID, table.findMultilingualName(names, mac=False))
-		self.assertEqual(None, table.findMultilingualName(names))
-		self.assertEqual(nameID, table.findMultilingualName(namesSubSet, mac=False))
-		self.assertEqual(None, table.findMultilingualName(namesSubSet))
-		self.assertEqual(None, table.findMultilingualName(namesSuperSet))
-
 	def test_addMultilingualName(self):
 		# Microsoft Windows has language codes for “English” (en)
 		# and for “Standard German as used in Switzerland” (de-CH).
@@ -294,17 +170,6 @@
 			nameTable.addMultilingualName({"en": "A", "la": "ⱾƤℚⱤ"})
 		captor.assertRegex("cannot store language la into 'ltag' table")
 
-	def test_addMultilingualName_minNameID(self):
-		table = table__n_a_m_e()
-		names, namesSubSet, namesSuperSet = self._get_test_names()
-		nameID = table.addMultilingualName(names, nameID=2)
-		self.assertEqual(nameID, 2)
-		nameID = table.addMultilingualName(names)
-		self.assertEqual(nameID, 2)
-		nameID = table.addMultilingualName(names, minNameID=256)
-		self.assertGreaterEqual(nameID, 256)
-		self.assertEqual(nameID, table.findMultilingualName(names, minNameID=256))
-
 	def test_decompile_badOffset(self):
                 # https://github.com/fonttools/fonttools/issues/525
 		table = table__n_a_m_e()
@@ -338,18 +203,13 @@
 	def test_toUnicode_macromanian(self):
 		name = makeName(b"Foo Italic\xfb", 222, 1, 0, 37)  # Mac Romanian
 		self.assertEqual("mac_romanian", name.getEncoding())
-		self.assertEqual("Foo Italic"+chr(0x02DA), name.toUnicode())
+		self.assertEqual("Foo Italic"+unichr(0x02DA), name.toUnicode())
 
 	def test_toUnicode_UnicodeDecodeError(self):
 		name = makeName(b"\1", 111, 0, 2, 7)
 		self.assertEqual("utf_16_be", name.getEncoding())
 		self.assertRaises(UnicodeDecodeError, name.toUnicode)
 
-	def test_toUnicode_singleChar(self):
-		# https://github.com/fonttools/fonttools/issues/1997
-		name = makeName("A", 256, 3, 1, 0x409)
-		self.assertEqual(name.toUnicode(), "A")
-
 	def toXML(self, name):
 		writer = XMLWriter(BytesIO())
 		name.toXML(writer, ttFont=None)
@@ -430,19 +290,7 @@
 
 	def test_extended_mac_encodings(self):
 		name = makeName(b'\xfe', 123, 1, 1, 0) # Mac Japanese
-		self.assertEqual(name.toUnicode(), chr(0x2122))
-
-	def test_extended_mac_encodings_errors(self):
-		s = "汉仪彩云体简"
-		name = makeName(s.encode("x_mac_simp_chinese_ttx"), 123, 1, 25, 0)
-		# first check we round-trip with 'strict'
-		self.assertEqual(name.toUnicode(errors="strict"), s)
-
-		# append an incomplete invalid sequence and check that we handle
-		# errors with the requested error handler
-		name.string += b"\xba"
-		self.assertEqual(name.toUnicode(errors="backslashreplace"), s + "\\xba")
-		self.assertEqual(name.toUnicode(errors="replace"), s + "�")
+		self.assertEqual(name.toUnicode(), unichr(0x2122))
 
 	def test_extended_unknown(self):
 		name = makeName(b'\xfe', 123, 10, 11, 12)
diff --git a/Tests/ttLib/tables/_o_p_b_d_test.py b/Tests/ttLib/tables/_o_p_b_d_test.py
index d62ada8..131d3f9 100644
--- a/Tests/ttLib/tables/_o_p_b_d_test.py
+++ b/Tests/ttLib/tables/_o_p_b_d_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import FakeFont, getXML, parseXML
 from fontTools.misc.textTools import deHexStr, hexStr
 from fontTools.ttLib import newTable
diff --git a/Tests/ttLib/tables/_p_r_o_p_test.py b/Tests/ttLib/tables/_p_r_o_p_test.py
index 63c2924..edac915 100644
--- a/Tests/ttLib/tables/_p_r_o_p_test.py
+++ b/Tests/ttLib/tables/_p_r_o_p_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import FakeFont, getXML, parseXML
 from fontTools.misc.textTools import deHexStr, hexStr
 from fontTools.ttLib import newTable
diff --git a/Tests/ttLib/tables/_t_r_a_k_test.py b/Tests/ttLib/tables/_t_r_a_k_test.py
index 2ea6cf5..c223c81 100644
--- a/Tests/ttLib/tables/_t_r_a_k_test.py
+++ b/Tests/ttLib/tables/_t_r_a_k_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import parseXML, getXML
 from fontTools.misc.textTools import deHexStr
 from fontTools.ttLib import TTFont, TTLibError
diff --git a/Tests/ttLib/tables/_v_h_e_a_test.py b/Tests/ttLib/tables/_v_h_e_a_test.py
index c601863..8979e92 100644
--- a/Tests/ttLib/tables/_v_h_e_a_test.py
+++ b/Tests/ttLib/tables/_v_h_e_a_test.py
@@ -1,3 +1,5 @@
+from __future__ import absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.loggingTools import CapturingLogHandler
 from fontTools.misc.testTools import parseXML, getXML
 from fontTools.misc.textTools import deHexStr
diff --git a/Tests/ttLib/tables/_v_m_t_x_test.py b/Tests/ttLib/tables/_v_m_t_x_test.py
index 5ea2d24..f55dbec 100644
--- a/Tests/ttLib/tables/_v_m_t_x_test.py
+++ b/Tests/ttLib/tables/_v_m_t_x_test.py
@@ -1,3 +1,6 @@
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.ttLib.tables._v_m_t_x import table__v_m_t_x
 import _h_m_t_x_test
 import unittest
diff --git a/Tests/ttLib/tables/data/C_F_F__2.bin b/Tests/ttLib/tables/data/C_F_F__2.bin
index 52b0177..faa0e91 100644
--- a/Tests/ttLib/tables/data/C_F_F__2.bin
+++ b/Tests/ttLib/tables/data/C_F_F__2.bin
Binary files differ
diff --git a/Tests/ttLib/tables/data/C_F_F__2.ttx b/Tests/ttLib/tables/data/C_F_F__2.ttx
index 95f840f..c86252b 100644
--- a/Tests/ttLib/tables/data/C_F_F__2.ttx
+++ b/Tests/ttLib/tables/data/C_F_F__2.ttx
@@ -21,7 +21,7 @@
     <xMin value="51"/>
     <yMin value="-115"/>
     <xMax value="560"/>
-    <yMax value="731"/>
+    <yMax value="762"/>
     <macStyle value="00000000 00000000"/>
     <lowestRecPPEM value="3"/>
     <fontDirectionHint value="2"/>
@@ -106,8 +106,6 @@
                 <blend value="190 -110 -162 0 -110 -162"/>
                 <blend value="200 0 -6 0 0 -6"/>
             </StemSnapV>
-            <LanguageGroup value="0"/>
-            <ExpansionFactor value="0.06"/>
           </Private>
         </FontDict>
       </FDArray>
diff --git a/Tests/ttLib/tables/data/NotoColorEmoji.subset.index_format_3.ttx b/Tests/ttLib/tables/data/NotoColorEmoji.subset.index_format_3.ttx
deleted file mode 100644
index 6a1728e..0000000
--- a/Tests/ttLib/tables/data/NotoColorEmoji.subset.index_format_3.ttx
+++ /dev/null
@@ -1,705 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.44">
-
-  <GlyphOrder>
-    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="eight"/>
-    <GlyphID id="2" name="registered"/>
-    <GlyphID id="3" name="uni2049"/>
-  </GlyphOrder>
-
-  <head>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="1.0"/>
-    <fontRevision value="2.011"/>
-    <checkSumAdjustment value="0x73631d70"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00001011"/>
-    <unitsPerEm value="2048"/>
-    <created value="Wed May 22 20:00:43 2013"/>
-    <modified value="Thu Jan 30 14:31:14 2020"/>
-    <xMin value="0"/>
-    <yMin value="-500"/>
-    <xMax value="2550"/>
-    <yMax value="1900"/>
-    <macStyle value="00000000 00000000"/>
-    <lowestRecPPEM value="8"/>
-    <fontDirectionHint value="2"/>
-    <indexToLocFormat value="0"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="1900"/>
-    <descent value="-500"/>
-    <lineGap value="0"/>
-    <advanceWidthMax value="2550"/>
-    <minLeftSideBearing value="0"/>
-    <minRightSideBearing value="0"/>
-    <xMaxExtent value="2550"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfHMetrics value="1"/>
-  </hhea>
-
-  <maxp>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="0x10000"/>
-    <numGlyphs value="4"/>
-    <maxPoints value="8"/>
-    <maxContours value="2"/>
-    <maxCompositePoints value="0"/>
-    <maxCompositeContours value="0"/>
-    <maxZones value="2"/>
-    <maxTwilightPoints value="0"/>
-    <maxStorage value="1"/>
-    <maxFunctionDefs value="1"/>
-    <maxInstructionDefs value="0"/>
-    <maxStackElements value="64"/>
-    <maxSizeOfInstructions value="46"/>
-    <maxComponentElements value="0"/>
-    <maxComponentDepth value="0"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="4"/>
-    <xAvgCharWidth value="2550"/>
-    <usWeightClass value="400"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00000000"/>
-    <ySubscriptXSize value="1331"/>
-    <ySubscriptYSize value="1433"/>
-    <ySubscriptXOffset value="0"/>
-    <ySubscriptYOffset value="286"/>
-    <ySuperscriptXSize value="1331"/>
-    <ySuperscriptYSize value="1433"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="983"/>
-    <yStrikeoutSize value="102"/>
-    <yStrikeoutPosition value="530"/>
-    <sFamilyClass value="0"/>
-    <panose>
-      <bFamilyType value="2"/>
-      <bSerifStyle value="0"/>
-      <bWeight value="6"/>
-      <bProportion value="9"/>
-      <bContrast value="0"/>
-      <bStrokeVariation value="0"/>
-      <bArmStyle value="0"/>
-      <bLetterForm value="0"/>
-      <bMidline value="0"/>
-      <bXHeight value="0"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="GOOG"/>
-    <fsSelection value="00000000 01000000"/>
-    <usFirstCharIndex value="56"/>
-    <usLastCharIndex value="8265"/>
-    <sTypoAscender value="1900"/>
-    <sTypoDescender value="-500"/>
-    <sTypoLineGap value="0"/>
-    <usWinAscent value="1900"/>
-    <usWinDescent value="500"/>
-    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
-    <sxHeight value="0"/>
-    <sCapHeight value="1900"/>
-    <usDefaultChar value="0"/>
-    <usBreakChar value="32"/>
-    <usMaxContext value="1"/>
-  </OS_2>
-
-  <hmtx>
-    <mtx name=".notdef" width="2550" lsb="0"/>
-    <mtx name="eight" width="2550" lsb="0"/>
-    <mtx name="registered" width="2550" lsb="0"/>
-    <mtx name="uni2049" width="2550" lsb="0"/>
-  </hmtx>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_14 platformID="0" platEncID="5">
-      <map uv="0x38" uvs="0xfe0f"/>
-      <map uv="0xae" uvs="0xfe0f"/>
-      <map uv="0x2049" uvs="0xfe0f"/>
-    </cmap_format_14>
-    <cmap_format_12 platformID="3" platEncID="10" format="12" reserved="0" length="52" language="0" nGroups="3">
-      <map code="0x38" name="eight"/><!-- DIGIT EIGHT -->
-      <map code="0xae" name="registered"/><!-- REGISTERED SIGN -->
-      <map code="0x2049" name="uni2049"/><!-- EXCLAMATION QUESTION MARK -->
-    </cmap_format_12>
-  </cmap>
-
-  <name>
-    <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
-      Copyright 2013 Google Inc.
-    </namerecord>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      Noto Color Emoji
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      Noto Color Emoji
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      Noto Color Emoji
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version 2.011;GOOG;noto-emoji:20180424; pistol
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      NotoColorEmoji
-    </namerecord>
-  </name>
-
-  <post>
-    <formatType value="3.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-1244"/>
-    <underlineThickness value="131"/>
-    <isFixedPitch value="1"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="0"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="0"/>
-  </post>
-
-  <CBDT>
-    <header version="3.0"/>
-    <strikedata index="0">
-      <cbdt_bitmap_format_17 name="registered">
-        <SmallGlyphMetrics>
-          <height value="128"/>
-          <width value="136"/>
-          <BearingX value="0"/>
-          <BearingY value="101"/>
-          <Advance value="136"/>
-        </SmallGlyphMetrics>
-        <rawimagedata>
-          89504e47 0d0a1a0a 0000000d 49484452
-          00000088 00000080 08030000 00e737d1
-          0d000000 ff504c54 454c6971 74747475
-          75757878 78777777 7b7b7b7e 7e7e6868
-          68787878 79797977 77777777 77787878
-          6969697b 7b7b7777 77737373 6f6f6f6c
-          6c6c6767 67787878 6a6a6a64 64646161
-          617d7d7d 7a7a7a60 60607575 75797979
-          6666665e 5e5e7171 716e6e6e 6565655c
-          5c5c5a5a 5a6c6c6c 58585857 57577373
-          73555555 53535352 52526e6e 6e505050
-          4e4e4e6b 6b6b4c4c 4c666666 4b4b4b66
-          66666565 65494949 65656547 47474646
-          465b5b5b 4444445a 5a5a4242 42606060
-          5757573f 3f3f6060 60575757 3d3d3d58
-          58583a3a 3a5c5c5c 5d5d5d39 39393737
-          37353535 33333353 53535252 52525252
-          2f2f2f52 52524f4f 4f2b2b2b 28282825
-          25252323 23212121 f9766a48 00000050
-          74524e53 00406180 bfefff20 9fcf508e
-          df30ffff ffffffff 10ffffff ffffffff
-          afffffff ffffffff 70ffffef ffffff80
-          ffffc0ff 8fffefa4 ffdfffff 50ff10ff
-          c162ff80 40ffa7ff d6efffff ffff8fdb
-          7fffefbf 08ff47de 00000bbe 49444154
-          7801ecd5 d77eab30 0c067033 dcb0629b
-          8d11a381 aef77fc2 23b70c93 09745c9d
-          ff5533ac 7e96941f e4bfff7e 8d615ab6
-          4d9f26d4 b62dd320 7fea603a eed30dae
-          631ec89f f0fce0e9 81c0f7c8 2f3bfaf3
-          30181761 144fa250 70360fca 3f925f93
-          98d34078 9866f915 591af269 4866f23b
-          312c5a7c 9222cdcb 3bf254c8 e213b592
-          5f8bc144 5cae100b f63b5186 181c7bb1
-          529ef221 0af93946 50281097 9bc45028
-          81f15353 a976c5d0 a2543f32 1f8f1648
-          d6cd2eb5 2c10f5be df0ebf40 2cbaf63f
-          a210a098 0084d1b5 b4112b90 ffcda61c
-          dc0241d6 9c89435e 5cc5c38b 301914c8
-          3d7c6b4b e9b576c4 2d2bee60 6d7cad29
-          d420bb99 0cf1653b f267c906 d4f62dcf
-          1878966f 533690cf f9b2299c 2193ec64
-          31d4968d e624d897 407fc8ea 8fe5807d
-          11a74653 b60c5964 1787a168 39ed2185
-          7fbcf75c 1cb240b6 1c0f7276 e788bb59
-          13b24fce c3611bea 2c0a9b6e 16ef4ca2
-          6ac9ac9b a592216a 252b1f4d 0cc9b49b
-          65724f12 4b95c9bb 492ef418 eba308bd
-          86dcbe27 e6598e5a 32541dc8 06878a21
-          59eb49b6 fe760c89 b4b94412 05c6f687
-          a544913e 1db4a1cc 814a29e3 794b8544
-          4e42364b 1c89c4bc b331bea4 87d5c75d
-          29b5356b 409d36c9 2ea6ba13 cc49527c
-          e9aebd92 affad98f 4ad58fe0 88350379
-          07b52bcb bb72d7a3 3a25ca7e a4a6ec93
-          553c75b2 9b72f0af 3b24b65c 21f0bdab
-          fde55392 4eddcb5b 35187a71 cec65e3a
-          7225ea1f ce0ada17 37a36b86 53a9455d
-          e4705487 d5a8b3fc b6380d85 1c386751
-          9c4512b5 b0d5ba5f 6edb8f5a d50f822c
-          2979d33f d0652948 85be9005 7b5974d5
-          6f38e01c bad741ca 397793a1 54d4af91
-          4752b193 e59e60a1 f475d001 e70179c0
-          c213f578 22e77822 19ef94f6 eb349144
-          f4b84812 60a9fc75 50e30beb d1a6722e
-          f4e4586f 631094c3 459223d5 3b2db070
-          f2b021e5 db20c417 e63865ce e3d7d5fa
-          673cba4c 62e23be1 58b97cd4 92e45dfb
-          f609bfed 903d4150 346cd7cc c1774eda
-          1ddf937b 0d0180e6 e3cbab00 08123dc8
-          db166acf fde59a00 88d7a178 0300d6bd
-          86003c7f 0c520030 c8ad20fd 29d4a531
-          0e74a9c5 2406d118 00908ed5 9f01eeb4
-          c4d41ad2 01404526 3640fd31 eb045c88
-          f0a8a607 009be82a 00e8b496 98e41657
-          6bc83f52 ca43c759 1c8ac2c0 163205c9
-          258e2524 c7941448 4fa6effc efff5c7b
-          b35c6106 dfb059f6 53733807 fbb3cd8c
-          00e59814 c16b23c8 601987c1 236d89d7
-          60db3992 87e00609 bca9dd81 e025b622
-          b95b23bf eef6b70e bf3f372a ba72acc0
-          76e27d82 05a61ac6 4940f304 5f535537
-          28bc435a 4474ae0d 897f7bee 9b4898c3
-          fb06152e 5081e653 40033589 b5a53b10
-          5ac4a56e 99eb8659 f9f32b79 f48e6489
-          4ba026c1 2363acc0 9681f1b4 2f52b7a0
-          08f5b18b da61fb9b 9ec2b406 c302c68f
-          f4cd30c6 db29189b 043d91d9 90084e01
-          2685ab49 f777834c 18b335c2 19a3efe6
-          196c370d 57dbf0a7 08631d11 c5182932
-          5d33265d 4d33d63b fdf07aea b8089cfa
-          73401013 9d6111fa 54adab95 30e5f06e
-          63ea82e1 798d1d0b a7e68b60 0880c816
-          037fc755 5babf060 7ba698d6 904681cf
-          c45ab56b 28adb589 27a20745 1098bc74
-          3d5f2481 a94b5c46 593ba1fe ad5aabb1
-          31b3b67f 7bbfb729 4e714364 6d6dea7a
-          b06ad8bf 1b6b6798 6a6ba97f ae84ea08
-          11ec1122 f4c113b7 0b4feb7d 030ca3c1
-          05e47891 089ee132 b51f030b 6b332cac
-          a010fb0b a4840879 ae832231 3c5bb90d
-          2f823e5b ce25e605 e7eb8010 d9b7d022
-          6e197247 c89af302 73c9b93f cd81f319
-          e69af303 11cf3126 674022ce f9aead2d
-          e117b590 c67c060b f97996cd 8f0d26cb
-          4e2345a0 a65c6d4e 2d74ca32 830bcdb3
-          cccfd759 563891ed 8027d540 1eb37616
-          ac4dfc6f c0891459 b6f67221 448d390c
-          1f478924 b01bb16f 5b7bd08a 7c59981e
-          0b350cff 4524f444 84e86c35 17624b79
-          c09b956b 95f033f6 5ae11d22 e7867122
-          d39300f4 d1a18438 04a4082e 3456e4dc
-          a285b874 2bd370f1 22aea467 c70a7e47
-          ff592486 679bd77f 38c230a1 445e5b36
-          82022bc8 f540de02 5a042b3b fa44ba22
-          2129e248 0541ba7f eda0f19b 1f10d950
-          224aa91d e630f445 942a5f3b 94aac76c
-          797ced17 0e012502 01767630 1c2be2d8
-          7539bff6 a86092cb 74acc87b c32d91f7
-          fb291590 04b744b0 754b64ff d100c34f
-          4264f971 2faf7305 4401c927 44d8db53
-          2217a52a ccb552db ff23b2cf 490f64ab
-          94c66205 d7e7e507 29575f0d a9942732
-          be8f4202 9724b8c1 49ca149b 2b290f94
-          48817949 e41057f7 79ec2470 f82ba0c0
-          994aa7ec 8b6c9d68 0d1b1a2f a2e1ed45
-          709b8b94 b53bfaad 972fa4cc bf1b8eb0
-          a59810f9 be0b7839 1af08821 3f623597
-          d2570ea1 f04ece45 8bec2ac7 7b4f241c
-          108920c7 e63b5d35 c6ecb191 1af3d217
-          31a6fe76 bc42a5c3 a613cddc cb142fc6
-          a4d8dcc3 9b44e397 5baa32e6 ad9fe679
-          5744e73f d9bb6809 3f07be91 37632a6c
-          d6c6fca2 54f3bcc0 c619e64a 86447650
-          787b796a 8028d75f 3f242f71 708304ca
-          672c1679 4e9ddddf 8456c792 eb2010f4
-          4da77785 2a0e1c98 924b72ce 56708e9b
-          feff7b5e d72e3028 d9fddeee 4a9aeea6
-          67c0612f 84280f7f 9042cc6a 4184181c
-          3c8c1041 2f199486 8b53c1d5 06664248
-          cb2bc1db b71d673c 9f5a4e22 c4fa5510
-          12e2180e 13d23957 53c1e53a d6422441
-          e0e80d67 0ecea91e 64d419a4 58a0cfd2
-          574b0d79 fb3beb89 2373b72d 53d307de
-          9b6523c8 d98383f0 e6f4b9bc e9dc9c25
-          efcc4157 f7bfeab6 b15629ae 8b4a1029
-          8320b194 d5d95fa4 942bae8f 24134214
-          b04d83b4 59c79baf 948e55b2 930f327e
-          11a48056 1d9840d0 9f7a0d1c f1b874bd
-          4ab9e83a d1815902 5ad119a4 df6838c3
-          12092a41 236bafe7 b84c3a28 29675daf
-          f160be79 6d243ba5 c6578fbe 52f5c95f
-          94525b66 8c713b6b 1b486e17 58e1baf3
-          abc24d29 0ad6ba47 9520535e 26690629
-          ee4ae973 85a26a9b 1381d277 7552ead6
-          ebc21ee2 dc124b5c 5faa411e 1e1c8491
-          419032e5 a0d149d1 185a69ed 735cefb9
-          d4d255e2 9c069596 765a4f9f 1e89d61c
-          c4e1a2b5 ce99b3c2 ed25ac9f 6038e056
-          38660b8e 1097d6e8 6cb4be15 4190392f
-          928641b8 0dadcdb5 42d25950 bea17cb6
-          b552571c 5abd92b0 a5e5fb20 8c0c8211
-          931ea475 70cc96a8 ae8291f2 405e8c84
-          5bdabb20 c6ac3e3c 5263dafa b918634a
-          6695b8dd f9f307b3 f4f97620 3c126362
-          67742663 eeffda82 0c10a443 4d4fa68d
-          90e464df 1a50a2b3 2bc4c6f0 40da7184
-          761bb674 2b7c904f 8f6a1046 06c18869
-          cfc4982f 7b40c261 6d0deb3b 01053d9c
-          62ee9320 c8865718 358d7873 0ecc5b61
-          6f7c8eb9 737d105c 7bef7082 6410b46e
-          ad2e4463 5e8088f6 adeae84e 147f78de
-          98e862db a8999e7a 6f812529 779a8f94
-          febcf6f8 fb704f4b dcb4bd3d 5bdedcf1
-          1e84c0d6 32f5f172 6bf90e05 9aea5f2b
-          4976452f 8ae338b1 5f1256b8 feee92ef
-          501c1f7e 799b04d7 51afd855 725cfb44
-          7c525f21 838ee7f8 808e704e 7ee20a3a
-          471bdd2b bc1f9c0f 42670fde 18dcfe6f
-          af5e7694 85a1008e 9f1d2b5e 83585342
-          4c8cdc02 2975a2f4 4a19bff7 7f96ef94
-          4174eee0 e8ace647 5c68da93 bf674306
-          b3481cb0 356747ea 1710828c 2e6c059f
-          0a6d7421 2154789d 1ecd995f a784798a
-          273c5c1a 235e1ee1 4b6c058c ab68f024
-          832fafeb 2e1a28ce a0b2be43 4cc372fc
-          8afb9d29 f07faa36 67228e10 2f60b182
-          472816e6 acf6eb0c 603616a1 8399e411
-          520c1662 2a42b999 1c22b468 4c851748
-          6b267b12 211ec002 018f10d9 9b49eba7
-          54b0885e ad56a475 1391ac90 d505cc54
-          68bb4289 709396e0 0f1a16e2 bee4e8cc
-          f8385793 29657606 a99d9b46 1cfd000e
-          8b71821a 77617232 e00cbec1 3819e4c6
-          5d34c35d 801b4b6a 77456cc9 40c9103e
-          154a4506 5be1aed4 b776204d 50eeaeb5
-          2979a178 15c03b41 c5157991 b6ee5a4e
-          90861b55 0425a2bf 664a4a46 b6933a63
-          28c44fa6 6567c988 96a6bf26 12822ab8
-          19b3ebf5 9aeefbd7 da92aebf 40cbb67f
-          6defcf5b 063f10a8 35dab9fe 0d516fd7
-          1fdad6a2 7fc3edd6 4805f023 85a4283e
-          f4ef8943 9da67492 a6f541f4 ef1d628a
-          64013f95 598a36e6 f9266643 91cde00e
-          0a4ebddc dc909153 8f17701f 4cc55e6e
-          4e8b983c f61483fb d136f652 f17c9ae9
-          59a4b167 35dc5531 a6248dfb 37836b92
-          31a3807b c39464b0 6bcce9ab 88936976
-          c9e01119 5e51a964 541e4dff 51446f8e
-          65325255 010f134a 9b9c6dcb a615ceeb
-          1d126d53 26132b43 78b04caa cd3794cc
-          e0570415 ff346678 2dff2aa6 75d7d9cd
-          c4769dd6 0cfefc79 94ff183d 2a93948d
-          64820000 00004945 4e44ae42 6082
-        </rawimagedata>
-      </cbdt_bitmap_format_17>
-      <cbdt_bitmap_format_17 name="eight">
-        <SmallGlyphMetrics>
-          <height value="128"/>
-          <width value="136"/>
-          <BearingX value="0"/>
-          <BearingY value="101"/>
-          <Advance value="136"/>
-        </SmallGlyphMetrics>
-        <rawimagedata>
-          89504e47 0d0a1a0a 0000000d 49484452
-          00000088 00000080 08030000 00e737d1
-          0d000000 36504c54 454c6971 40404040
-          40404040 40404040 40404071 7171c3c3
-          c3dfdfdf efefeff4 f4f4fafa fad0d0d0
-          f8f8f8b6 b6b6e7e7 e7909090 a6a6a6ad
-          4143d100 00001274 524e5300 0a131e29
-          3340739e c8dfff84 f266b34d 59e71538
-          bc000003 04494441 547801ed 9ac1b29d
-          200c860b f02902a2 beffcb76 3a3d73ab
-          a15e4f17 c959946f ed8cbf49 0249cc8f
-          c1603018 0c0683c1 6030b0c7 f910232f
-          620cde7d 44458874 c460adc5 456e88ce
-          5ec634a7 25971779 49f3642c 25005097
-          d2b15400 828d8e08 5073f92b 6b028856
-          3a5a2eb7 e406441b 1da97c4b 02a2858e
-          ad3cb04d ea4a82d0 71c3a21d b1eece2f
-          920d70ba 8e99cb5b ccaacef1 30e5f216
-          eb045ed3 20a93b37 e61df639 ad7dea44
-          c50899d6 ee752fa6 d49bc4e9 a54cbdbe
-          ece0c47c 155921e8 79662967 1a10bdfb
-          559944a4 caace71b a0f38b3f 994b0490
-          9a6f1c34 190527e3 0719414d 2b6fbc30
-          fe266c1f c5a19bb4 822408db cfe085d0
-          6623447c f10e4e9e ffe2c289 26490374
-          c1bc7e5e 887ce07f 102282f5 d9355659
-          b3839342 4cb2c6c3 fc2fe95b c1ab5dbe
-          0f075a6f 311522e4 72e27ac4 7b71c467
-          c0a80c48 9c947820 c932c0aa 30aad732
-          e0d02b8c 04519864 9d3971ac 7aa5a2c0
-          21a2a4a4 e9a654cc 80576d27 f6b59c59
-          b7b9c121 8be7f580 a8dc60b5 37db1a54
-          c7241ea8 e5910a78 fde6b7ad 0fcd55b3
-          18d60460 5fca372c bba20ea1 847a6b94
-          5cb1d1e1 7930c9b6 03380b1d d31b1323
-          bcbe8e23 9707f204 78751d6b 79643d74
-          bde3a48e 4f2989bd 8e9c5a83 36a72c94
-          68cef37c 77e72d8d 2f5a36bb f5ba7e3f
-          7161331a 1979d8bb 1b85f0bb 300a208b
-          955dcb24 7db70fd1 5dfe586c b2b8b628
-          e2f3a576 160312cd 625196ce b5fbe0d8
-          3f11f45b df1570bd cd54e612 cf438767
-          ad2a21b2 f79ded73 77ac3eca 9bc13f75
-          c74d5f88 7c897c66 083116f2 744878a8
-          e642b6e7 ac5113b2 cb6b5ebe 05c8327d
-          f57f09b4 ce24415e cf80c174 7301bcb0
-          199b3ce2 2d7e1b55 e4e88a26 1f081675
-          d17afcd9 18713ed2 8d2cb42a 2360e99a
-          6d313292 bed36a7a 5bdf5e22 4746fad3
-          3c072cfd c6480338 eaf63287 c86f2d93
-          1ce56d0e d5f126b5 bc49d26c f5bc3c29
-          eed980f0 a9ad0da1 23daefb1 98e9104a
-          ead330af 9aecf6bc 37cc8b46 c3bc762b
-          6569669b 681e803d e5d291d3 0180375d
-          cd63afd7 15c1ba83 b239242e 708bf502
-          a70ff410 fca7166b f9e2338b b583c160
-          30180c06 83c160f0 13e55b78 1b5bd5fd
-          5a000000 0049454e 44ae4260 82
-        </rawimagedata>
-      </cbdt_bitmap_format_17>
-      <cbdt_bitmap_format_17 name="uni2049">
-        <SmallGlyphMetrics>
-          <height value="128"/>
-          <width value="136"/>
-          <BearingX value="0"/>
-          <BearingY value="101"/>
-          <Advance value="136"/>
-        </SmallGlyphMetrics>
-        <rawimagedata>
-          89504e47 0d0a1a0a 0000000d 49484452
-          00000088 00000080 08030000 00e737d1
-          0d000001 3b504c54 454c6971 d73b3bd9
-          4141da44 44d94141 d94242d5 3737d83f
-          3fd84040 d94040d9 4141d941 41d53838
-          d13030d8 3f3fee4a 4af74d4d e34545eb
-          4747ff50 50fe5050 fe4e4eda 4242fe4f
-          4ffb4747 d94040d3 3434fd4c 4ce14040
-          f34747fc 4b4bd83e 3eeb4242 fb4949fa
-          4545d639 39d02e2e dc3a3aef 3f3fd333
-          33f94343 d43737f8 4141f740 40ed3939
-          e13434d3 3434cf2b 2bf63e3e f53c3cd2
-          3131f439 39d02c2c cc2626d0 2d2df337
-          37f23535 e83030cf 2b2bf132 32ce2929
-          dd2b2bcb 2222f030 30cb2323 d42525cd
-          2626ef2d 2dc81d1d c31313cb 2222eb25
-          25ee2929 c81b1bdb 2121c91f 1fec2525
-          ea2222eb 2424c71a 1ac10c0c c61919c0
-          0a0ac00a 0ac20c0c c10c0cd1 0b0bda0c
-          0cc00a0a e10c0cc1 0808be06 06df0909
-          cb0202de 0606d403 03bc0202 dc0303b9
-          0000b800 00da0101 b80000b9 0000b800
-          00b70000 fbff4a1d 00000068 74524e53
-          0040cfff df583080 afbfef8f 10209fff
-          ffffffff ffffffff ffff70ff ffffffff
-          ffffffff 60ffffef ffffffff ffffffbf
-          ffffffff 9fd5ffff ffffffff ffff80ff
-          8fffffff ef40ffff ffbfffff ffffffff
-          a0ff50df ff8fffff 8fffffff ffffffff
-          ffffdf9f ff50ff8f 9e461cce 00000655
-          49444154 7801ec96 e9e2e22a 0c476ff7
-          55812254 dcfabfef ff929320 636b6c71
-          c3d98fdf f0977808 a8fdef1f ff788128
-          4e6e48b3 7b557956 94553d56 c4555344
-          ed3b1e59 328bcf64 95954e81 1237d9cb
-          2269324b ba946fb3 2af151af f3d744a0
-          96710283 c5d5bc46 719985e8 189b9430
-          7171a9b2 1745b824 7058cc7d 1a827179
-          0be79d70 2a513891 b96b9d3a 8b8d5c04
-          a78934ed c744dae6 ac31492b 3e833c1f
-          529a7f48 64156b00 34b81f6c c6120d3c
-          7953a0e2 56041649 2caf612d 614b6320
-          6c843509 2f821ebe 7110140c c59a0417
-          b11e5dbf d928fe20 ea691314 d910a848
-          6b3dfc16 0437933c ac486c3d 36923f07
-          54a56d48 9102ef47 3f734b7b c63a21ec
-          4f6ccf29 b2c79934 0f8ba45a b39e702d
-          92a387ea a949dfe9 291da32e 4a8a670e
-          a79a1161 30d3ab84 e654830b 4d49ae55
-          94b41baa de1419eb 236d1357 26dbef1a
-          55d514f8 60a22d82 13153c9c 28944865
-          8c564a49 b5e5eea5 943640dd 8c9fb1da
-          c506d05c f131266d 70fda888 319d2274
-          c65c4472 e3025272 47af5123 bb79d23b
-          9b8c833b 77326d18 9106baef ad08771b
-          e5e851ce b45f1b9b e5e34014 87a52c8c
-          486a8c50 167749e4 c14ce74d 4d84cd21
-          0a398073 10113c99 e3dea2e0 fced9bcb
-          e75eda34 de26f4c6 224c3f2e b2274c44
-          0a9cb643 49789da0 73bcd4ac ad8d1198
-          430d2b82 67138510 29b1f3c5 449db798
-          2f35436f c3210749 87366617 4224a56f
-          fbbf906d 4df3c298 e62191c6 18e111b1
-          873ee1e8 ff1ae07d 3d2cf5f2 53cc8888
-          cbae231c 35e95bfb da655040 45d27744
-          0a27320c 43779c70 1806ef06 5750703c
-          4d38c2c2 6322c370 3811e0d3 5004a987
-          1bfc77ef 5322d940 895b6fbf 7818bec2
-          8ba0493c 4ca9d7c4 8352bd23 f23fc18a
-          bc088a4c 7bfd13f9 65446a10 d94ef87a
-          46644b78 43a4c5af 2f11a9be 114717ba
-          11c34010 40b74cee 89a10ca6 630ef9ff
-          3fac7315 d99b8241 ca8d78a5 993c3951
-          cd0b340b 217cee93 6d8da29a 2752ca4f
-          96372915 e5e54e4a cdb71eb3 21389d50
-          5ecea57c f6a70cb6 2e8f0051 a81a7fea
-          594a4b47 80dc48a9 c77eb494 a378c898
-          251ba2d0 7cf7970c 9f1a0622 ec0f0f72
-          4e9190c9 64c22138 6541ae51 34c183e0
-          f0383ce4 113d3df5 a327132b 12205396
-          3c889a20 337fc7e0 70454343 2e2d6ac6
-          9f99c984 0721c1ea 6910e698 07330b5c
-          144567b9 5c9a5910 83934876 a034efcd
-          aca81492 e358042b eb094e97 89907590
-          68087384 2b1aa72b 4a83ccc3 89394ea5
-          8ed922f1 c7144098 6313e4b0 614532a4
-          3f52ec40 2e694808 1cdbedb6 e7c04d51
-          5a50e110 9cca1c5b e4913220 bb202910
-          f1ede07d 644f8342 4455e060 59fdb814
-          5baeeb7a d104996f 71cb7060 8b4f2dea
-          ba8aebee f1cd2d73 d4dc5104 594555d5
-          c1d1963b 4a21f716 1f9db77e 921d0cd2
-          068985a0 597741b3 2b70d0ca 390e712e
-          06f2e878 b373c89e 068608eb 5cdd777c
-          1143c74a 0ac25014 865359b1 2f604d6f
-          2305eb05 f50a27c8 d1d57dff 9759ab4d
-          120b329b ccf20fed c97c97ad 290639a4
-          41f622d2 1ebcda4f 11a9cddf 2122dd21
-          a8135986 5412efd2 1d4521bd 881ca395
-          9cccff43 9ad7ece8 d5cad22a e1b4f331
-          2805b251 d53618a9 ea471e44 35829c55
-          fb8495fa 9b8bba51 06e4e297 04d9a976
-          fea8531d aa321057 0a442388 aaeecd0a
-          90118075 8ba905b0 c9850031 045882d4
-          0026af0e 684c01c8 14e420cb 2337d917
-          825cdc97 00d94510 00f52a7f e40accde
-          c202d864 43c81842 2e411af2 176227db
-          91340520 b8f9d904 08c9bb37 99c9abc9
-          6d24790b 421ac4ba 8a416c10 c9716134
-          909c5d24 4f45205f 410990fe 1137e643
-          5eafdc83 129ead9a c8d19b22 90d977cc
-          49f7d5cf abeb399a fcaae1f1 5e6556a8
-          7f77f466 95b6c377 d090e9f8 698f0e76
-          1c048130 8e73da5b 1f8b3b11 4b5b953a
-          8222efff 043b241b 56d9c334 0e7be377
-          2bc9ff8b 50869b3c b889a669 9a0b3aa5
-          7ba455c7 6f18a4ee 332d990d c3bd3f51
-          179abba8 40f58979 20437c09 aba13c7b
-          645e3fcc 47abcf61 188e0dfe 7c0a2699
-          361fafec 91563ba2 19c77138 36031e48
-          c1a30f9b 7955d76f 281ddec5 bc4e0c1e
-          7564339d 900d49e1 e5a6025e 4f5d69b8
-          ff8c9d0a 16df996a de05aa21 e193ceef
-          c28c87b5 1b1200fc 1dc5c3af 0bcdbf7c
-          c88d6896 02e34388 d1ca0dc9 01d8a560
-          015ced86 e401c6a5 300278aa 590b5443
-          da420876 3db178b4 d56e682e 0498d783
-          194270f5 1b920c79 356f86ed 422305d3
-          9e566d7e e3b4e9c9 26c6187e 9b803f77
-          c1e62302 3b230b11 f98f9b24 377c7b3c
-          d9990d83 74317392 df306cde 45e4fc56
-          af691a86 6f38d2f4 13a054ea b3000000
-          0049454e 44ae4260 82 
-        </rawimagedata>
-      </cbdt_bitmap_format_17>
-    </strikedata>
-  </CBDT>
-
-  <CBLC>
-    <header version="3.0"/>
-    <strike index="0">
-      <bitmapSizeTable>
-        <sbitLineMetrics direction="hori">
-          <ascender value="101"/>
-          <descender value="-27"/>
-          <widthMax value="136"/>
-          <caretSlopeNumerator value="0"/>
-          <caretSlopeDenominator value="0"/>
-          <caretOffset value="0"/>
-          <minOriginSB value="0"/>
-          <minAdvanceSB value="0"/>
-          <maxBeforeBL value="0"/>
-          <minAfterBL value="0"/>
-          <pad1 value="0"/>
-          <pad2 value="0"/>
-        </sbitLineMetrics>
-        <sbitLineMetrics direction="vert">
-          <ascender value="101"/>
-          <descender value="-27"/>
-          <widthMax value="136"/>
-          <caretSlopeNumerator value="0"/>
-          <caretSlopeDenominator value="0"/>
-          <caretOffset value="0"/>
-          <minOriginSB value="0"/>
-          <minAdvanceSB value="0"/>
-          <maxBeforeBL value="0"/>
-          <minAfterBL value="0"/>
-          <pad1 value="0"/>
-          <pad2 value="0"/>
-        </sbitLineMetrics>
-        <colorRef value="0"/>
-        <startGlyphIndex value="1"/>
-        <endGlyphIndex value="3"/>
-        <ppemX value="109"/>
-        <ppemY value="109"/>
-        <bitDepth value="32"/>
-        <flags value="1"/>
-      </bitmapSizeTable>
-      <!-- GlyphIds are written but not read. The firstGlyphIndex and
-           lastGlyphIndex values will be recalculated by the compiler. -->
-      <eblc_index_sub_table_3 imageFormat="17" firstGlyphIndex="1" lastGlyphIndex="2">
-        <glyphLoc id="1" name="eight"/>
-        <glyphLoc id="2" name="registered"/>
-      </eblc_index_sub_table_3>
-      <eblc_index_sub_table_3 imageFormat="17" firstGlyphIndex="3" lastGlyphIndex="3">
-        <glyphLoc id="3" name="uni2049"/>
-      </eblc_index_sub_table_3>
-    </strike>
-  </CBLC>
-
-  <vhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="1275"/>
-    <descent value="-1275"/>
-    <lineGap value="0"/>
-    <advanceHeightMax value="2500"/>
-    <minTopSideBearing value="0"/>
-    <minBottomSideBearing value="0"/>
-    <yMaxExtent value="2400"/>
-    <caretSlopeRise value="0"/>
-    <caretSlopeRun value="1"/>
-    <caretOffset value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <reserved4 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfVMetrics value="1"/>
-  </vhea>
-
-  <vmtx>
-    <mtx name=".notdef" height="2500" tsb="0"/>
-    <mtx name="eight" height="2500" tsb="0"/>
-    <mtx name="registered" height="2500" tsb="0"/>
-    <mtx name="uni2049" height="2500" tsb="0"/>
-  </vmtx>
-
-</ttFont>
diff --git a/Tests/ttLib/tables/data/aots/classdef1_font1.ttx.GSUB b/Tests/ttLib/tables/data/aots/classdef1_font1.ttx.GSUB
index 7a8f510..21f1ab1 100644
--- a/Tests/ttLib/tables/data/aots/classdef1_font1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/classdef1_font1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g3"/>
           <Substitution in="g1" out="g4"/>
           <Substitution in="g10" out="g13"/>
@@ -140,7 +140,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g4"/>
           <Substitution in="g1" out="g5"/>
           <Substitution in="g10" out="g14"/>
@@ -247,7 +247,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g5"/>
           <Substitution in="g1" out="g6"/>
           <Substitution in="g10" out="g15"/>
@@ -355,7 +355,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value=".notdef"/>
             <Glyph value="g1"/>
             <Glyph value="g2"/>
@@ -457,7 +457,7 @@
             <Glyph value="g98"/>
             <Glyph value="g99"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="1">
             <ClassDef glyph="g18" class="1"/>
             <ClassDef glyph="g19" class="1"/>
             <ClassDef glyph="g20" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/classdef1_font2.ttx.GSUB b/Tests/ttLib/tables/data/aots/classdef1_font2.ttx.GSUB
index 563d6b6..ec7278e 100644
--- a/Tests/ttLib/tables/data/aots/classdef1_font2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/classdef1_font2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g3"/>
           <Substitution in="g1" out="g4"/>
           <Substitution in="g10" out="g13"/>
@@ -140,7 +140,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g4"/>
           <Substitution in="g1" out="g5"/>
           <Substitution in="g10" out="g14"/>
@@ -247,7 +247,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g5"/>
           <Substitution in="g1" out="g6"/>
           <Substitution in="g10" out="g15"/>
@@ -355,7 +355,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value=".notdef"/>
             <Glyph value="g1"/>
             <Glyph value="g2"/>
@@ -457,7 +457,7 @@
             <Glyph value="g98"/>
             <Glyph value="g99"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="1">
             <ClassDef glyph="g18" class="2"/>
             <ClassDef glyph="g19" class="2"/>
             <ClassDef glyph="g20" class="2"/>
diff --git a/Tests/ttLib/tables/data/aots/classdef1_font3.ttx.GSUB b/Tests/ttLib/tables/data/aots/classdef1_font3.ttx.GSUB
index 0bcbc72..9bc1e43 100644
--- a/Tests/ttLib/tables/data/aots/classdef1_font3.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/classdef1_font3.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g3"/>
           <Substitution in="g1" out="g4"/>
           <Substitution in="g10" out="g13"/>
@@ -140,7 +140,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g4"/>
           <Substitution in="g1" out="g5"/>
           <Substitution in="g10" out="g14"/>
@@ -247,7 +247,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g5"/>
           <Substitution in="g1" out="g6"/>
           <Substitution in="g10" out="g15"/>
@@ -355,7 +355,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value=".notdef"/>
             <Glyph value="g1"/>
             <Glyph value="g2"/>
@@ -457,7 +457,7 @@
             <Glyph value="g98"/>
             <Glyph value="g99"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="1">
             <ClassDef glyph="g18" class="2"/>
             <ClassDef glyph="g19" class="2"/>
             <ClassDef glyph="g20" class="2"/>
diff --git a/Tests/ttLib/tables/data/aots/classdef1_font4.ttx.GSUB b/Tests/ttLib/tables/data/aots/classdef1_font4.ttx.GSUB
index dce2706..681240d 100644
--- a/Tests/ttLib/tables/data/aots/classdef1_font4.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/classdef1_font4.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g3"/>
           <Substitution in="g1" out="g4"/>
           <Substitution in="g10" out="g13"/>
@@ -140,7 +140,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g4"/>
           <Substitution in="g1" out="g5"/>
           <Substitution in="g10" out="g14"/>
@@ -247,7 +247,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g5"/>
           <Substitution in="g1" out="g6"/>
           <Substitution in="g10" out="g15"/>
@@ -355,7 +355,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value=".notdef"/>
             <Glyph value="g1"/>
             <Glyph value="g2"/>
@@ -457,7 +457,7 @@
             <Glyph value="g98"/>
             <Glyph value="g99"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="1">
           </ClassDef>
           <!-- SubClassSetCount=1 -->
           <SubClassSet index="0" empty="1"/>
diff --git a/Tests/ttLib/tables/data/aots/classdef2_font1.ttx.GSUB b/Tests/ttLib/tables/data/aots/classdef2_font1.ttx.GSUB
index 7a8f510..f602354 100644
--- a/Tests/ttLib/tables/data/aots/classdef2_font1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/classdef2_font1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g3"/>
           <Substitution in="g1" out="g4"/>
           <Substitution in="g10" out="g13"/>
@@ -140,7 +140,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g4"/>
           <Substitution in="g1" out="g5"/>
           <Substitution in="g10" out="g14"/>
@@ -247,7 +247,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g5"/>
           <Substitution in="g1" out="g6"/>
           <Substitution in="g10" out="g15"/>
@@ -355,7 +355,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value=".notdef"/>
             <Glyph value="g1"/>
             <Glyph value="g2"/>
@@ -457,7 +457,7 @@
             <Glyph value="g98"/>
             <Glyph value="g99"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g18" class="1"/>
             <ClassDef glyph="g19" class="1"/>
             <ClassDef glyph="g20" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/classdef2_font2.ttx.GSUB b/Tests/ttLib/tables/data/aots/classdef2_font2.ttx.GSUB
index 563d6b6..d4650bd 100644
--- a/Tests/ttLib/tables/data/aots/classdef2_font2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/classdef2_font2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g3"/>
           <Substitution in="g1" out="g4"/>
           <Substitution in="g10" out="g13"/>
@@ -140,7 +140,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g4"/>
           <Substitution in="g1" out="g5"/>
           <Substitution in="g10" out="g14"/>
@@ -247,7 +247,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g5"/>
           <Substitution in="g1" out="g6"/>
           <Substitution in="g10" out="g15"/>
@@ -355,7 +355,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value=".notdef"/>
             <Glyph value="g1"/>
             <Glyph value="g2"/>
@@ -457,7 +457,7 @@
             <Glyph value="g98"/>
             <Glyph value="g99"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g18" class="2"/>
             <ClassDef glyph="g19" class="2"/>
             <ClassDef glyph="g20" class="2"/>
diff --git a/Tests/ttLib/tables/data/aots/classdef2_font3.ttx.GSUB b/Tests/ttLib/tables/data/aots/classdef2_font3.ttx.GSUB
index 0bcbc72..7cb045f 100644
--- a/Tests/ttLib/tables/data/aots/classdef2_font3.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/classdef2_font3.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g3"/>
           <Substitution in="g1" out="g4"/>
           <Substitution in="g10" out="g13"/>
@@ -140,7 +140,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g4"/>
           <Substitution in="g1" out="g5"/>
           <Substitution in="g10" out="g14"/>
@@ -247,7 +247,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g5"/>
           <Substitution in="g1" out="g6"/>
           <Substitution in="g10" out="g15"/>
@@ -355,7 +355,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value=".notdef"/>
             <Glyph value="g1"/>
             <Glyph value="g2"/>
@@ -457,7 +457,7 @@
             <Glyph value="g98"/>
             <Glyph value="g99"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g18" class="2"/>
             <ClassDef glyph="g19" class="2"/>
             <ClassDef glyph="g20" class="2"/>
diff --git a/Tests/ttLib/tables/data/aots/classdef2_font4.ttx.GSUB b/Tests/ttLib/tables/data/aots/classdef2_font4.ttx.GSUB
index dce2706..90f0b93 100644
--- a/Tests/ttLib/tables/data/aots/classdef2_font4.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/classdef2_font4.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g3"/>
           <Substitution in="g1" out="g4"/>
           <Substitution in="g10" out="g13"/>
@@ -140,7 +140,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g4"/>
           <Substitution in="g1" out="g5"/>
           <Substitution in="g10" out="g14"/>
@@ -247,7 +247,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in=".notdef" out="g5"/>
           <Substitution in="g1" out="g6"/>
           <Substitution in="g10" out="g15"/>
@@ -355,7 +355,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value=".notdef"/>
             <Glyph value="g1"/>
             <Glyph value="g2"/>
@@ -457,7 +457,7 @@
             <Glyph value="g98"/>
             <Glyph value="g99"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
           </ClassDef>
           <!-- SubClassSetCount=1 -->
           <SubClassSet index="0" empty="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos1_1_lookupflag_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos1_1_lookupflag_f1.ttx.GDEF
index 08e65de..971a3f1 100644
--- a/Tests/ttLib/tables/data/aots/gpos1_1_lookupflag_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos1_1_lookupflag_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g18" class="1"/>
     </GlyphClassDef>
   </GDEF>
diff --git a/Tests/ttLib/tables/data/aots/gpos1_1_lookupflag_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos1_1_lookupflag_f1.ttx.GPOS
index 3ab19a6..93d3a05 100644
--- a/Tests/ttLib/tables/data/aots/gpos1_1_lookupflag_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos1_1_lookupflag_f1.ttx.GPOS
@@ -31,10 +31,10 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="1"/>
-        <LookupFlag value="2"/><!-- ignoreBaseGlyphs -->
+        <LookupFlag value="2"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g18"/>
             <Glyph value="g20"/>
           </Coverage>
diff --git a/Tests/ttLib/tables/data/aots/gpos1_1_simple_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos1_1_simple_f1.ttx.GPOS
index 508d14e..00eacc3 100644
--- a/Tests/ttLib/tables/data/aots/gpos1_1_simple_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos1_1_simple_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g18"/>
             <Glyph value="g20"/>
           </Coverage>
diff --git a/Tests/ttLib/tables/data/aots/gpos1_1_simple_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos1_1_simple_f2.ttx.GPOS
index ef78ece..1eff021 100644
--- a/Tests/ttLib/tables/data/aots/gpos1_1_simple_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos1_1_simple_f2.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g18"/>
             <Glyph value="g20"/>
           </Coverage>
diff --git a/Tests/ttLib/tables/data/aots/gpos1_1_simple_f3.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos1_1_simple_f3.ttx.GPOS
index 523b139..c3850df 100644
--- a/Tests/ttLib/tables/data/aots/gpos1_1_simple_f3.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos1_1_simple_f3.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g18"/>
             <Glyph value="g20"/>
           </Coverage>
diff --git a/Tests/ttLib/tables/data/aots/gpos1_1_simple_f4.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos1_1_simple_f4.ttx.GPOS
index 027d687..f80286c 100644
--- a/Tests/ttLib/tables/data/aots/gpos1_1_simple_f4.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos1_1_simple_f4.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g18"/>
             <Glyph value="g20"/>
           </Coverage>
diff --git a/Tests/ttLib/tables/data/aots/gpos1_2_font1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos1_2_font1.ttx.GPOS
index 058c302..11351a6 100644
--- a/Tests/ttLib/tables/data/aots/gpos1_2_font1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos1_2_font1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g18"/>
             <Glyph value="g20"/>
           </Coverage>
diff --git a/Tests/ttLib/tables/data/aots/gpos1_2_font2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos1_2_font2.ttx.GDEF
index 08e65de..971a3f1 100644
--- a/Tests/ttLib/tables/data/aots/gpos1_2_font2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos1_2_font2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g18" class="1"/>
     </GlyphClassDef>
   </GDEF>
diff --git a/Tests/ttLib/tables/data/aots/gpos1_2_font2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos1_2_font2.ttx.GPOS
index 2b557f7..88257ac 100644
--- a/Tests/ttLib/tables/data/aots/gpos1_2_font2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos1_2_font2.ttx.GPOS
@@ -31,10 +31,10 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="1"/>
-        <LookupFlag value="2"/><!-- ignoreBaseGlyphs -->
+        <LookupFlag value="2"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g18"/>
             <Glyph value="g20"/>
           </Coverage>
diff --git a/Tests/ttLib/tables/data/aots/gpos2_1_font6.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos2_1_font6.ttx.GPOS
index e27e72b..db1315b 100644
--- a/Tests/ttLib/tables/data/aots/gpos2_1_font6.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos2_1_font6.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g18"/>
           </Coverage>
           <ValueFormat1 value="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos2_1_font7.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos2_1_font7.ttx.GPOS
index 01f6b45..8b22294 100644
--- a/Tests/ttLib/tables/data/aots/gpos2_1_font7.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos2_1_font7.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g18"/>
             <Glyph value="g21"/>
           </Coverage>
diff --git a/Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f1.ttx.GDEF
index 08e65de..971a3f1 100644
--- a/Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g18" class="1"/>
     </GlyphClassDef>
   </GDEF>
diff --git a/Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f1.ttx.GPOS
index 329315c..06b0691 100644
--- a/Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f1.ttx.GPOS
@@ -31,10 +31,10 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="2"/><!-- ignoreBaseGlyphs -->
+        <LookupFlag value="2"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g19"/>
           </Coverage>
           <ValueFormat1 value="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f2.ttx.GDEF
index 08e65de..971a3f1 100644
--- a/Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g18" class="1"/>
     </GlyphClassDef>
   </GDEF>
diff --git a/Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f2.ttx.GPOS
index 5650616..03e9f8b 100644
--- a/Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos2_1_lookupflag_f2.ttx.GPOS
@@ -31,10 +31,10 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="2"/><!-- ignoreBaseGlyphs -->
+        <LookupFlag value="2"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g19"/>
           </Coverage>
           <ValueFormat1 value="4"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos2_1_next_glyph_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos2_1_next_glyph_f1.ttx.GPOS
index e5f8cc7..d8b4e83 100644
--- a/Tests/ttLib/tables/data/aots/gpos2_1_next_glyph_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos2_1_next_glyph_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g18"/>
           </Coverage>
           <ValueFormat1 value="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos2_1_next_glyph_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos2_1_next_glyph_f2.ttx.GPOS
index 820bea6..cf71f47 100644
--- a/Tests/ttLib/tables/data/aots/gpos2_1_next_glyph_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos2_1_next_glyph_f2.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g18"/>
           </Coverage>
           <ValueFormat1 value="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos2_1_simple_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos2_1_simple_f1.ttx.GPOS
index 55b8402..81b1720 100644
--- a/Tests/ttLib/tables/data/aots/gpos2_1_simple_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos2_1_simple_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g18"/>
           </Coverage>
           <ValueFormat1 value="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos2_2_font1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos2_2_font1.ttx.GPOS
index d41d02d..5595b99 100644
--- a/Tests/ttLib/tables/data/aots/gpos2_2_font1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos2_2_font1.ttx.GPOS
@@ -34,15 +34,15 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g18"/>
           </Coverage>
           <ValueFormat1 value="1"/>
           <ValueFormat2 value="2"/>
-          <ClassDef1>
+          <ClassDef1 Format="2">
             <ClassDef glyph="g18" class="1"/>
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="2">
             <ClassDef glyph="g19" class="1"/>
           </ClassDef2>
           <!-- Class1Count=2 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos2_2_font2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos2_2_font2.ttx.GDEF
index 08e65de..971a3f1 100644
--- a/Tests/ttLib/tables/data/aots/gpos2_2_font2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos2_2_font2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g18" class="1"/>
     </GlyphClassDef>
   </GDEF>
diff --git a/Tests/ttLib/tables/data/aots/gpos2_2_font2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos2_2_font2.ttx.GPOS
index c7f3f32..7896be3 100644
--- a/Tests/ttLib/tables/data/aots/gpos2_2_font2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos2_2_font2.ttx.GPOS
@@ -31,18 +31,18 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="2"/><!-- ignoreBaseGlyphs -->
+        <LookupFlag value="2"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g19"/>
           </Coverage>
           <ValueFormat1 value="1"/>
           <ValueFormat2 value="2"/>
-          <ClassDef1>
+          <ClassDef1 Format="2">
             <ClassDef glyph="g19" class="1"/>
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="2">
             <ClassDef glyph="g20" class="1"/>
           </ClassDef2>
           <!-- Class1Count=2 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos2_2_font3.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos2_2_font3.ttx.GDEF
index 08e65de..971a3f1 100644
--- a/Tests/ttLib/tables/data/aots/gpos2_2_font3.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos2_2_font3.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g18" class="1"/>
     </GlyphClassDef>
   </GDEF>
diff --git a/Tests/ttLib/tables/data/aots/gpos2_2_font3.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos2_2_font3.ttx.GPOS
index 25ac07c..216a591 100644
--- a/Tests/ttLib/tables/data/aots/gpos2_2_font3.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos2_2_font3.ttx.GPOS
@@ -31,18 +31,18 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="2"/><!-- ignoreBaseGlyphs -->
+        <LookupFlag value="2"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g19"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="2"/>
-          <ClassDef1>
+          <ClassDef1 Format="2">
             <ClassDef glyph="g19" class="1"/>
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="2">
             <ClassDef glyph="g20" class="1"/>
           </ClassDef2>
           <!-- Class1Count=2 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos2_2_font4.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos2_2_font4.ttx.GPOS
index 46f3e6e..a2e6017 100644
--- a/Tests/ttLib/tables/data/aots/gpos2_2_font4.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos2_2_font4.ttx.GPOS
@@ -34,15 +34,15 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g18"/>
           </Coverage>
           <ValueFormat1 value="1"/>
           <ValueFormat2 value="2"/>
-          <ClassDef1>
+          <ClassDef1 Format="2">
             <ClassDef glyph="g18" class="1"/>
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="2">
             <ClassDef glyph="g18" class="1"/>
           </ClassDef2>
           <!-- Class1Count=2 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos2_2_font5.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos2_2_font5.ttx.GPOS
index 1d589ca..d269735 100644
--- a/Tests/ttLib/tables/data/aots/gpos2_2_font5.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos2_2_font5.ttx.GPOS
@@ -34,15 +34,15 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g18"/>
           </Coverage>
           <ValueFormat1 value="1"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="2">
             <ClassDef glyph="g18" class="1"/>
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="2">
             <ClassDef glyph="g18" class="1"/>
           </ClassDef2>
           <!-- Class1Count=2 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos3_font1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos3_font1.ttx.GPOS
index 8babfbf..8cbdbc7 100644
--- a/Tests/ttLib/tables/data/aots/gpos3_font1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos3_font1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <CursivePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g18"/>
             <Glyph value="g19"/>
           </Coverage>
diff --git a/Tests/ttLib/tables/data/aots/gpos3_font2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos3_font2.ttx.GDEF
index d2981b4..b5ca1ed 100644
--- a/Tests/ttLib/tables/data/aots/gpos3_font2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos3_font2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g21" class="1"/>
     </GlyphClassDef>
   </GDEF>
diff --git a/Tests/ttLib/tables/data/aots/gpos3_font2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos3_font2.ttx.GPOS
index 378af37..3ded3a7 100644
--- a/Tests/ttLib/tables/data/aots/gpos3_font2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos3_font2.ttx.GPOS
@@ -31,10 +31,10 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="3"/>
-        <LookupFlag value="2"/><!-- ignoreBaseGlyphs -->
+        <LookupFlag value="2"/>
         <!-- SubTableCount=1 -->
         <CursivePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g18"/>
             <Glyph value="g19"/>
           </Coverage>
diff --git a/Tests/ttLib/tables/data/aots/gpos3_font3.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos3_font3.ttx.GDEF
index d2981b4..b5ca1ed 100644
--- a/Tests/ttLib/tables/data/aots/gpos3_font3.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos3_font3.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g21" class="1"/>
     </GlyphClassDef>
   </GDEF>
diff --git a/Tests/ttLib/tables/data/aots/gpos3_font3.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos3_font3.ttx.GPOS
index 7da5f5e..e6a1c04 100644
--- a/Tests/ttLib/tables/data/aots/gpos3_font3.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos3_font3.ttx.GPOS
@@ -31,10 +31,10 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="3"/>
-        <LookupFlag value="2"/><!-- ignoreBaseGlyphs -->
+        <LookupFlag value="2"/>
         <!-- SubTableCount=1 -->
         <CursivePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g18"/>
             <Glyph value="g19"/>
             <Glyph value="g20"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos4_lookupflag_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos4_lookupflag_f1.ttx.GDEF
index e6b3946..5118ad8 100644
--- a/Tests/ttLib/tables/data/aots/gpos4_lookupflag_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos4_lookupflag_f1.ttx.GDEF
@@ -3,13 +3,13 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g17" class="1"/>
       <ClassDef glyph="g18" class="1"/>
       <ClassDef glyph="g19" class="3"/>
       <ClassDef glyph="g20" class="3"/>
     </GlyphClassDef>
-    <MarkAttachClassDef>
+    <MarkAttachClassDef Format="2">
       <ClassDef glyph="g19" class="1"/>
       <ClassDef glyph="g20" class="2"/>
     </MarkAttachClassDef>
diff --git a/Tests/ttLib/tables/data/aots/gpos4_lookupflag_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos4_lookupflag_f1.ttx.GPOS
index d7526b5..744eaaa 100644
--- a/Tests/ttLib/tables/data/aots/gpos4_lookupflag_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos4_lookupflag_f1.ttx.GPOS
@@ -31,13 +31,13 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="4"/>
-        <LookupFlag value="2"/><!-- ignoreBaseGlyphs -->
+        <LookupFlag value="2"/>
         <!-- SubTableCount=1 -->
         <MarkBasePos index="0" Format="1">
-          <MarkCoverage>
+          <MarkCoverage Format="1">
             <Glyph value="g19"/>
           </MarkCoverage>
-          <BaseCoverage>
+          <BaseCoverage Format="1">
             <Glyph value="g18"/>
           </BaseCoverage>
           <!-- ClassCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos4_lookupflag_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos4_lookupflag_f2.ttx.GDEF
index 8184af2..2627f21 100644
--- a/Tests/ttLib/tables/data/aots/gpos4_lookupflag_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos4_lookupflag_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g17" class="1"/>
       <ClassDef glyph="g18" class="1"/>
       <ClassDef glyph="g19" class="3"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos4_lookupflag_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos4_lookupflag_f2.ttx.GPOS
index 3efed82..7817336 100644
--- a/Tests/ttLib/tables/data/aots/gpos4_lookupflag_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos4_lookupflag_f2.ttx.GPOS
@@ -31,13 +31,13 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <MarkBasePos index="0" Format="1">
-          <MarkCoverage>
+          <MarkCoverage Format="1">
             <Glyph value="g19"/>
           </MarkCoverage>
-          <BaseCoverage>
+          <BaseCoverage Format="1">
             <Glyph value="g18"/>
           </BaseCoverage>
           <!-- ClassCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos4_multiple_anchors_1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos4_multiple_anchors_1.ttx.GDEF
index a8df0fd..4f9f64a 100644
--- a/Tests/ttLib/tables/data/aots/gpos4_multiple_anchors_1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos4_multiple_anchors_1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g17" class="1"/>
       <ClassDef glyph="g18" class="1"/>
       <ClassDef glyph="g19" class="3"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos4_multiple_anchors_1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos4_multiple_anchors_1.ttx.GPOS
index cfd3ddb..afe7e6a 100644
--- a/Tests/ttLib/tables/data/aots/gpos4_multiple_anchors_1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos4_multiple_anchors_1.ttx.GPOS
@@ -34,13 +34,13 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <MarkBasePos index="0" Format="1">
-          <MarkCoverage>
+          <MarkCoverage Format="1">
             <Glyph value="g19"/>
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
           </MarkCoverage>
-          <BaseCoverage>
+          <BaseCoverage Format="1">
             <Glyph value="g17"/>
             <Glyph value="g18"/>
           </BaseCoverage>
diff --git a/Tests/ttLib/tables/data/aots/gpos4_simple_1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos4_simple_1.ttx.GDEF
index 8184af2..2627f21 100644
--- a/Tests/ttLib/tables/data/aots/gpos4_simple_1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos4_simple_1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g17" class="1"/>
       <ClassDef glyph="g18" class="1"/>
       <ClassDef glyph="g19" class="3"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos4_simple_1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos4_simple_1.ttx.GPOS
index ccbc784..3a2e623 100644
--- a/Tests/ttLib/tables/data/aots/gpos4_simple_1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos4_simple_1.ttx.GPOS
@@ -34,10 +34,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <MarkBasePos index="0" Format="1">
-          <MarkCoverage>
+          <MarkCoverage Format="1">
             <Glyph value="g19"/>
           </MarkCoverage>
-          <BaseCoverage>
+          <BaseCoverage Format="1">
             <Glyph value="g18"/>
           </BaseCoverage>
           <!-- ClassCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos5_font1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos5_font1.ttx.GDEF
index 461a982..ff2dc98 100644
--- a/Tests/ttLib/tables/data/aots/gpos5_font1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos5_font1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g17" class="1"/>
       <ClassDef glyph="g18" class="2"/>
       <ClassDef glyph="g19" class="3"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos5_font1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos5_font1.ttx.GPOS
index d5abadc..b5017b3 100644
--- a/Tests/ttLib/tables/data/aots/gpos5_font1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos5_font1.ttx.GPOS
@@ -34,10 +34,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <MarkLigPos index="0" Format="1">
-          <MarkCoverage>
+          <MarkCoverage Format="1">
             <Glyph value="g19"/>
           </MarkCoverage>
-          <LigatureCoverage>
+          <LigatureCoverage Format="1">
             <Glyph value="g18"/>
           </LigatureCoverage>
           <!-- ClassCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos5_font1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gpos5_font1.ttx.GSUB
index f81552a..85d3308 100644
--- a/Tests/ttLib/tables/data/aots/gpos5_font1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gpos5_font1.ttx.GSUB
@@ -31,9 +31,9 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g30">
             <Ligature components="g31" glyph="g18"/>
           </LigatureSet>
diff --git a/Tests/ttLib/tables/data/aots/gpos6_font1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos6_font1.ttx.GDEF
index f07a29b..640f3eb 100644
--- a/Tests/ttLib/tables/data/aots/gpos6_font1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos6_font1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g17" class="1"/>
       <ClassDef glyph="g18" class="3"/>
       <ClassDef glyph="g19" class="3"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos6_font1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos6_font1.ttx.GPOS
index f2fd253..d4c4da5 100644
--- a/Tests/ttLib/tables/data/aots/gpos6_font1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos6_font1.ttx.GPOS
@@ -34,10 +34,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <MarkMarkPos index="0" Format="1">
-          <Mark1Coverage>
+          <Mark1Coverage Format="1">
             <Glyph value="g19"/>
           </Mark1Coverage>
-          <Mark2Coverage>
+          <Mark2Coverage Format="1">
             <Glyph value="g18"/>
           </Mark2Coverage>
           <!-- ClassCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos7_1_font1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos7_1_font1.ttx.GPOS
index db3b76e..3d82e68 100644
--- a/Tests/ttLib/tables/data/aots/gpos7_1_font1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos7_1_font1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g18"/>
             <Glyph value="g19"/>
             <Glyph value="g20"/>
@@ -51,7 +51,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g18"/>
           </Coverage>
           <!-- PosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos9_font1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos9_font1.ttx.GPOS
index 9bcef94..bbc1c38 100644
--- a/Tests/ttLib/tables/data/aots/gpos9_font1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos9_font1.ttx.GPOS
@@ -36,7 +36,7 @@
         <ExtensionPos index="0" Format="1">
           <ExtensionLookupType value="1"/>
           <SinglePos Format="1">
-            <Coverage>
+            <Coverage Format="1">
               <Glyph value="g18"/>
               <Glyph value="g20"/>
             </Coverage>
diff --git a/Tests/ttLib/tables/data/aots/gpos9_font2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos9_font2.ttx.GPOS
index ffb993b..ac6d6af 100644
--- a/Tests/ttLib/tables/data/aots/gpos9_font2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos9_font2.ttx.GPOS
@@ -36,7 +36,7 @@
         <ExtensionPos index="0" Format="1">
           <ExtensionLookupType value="1"/>
           <SinglePos Format="1">
-            <Coverage>
+            <Coverage Format="1">
               <Glyph value="g18"/>
               <Glyph value="g20"/>
             </Coverage>
@@ -47,7 +47,7 @@
         <ExtensionPos index="1" Format="1">
           <ExtensionLookupType value="1"/>
           <SinglePos Format="1">
-            <Coverage>
+            <Coverage Format="1">
               <Glyph value="g19"/>
               <Glyph value="g21"/>
             </Coverage>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f1.ttx.GPOS
index a701d03..ea85d9f 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <!-- ChainPosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f2.ttx.GPOS
index 865a69b..bd176ba 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f2.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <!-- ChainPosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f3.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f3.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f3.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f3.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f3.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f3.ttx.GPOS
index f36b48a..b189067 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f3.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f3.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <!-- ChainPosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f4.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f4.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f4.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f4.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f4.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f4.ttx.GPOS
index d497f58..f750652 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f4.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_boundary_f4.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g22"/>
           </Coverage>
           <!-- ChainPosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_lookupflag_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining1_lookupflag_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_lookupflag_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_lookupflag_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_lookupflag_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining1_lookupflag_f1.ttx.GPOS
index 540a00e..b07a9ba 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_lookupflag_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_lookupflag_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -97,10 +97,10 @@
       </Lookup>
       <Lookup index="4">
         <LookupType value="8"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g22"/>
           </Coverage>
           <!-- ChainPosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f1.ttx.GPOS
index 81374bc..09b5bd8 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <!-- ChainPosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f2.ttx.GPOS
index 404e929..e8fb516 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_multiple_subrules_f2.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <!-- ChainPosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_next_glyph_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining1_next_glyph_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_next_glyph_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_next_glyph_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_next_glyph_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining1_next_glyph_f1.ttx.GPOS
index 87be738..1f7539e 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_next_glyph_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_next_glyph_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
             <Glyph value="g23"/>
           </Coverage>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f1.ttx.GPOS
index c755f87..1780fda 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <!-- ChainPosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f2.ttx.GPOS
index e211d85..c2d3411 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_simple_f2.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g22"/>
           </Coverage>
           <!-- ChainPosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_successive_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining1_successive_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_successive_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_successive_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining1_successive_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining1_successive_f1.ttx.GPOS
index a2da259..3960d8a 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining1_successive_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining1_successive_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- ChainPosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f1.ttx.GPOS
index f8b5eac..fe06077 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -109,7 +109,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -118,7 +118,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -127,7 +127,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f2.ttx.GPOS
index aa832de..c529371 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f2.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -109,7 +109,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -118,7 +118,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -127,7 +127,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f3.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f3.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f3.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f3.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f3.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f3.ttx.GPOS
index 6ee0bc9..fa55cf1 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f3.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f3.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -109,7 +109,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -118,7 +118,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -127,7 +127,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f4.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f4.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f4.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f4.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f4.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f4.ttx.GPOS
index 1acf6c4..f943402 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f4.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_boundary_f4.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -109,7 +109,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -118,7 +118,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -127,7 +127,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_lookupflag_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining2_lookupflag_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_lookupflag_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_lookupflag_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_lookupflag_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining2_lookupflag_f1.ttx.GPOS
index a5b4dec..b26d93b 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_lookupflag_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_lookupflag_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -97,10 +97,10 @@
       </Lookup>
       <Lookup index="4">
         <LookupType value="8"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -109,7 +109,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -118,7 +118,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -127,7 +127,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f1.ttx.GPOS
index c5b5253..33399ba 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -109,7 +109,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -118,7 +118,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -127,7 +127,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f2.ttx.GPOS
index b9512fa..dc10c2f 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_multiple_subrules_f2.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -109,7 +109,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -118,7 +118,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -127,7 +127,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_next_glyph_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining2_next_glyph_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_next_glyph_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_next_glyph_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_next_glyph_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining2_next_glyph_f1.ttx.GPOS
index b9e864d..9c18a9b 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_next_glyph_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_next_glyph_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -109,7 +109,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -118,7 +118,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -127,7 +127,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f1.ttx.GPOS
index 3fddfb2..decc575 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -109,7 +109,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -118,7 +118,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -127,7 +127,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f2.ttx.GPOS
index 248c52a..a35678d 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_simple_f2.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -109,7 +109,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -118,7 +118,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -127,7 +127,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_successive_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining2_successive_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_successive_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_successive_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining2_successive_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining2_successive_f1.ttx.GPOS
index 4914552..6775e5b 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining2_successive_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining2_successive_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -109,7 +109,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -118,7 +118,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -127,7 +127,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f1.ttx.GPOS
index 4a4f076..c362427 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -101,18 +101,18 @@
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="3">
           <!-- BacktrackGlyphCount=1 -->
-          <BacktrackCoverage index="0">
+          <BacktrackCoverage index="0" Format="1">
             <Glyph value="g20"/>
           </BacktrackCoverage>
           <!-- InputGlyphCount=2 -->
-          <InputCoverage index="0">
+          <InputCoverage index="0" Format="1">
             <Glyph value="g21"/>
           </InputCoverage>
-          <InputCoverage index="1">
+          <InputCoverage index="1" Format="1">
             <Glyph value="g22"/>
           </InputCoverage>
           <!-- LookAheadGlyphCount=1 -->
-          <LookAheadCoverage index="0">
+          <LookAheadCoverage index="0" Format="1">
             <Glyph value="g23"/>
           </LookAheadCoverage>
           <!-- PosCount=0 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f2.ttx.GPOS
index 4f38aec..7b27f90 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f2.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -101,18 +101,18 @@
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="3">
           <!-- BacktrackGlyphCount=1 -->
-          <BacktrackCoverage index="0">
+          <BacktrackCoverage index="0" Format="1">
             <Glyph value="g20"/>
           </BacktrackCoverage>
           <!-- InputGlyphCount=1 -->
-          <InputCoverage index="0">
+          <InputCoverage index="0" Format="1">
             <Glyph value="g21"/>
           </InputCoverage>
           <!-- LookAheadGlyphCount=2 -->
-          <LookAheadCoverage index="0">
+          <LookAheadCoverage index="0" Format="1">
             <Glyph value="g22"/>
           </LookAheadCoverage>
-          <LookAheadCoverage index="1">
+          <LookAheadCoverage index="1" Format="1">
             <Glyph value="g23"/>
           </LookAheadCoverage>
           <!-- PosCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f3.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f3.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f3.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f3.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f3.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f3.ttx.GPOS
index 4cde228..73df34c 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f3.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f3.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -102,14 +102,14 @@
         <ChainContextPos index="0" Format="3">
           <!-- BacktrackGlyphCount=0 -->
           <!-- InputGlyphCount=1 -->
-          <InputCoverage index="0">
+          <InputCoverage index="0" Format="1">
             <Glyph value="g21"/>
           </InputCoverage>
           <!-- LookAheadGlyphCount=2 -->
-          <LookAheadCoverage index="0">
+          <LookAheadCoverage index="0" Format="1">
             <Glyph value="g22"/>
           </LookAheadCoverage>
-          <LookAheadCoverage index="1">
+          <LookAheadCoverage index="1" Format="1">
             <Glyph value="g23"/>
           </LookAheadCoverage>
           <!-- PosCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f4.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f4.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f4.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f4.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f4.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f4.ttx.GPOS
index ab46ecb..67bfc0e 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f4.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining3_boundary_f4.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -101,14 +101,14 @@
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="3">
           <!-- BacktrackGlyphCount=2 -->
-          <BacktrackCoverage index="0">
+          <BacktrackCoverage index="0" Format="1">
             <Glyph value="g21"/>
           </BacktrackCoverage>
-          <BacktrackCoverage index="1">
+          <BacktrackCoverage index="1" Format="1">
             <Glyph value="g20"/>
           </BacktrackCoverage>
           <!-- InputGlyphCount=1 -->
-          <InputCoverage index="0">
+          <InputCoverage index="0" Format="1">
             <Glyph value="g22"/>
           </InputCoverage>
           <!-- LookAheadGlyphCount=0 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining3_lookupflag_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining3_lookupflag_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining3_lookupflag_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining3_lookupflag_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining3_lookupflag_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining3_lookupflag_f1.ttx.GPOS
index 2bc6f6b..b12b665 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining3_lookupflag_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining3_lookupflag_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -97,31 +97,31 @@
       </Lookup>
       <Lookup index="4">
         <LookupType value="8"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="3">
           <!-- BacktrackGlyphCount=2 -->
-          <BacktrackCoverage index="0">
+          <BacktrackCoverage index="0" Format="1">
             <Glyph value="g21"/>
           </BacktrackCoverage>
-          <BacktrackCoverage index="1">
+          <BacktrackCoverage index="1" Format="1">
             <Glyph value="g20"/>
           </BacktrackCoverage>
           <!-- InputGlyphCount=3 -->
-          <InputCoverage index="0">
+          <InputCoverage index="0" Format="1">
             <Glyph value="g22"/>
           </InputCoverage>
-          <InputCoverage index="1">
+          <InputCoverage index="1" Format="1">
             <Glyph value="g23"/>
           </InputCoverage>
-          <InputCoverage index="2">
+          <InputCoverage index="2" Format="1">
             <Glyph value="g24"/>
           </InputCoverage>
           <!-- LookAheadGlyphCount=2 -->
-          <LookAheadCoverage index="0">
+          <LookAheadCoverage index="0" Format="1">
             <Glyph value="g25"/>
           </LookAheadCoverage>
-          <LookAheadCoverage index="1">
+          <LookAheadCoverage index="1" Format="1">
             <Glyph value="g26"/>
           </LookAheadCoverage>
           <!-- PosCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining3_next_glyph_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining3_next_glyph_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining3_next_glyph_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining3_next_glyph_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining3_next_glyph_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining3_next_glyph_f1.ttx.GPOS
index 76be0ca..d5b0c1f 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining3_next_glyph_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining3_next_glyph_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -101,18 +101,18 @@
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="3">
           <!-- BacktrackGlyphCount=1 -->
-          <BacktrackCoverage index="0">
+          <BacktrackCoverage index="0" Format="1">
             <Glyph value="g22"/>
           </BacktrackCoverage>
           <!-- InputGlyphCount=2 -->
-          <InputCoverage index="0">
+          <InputCoverage index="0" Format="1">
             <Glyph value="g21"/>
           </InputCoverage>
-          <InputCoverage index="1">
+          <InputCoverage index="1" Format="1">
             <Glyph value="g22"/>
           </InputCoverage>
           <!-- LookAheadGlyphCount=1 -->
-          <LookAheadCoverage index="0">
+          <LookAheadCoverage index="0" Format="1">
             <Glyph value="g21"/>
           </LookAheadCoverage>
           <!-- PosCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f1.ttx.GPOS
index 4a3d10a..b9b0ce5 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -101,18 +101,18 @@
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="3">
           <!-- BacktrackGlyphCount=1 -->
-          <BacktrackCoverage index="0">
+          <BacktrackCoverage index="0" Format="1">
             <Glyph value="g20"/>
           </BacktrackCoverage>
           <!-- InputGlyphCount=2 -->
-          <InputCoverage index="0">
+          <InputCoverage index="0" Format="1">
             <Glyph value="g21"/>
           </InputCoverage>
-          <InputCoverage index="1">
+          <InputCoverage index="1" Format="1">
             <Glyph value="g22"/>
           </InputCoverage>
           <!-- LookAheadGlyphCount=1 -->
-          <LookAheadCoverage index="0">
+          <LookAheadCoverage index="0" Format="1">
             <Glyph value="g23"/>
           </LookAheadCoverage>
           <!-- PosCount=2 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f2.ttx.GPOS
index 1a1f57b..6d023ec 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining3_simple_f2.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -101,27 +101,27 @@
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="3">
           <!-- BacktrackGlyphCount=2 -->
-          <BacktrackCoverage index="0">
+          <BacktrackCoverage index="0" Format="1">
             <Glyph value="g21"/>
           </BacktrackCoverage>
-          <BacktrackCoverage index="1">
+          <BacktrackCoverage index="1" Format="1">
             <Glyph value="g20"/>
           </BacktrackCoverage>
           <!-- InputGlyphCount=3 -->
-          <InputCoverage index="0">
+          <InputCoverage index="0" Format="1">
             <Glyph value="g22"/>
           </InputCoverage>
-          <InputCoverage index="1">
+          <InputCoverage index="1" Format="1">
             <Glyph value="g23"/>
           </InputCoverage>
-          <InputCoverage index="2">
+          <InputCoverage index="2" Format="1">
             <Glyph value="g24"/>
           </InputCoverage>
           <!-- LookAheadGlyphCount=2 -->
-          <LookAheadCoverage index="0">
+          <LookAheadCoverage index="0" Format="1">
             <Glyph value="g25"/>
           </LookAheadCoverage>
-          <LookAheadCoverage index="1">
+          <LookAheadCoverage index="1" Format="1">
             <Glyph value="g26"/>
           </LookAheadCoverage>
           <!-- PosCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining3_successive_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_chaining3_successive_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining3_successive_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining3_successive_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_chaining3_successive_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_chaining3_successive_f1.ttx.GPOS
index 2c6ebb6..f7c85b6 100644
--- a/Tests/ttLib/tables/data/aots/gpos_chaining3_successive_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_chaining3_successive_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -101,24 +101,24 @@
         <!-- SubTableCount=1 -->
         <ChainContextPos index="0" Format="3">
           <!-- BacktrackGlyphCount=1 -->
-          <BacktrackCoverage index="0">
+          <BacktrackCoverage index="0" Format="1">
             <Glyph value="g25"/>
           </BacktrackCoverage>
           <!-- InputGlyphCount=4 -->
-          <InputCoverage index="0">
+          <InputCoverage index="0" Format="1">
             <Glyph value="g20"/>
           </InputCoverage>
-          <InputCoverage index="1">
+          <InputCoverage index="1" Format="1">
             <Glyph value="g21"/>
           </InputCoverage>
-          <InputCoverage index="2">
+          <InputCoverage index="2" Format="1">
             <Glyph value="g22"/>
           </InputCoverage>
-          <InputCoverage index="3">
+          <InputCoverage index="3" Format="1">
             <Glyph value="g23"/>
           </InputCoverage>
           <!-- LookAheadGlyphCount=1 -->
-          <LookAheadCoverage index="0">
+          <LookAheadCoverage index="0" Format="1">
             <Glyph value="g24"/>
           </LookAheadCoverage>
           <!-- PosCount=2 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_boundary_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context1_boundary_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_boundary_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_boundary_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_boundary_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context1_boundary_f1.ttx.GPOS
index e61cc4e..662ae54 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_boundary_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_boundary_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- PosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_boundary_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context1_boundary_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_boundary_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_boundary_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_boundary_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context1_boundary_f2.ttx.GPOS
index 70c9250..56a4f7b 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_boundary_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_boundary_f2.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- PosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_expansion_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context1_expansion_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_expansion_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_expansion_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_expansion_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context1_expansion_f1.ttx.GPOS
index ba6c146..77d52eb 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_expansion_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_expansion_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- PosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f1.ttx.GPOS
index 8688a39..2d5f796 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -97,10 +97,10 @@
       </Lookup>
       <Lookup index="4">
         <LookupType value="7"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- PosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f2.ttx.GPOS
index 8e2621f..ef419ff 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_lookupflag_f2.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -97,10 +97,10 @@
       </Lookup>
       <Lookup index="4">
         <LookupType value="7"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- PosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f1.ttx.GPOS
index 03cec90..82750d5 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- PosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f2.ttx.GPOS
index 652850f..764703b 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_multiple_subrules_f2.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- PosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_next_glyph_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context1_next_glyph_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_next_glyph_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_next_glyph_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_next_glyph_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context1_next_glyph_f1.ttx.GPOS
index 6ad207d..ac00f86 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_next_glyph_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_next_glyph_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- PosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_simple_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context1_simple_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_simple_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_simple_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_simple_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context1_simple_f1.ttx.GPOS
index a4c824f..031f56f 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_simple_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_simple_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- PosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_simple_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context1_simple_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_simple_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_simple_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_simple_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context1_simple_f2.ttx.GPOS
index 15faa22..bb3d01d 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_simple_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_simple_f2.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- PosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_successive_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context1_successive_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_successive_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_successive_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context1_successive_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context1_successive_f1.ttx.GPOS
index 11ae1c7..2d17ca5 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context1_successive_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context1_successive_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,7 +100,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- PosRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_boundary_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context2_boundary_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_boundary_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_boundary_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_boundary_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context2_boundary_f1.ttx.GPOS
index 08af7f3..b830138 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_boundary_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_boundary_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,10 +100,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
           </ClassDef>
           <!-- PosClassSetCount=2 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_boundary_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context2_boundary_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_boundary_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_boundary_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_boundary_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context2_boundary_f2.ttx.GPOS
index 832e37b..a48dc6a 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_boundary_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_boundary_f2.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,10 +100,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
           </ClassDef>
           <!-- PosClassSetCount=2 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_classes_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context2_classes_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_classes_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_classes_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_classes_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context2_classes_f1.ttx.GPOS
index b06382d..7573e48 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_classes_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_classes_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,11 +100,11 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
             <ClassDef glyph="g21" class="1"/>
             <ClassDef glyph="g22" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_classes_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context2_classes_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_classes_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_classes_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_classes_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context2_classes_f2.ttx.GPOS
index a266ada..4435c02 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_classes_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_classes_f2.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,13 +100,13 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
             <Glyph value="g24"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
             <ClassDef glyph="g21" class="1"/>
             <ClassDef glyph="g22" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_expansion_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context2_expansion_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_expansion_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_expansion_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_expansion_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context2_expansion_f1.ttx.GPOS
index 48833f7..584892f 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_expansion_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_expansion_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,10 +100,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
             <ClassDef glyph="g21" class="2"/>
             <ClassDef glyph="g22" class="3"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f1.ttx.GPOS
index d45c280..99546b5 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -97,13 +97,13 @@
       </Lookup>
       <Lookup index="4">
         <LookupType value="7"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
             <ClassDef glyph="g21" class="2"/>
             <ClassDef glyph="g22" class="3"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f2.ttx.GPOS
index 6f3c016..4a0fcb8 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_lookupflag_f2.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -97,13 +97,13 @@
       </Lookup>
       <Lookup index="4">
         <LookupType value="7"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
             <ClassDef glyph="g21" class="2"/>
             <ClassDef glyph="g22" class="3"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f1.ttx.GPOS
index 1a9b1e2..d2f38c3 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,10 +100,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
             <ClassDef glyph="g21" class="2"/>
             <ClassDef glyph="g22" class="3"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f2.ttx.GPOS
index f3f9d9d..e5d0a63 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_multiple_subrules_f2.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,10 +100,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
             <ClassDef glyph="g21" class="2"/>
             <ClassDef glyph="g22" class="3"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_next_glyph_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context2_next_glyph_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_next_glyph_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_next_glyph_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_next_glyph_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context2_next_glyph_f1.ttx.GPOS
index 655d1d3..c171781 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_next_glyph_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_next_glyph_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,10 +100,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
           </ClassDef>
           <!-- PosClassSetCount=2 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_simple_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context2_simple_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_simple_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_simple_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_simple_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context2_simple_f1.ttx.GPOS
index bc06db5..266f31b 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_simple_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_simple_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,10 +100,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
             <ClassDef glyph="g21" class="2"/>
             <ClassDef glyph="g22" class="3"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_simple_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context2_simple_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_simple_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_simple_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_simple_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context2_simple_f2.ttx.GPOS
index c2964bb..8001658 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_simple_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_simple_f2.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,10 +100,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
           </ClassDef>
           <!-- PosClassSetCount=2 -->
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_successive_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context2_successive_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_successive_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_successive_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context2_successive_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context2_successive_f1.ttx.GPOS
index 797b37b..2de586f 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context2_successive_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context2_successive_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -100,10 +100,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
             <ClassDef glyph="g21" class="2"/>
             <ClassDef glyph="g22" class="3"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context3_boundary_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context3_boundary_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context3_boundary_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context3_boundary_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context3_boundary_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context3_boundary_f1.ttx.GPOS
index f709b3b..fd85d19 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context3_boundary_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context3_boundary_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -102,10 +102,10 @@
         <ContextPos index="0" Format="3">
           <!-- GlyphCount=2 -->
           <!-- PosCount=0 -->
-          <Coverage index="0">
+          <Coverage index="0" Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <Coverage index="1">
+          <Coverage index="1" Format="1">
             <Glyph value="g20"/>
           </Coverage>
         </ContextPos>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context3_boundary_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context3_boundary_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context3_boundary_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context3_boundary_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context3_boundary_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context3_boundary_f2.ttx.GPOS
index a885d1a..bee96ff 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context3_boundary_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context3_boundary_f2.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -102,7 +102,7 @@
         <ContextPos index="0" Format="3">
           <!-- GlyphCount=1 -->
           <!-- PosCount=1 -->
-          <Coverage index="0">
+          <Coverage index="0" Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <PosLookupRecord index="0">
diff --git a/Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f1.ttx.GPOS
index 286a200..e9c854c 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -97,18 +97,18 @@
       </Lookup>
       <Lookup index="4">
         <LookupType value="7"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="3">
           <!-- GlyphCount=3 -->
           <!-- PosCount=3 -->
-          <Coverage index="0">
+          <Coverage index="0" Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <Coverage index="1">
+          <Coverage index="1" Format="1">
             <Glyph value="g21"/>
           </Coverage>
-          <Coverage index="2">
+          <Coverage index="2" Format="1">
             <Glyph value="g22"/>
           </Coverage>
           <PosLookupRecord index="0">
diff --git a/Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f2.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f2.ttx.GPOS
index ea697fc..e2b4a23 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f2.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context3_lookupflag_f2.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -97,18 +97,18 @@
       </Lookup>
       <Lookup index="4">
         <LookupType value="7"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <ContextPos index="0" Format="3">
           <!-- GlyphCount=3 -->
           <!-- PosCount=1 -->
-          <Coverage index="0">
+          <Coverage index="0" Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <Coverage index="1">
+          <Coverage index="1" Format="1">
             <Glyph value="g21"/>
           </Coverage>
-          <Coverage index="2">
+          <Coverage index="2" Format="1">
             <Glyph value="g22"/>
           </Coverage>
           <PosLookupRecord index="0">
diff --git a/Tests/ttLib/tables/data/aots/gpos_context3_next_glyph_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context3_next_glyph_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context3_next_glyph_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context3_next_glyph_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context3_next_glyph_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context3_next_glyph_f1.ttx.GPOS
index c4b9d8a..44ce072 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context3_next_glyph_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context3_next_glyph_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -102,10 +102,10 @@
         <ContextPos index="0" Format="3">
           <!-- GlyphCount=2 -->
           <!-- PosCount=1 -->
-          <Coverage index="0">
+          <Coverage index="0" Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <Coverage index="1">
+          <Coverage index="1" Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <PosLookupRecord index="0">
diff --git a/Tests/ttLib/tables/data/aots/gpos_context3_simple_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context3_simple_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context3_simple_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context3_simple_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context3_simple_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context3_simple_f1.ttx.GPOS
index 7804fb8..c559a7d 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context3_simple_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context3_simple_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -102,13 +102,13 @@
         <ContextPos index="0" Format="3">
           <!-- GlyphCount=3 -->
           <!-- PosCount=3 -->
-          <Coverage index="0">
+          <Coverage index="0" Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <Coverage index="1">
+          <Coverage index="1" Format="1">
             <Glyph value="g21"/>
           </Coverage>
-          <Coverage index="2">
+          <Coverage index="2" Format="1">
             <Glyph value="g22"/>
           </Coverage>
           <PosLookupRecord index="0">
diff --git a/Tests/ttLib/tables/data/aots/gpos_context3_successive_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gpos_context3_successive_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context3_successive_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gpos_context3_successive_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gpos_context3_successive_f1.ttx.GPOS b/Tests/ttLib/tables/data/aots/gpos_context3_successive_f1.ttx.GPOS
index 17b5ed2..8ff7eea 100644
--- a/Tests/ttLib/tables/data/aots/gpos_context3_successive_f1.ttx.GPOS
+++ b/Tests/ttLib/tables/data/aots/gpos_context3_successive_f1.ttx.GPOS
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -55,7 +55,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -72,10 +72,10 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <ValueFormat1 value="1"/>
@@ -102,16 +102,16 @@
         <ContextPos index="0" Format="3">
           <!-- GlyphCount=4 -->
           <!-- PosCount=2 -->
-          <Coverage index="0">
+          <Coverage index="0" Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <Coverage index="1">
+          <Coverage index="1" Format="1">
             <Glyph value="g21"/>
           </Coverage>
-          <Coverage index="2">
+          <Coverage index="2" Format="1">
             <Glyph value="g22"/>
           </Coverage>
-          <Coverage index="3">
+          <Coverage index="3" Format="1">
             <Glyph value="g23"/>
           </Coverage>
           <PosLookupRecord index="0">
diff --git a/Tests/ttLib/tables/data/aots/gsub1_1_lookupflag_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub1_1_lookupflag_f1.ttx.GDEF
index 08e65de..971a3f1 100644
--- a/Tests/ttLib/tables/data/aots/gsub1_1_lookupflag_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub1_1_lookupflag_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g18" class="1"/>
     </GlyphClassDef>
   </GDEF>
diff --git a/Tests/ttLib/tables/data/aots/gsub1_1_lookupflag_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub1_1_lookupflag_f1.ttx.GSUB
index d5e0bf7..ba7b68f 100644
--- a/Tests/ttLib/tables/data/aots/gsub1_1_lookupflag_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub1_1_lookupflag_f1.ttx.GSUB
@@ -31,9 +31,9 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="1"/>
-        <LookupFlag value="2"/><!-- ignoreBaseGlyphs -->
+        <LookupFlag value="2"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g18" out="g23"/>
           <Substitution in="g19" out="g24"/>
         </SingleSubst>
diff --git a/Tests/ttLib/tables/data/aots/gsub1_1_modulo_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub1_1_modulo_f1.ttx.GSUB
index f145dd3..b9923da 100644
--- a/Tests/ttLib/tables/data/aots/gsub1_1_modulo_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub1_1_modulo_f1.ttx.GSUB
@@ -34,11 +34,11 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=2 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g21" out="glyph32787"/>
           <Substitution in="g22" out="glyph32788"/>
         </SingleSubst>
-        <SingleSubst index="1">
+        <SingleSubst index="1" Format="1">
           <Substitution in="g19" out="glyph32789"/>
           <Substitution in="g20" out="glyph32790"/>
         </SingleSubst>
@@ -47,16 +47,16 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=4 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="glyph32787" out="g23"/>
         </SingleSubst>
-        <SingleSubst index="1">
+        <SingleSubst index="1" Format="1">
           <Substitution in="glyph32788" out="g18"/>
         </SingleSubst>
-        <SingleSubst index="2">
+        <SingleSubst index="2" Format="1">
           <Substitution in="glyph32789" out="g17"/>
         </SingleSubst>
-        <SingleSubst index="3">
+        <SingleSubst index="3" Format="1">
           <Substitution in="glyph32790" out="g24"/>
         </SingleSubst>
       </Lookup>
diff --git a/Tests/ttLib/tables/data/aots/gsub1_1_simple_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub1_1_simple_f1.ttx.GSUB
index 7de19b0..e76ba74 100644
--- a/Tests/ttLib/tables/data/aots/gsub1_1_simple_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub1_1_simple_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g18" out="g23"/>
           <Substitution in="g19" out="g24"/>
         </SingleSubst>
diff --git a/Tests/ttLib/tables/data/aots/gsub1_2_lookupflag_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub1_2_lookupflag_f1.ttx.GDEF
index 08e65de..971a3f1 100644
--- a/Tests/ttLib/tables/data/aots/gsub1_2_lookupflag_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub1_2_lookupflag_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g18" class="1"/>
     </GlyphClassDef>
   </GDEF>
diff --git a/Tests/ttLib/tables/data/aots/gsub1_2_lookupflag_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub1_2_lookupflag_f1.ttx.GSUB
index a518afb..51bfbb1 100644
--- a/Tests/ttLib/tables/data/aots/gsub1_2_lookupflag_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub1_2_lookupflag_f1.ttx.GSUB
@@ -31,9 +31,9 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="1"/>
-        <LookupFlag value="2"/><!-- ignoreBaseGlyphs -->
+        <LookupFlag value="2"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="2">
           <Substitution in="g18" out="g22"/>
           <Substitution in="g20" out="g25"/>
         </SingleSubst>
diff --git a/Tests/ttLib/tables/data/aots/gsub1_2_simple_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub1_2_simple_f1.ttx.GSUB
index 392ff3c..55649d2 100644
--- a/Tests/ttLib/tables/data/aots/gsub1_2_simple_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub1_2_simple_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="2">
           <Substitution in="g18" out="g22"/>
           <Substitution in="g20" out="g25"/>
         </SingleSubst>
diff --git a/Tests/ttLib/tables/data/aots/gsub2_1_lookupflag_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub2_1_lookupflag_f1.ttx.GDEF
index 08e65de..971a3f1 100644
--- a/Tests/ttLib/tables/data/aots/gsub2_1_lookupflag_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub2_1_lookupflag_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g18" class="1"/>
     </GlyphClassDef>
   </GDEF>
diff --git a/Tests/ttLib/tables/data/aots/gsub2_1_lookupflag_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub2_1_lookupflag_f1.ttx.GSUB
index d3c37dc..2c59793 100644
--- a/Tests/ttLib/tables/data/aots/gsub2_1_lookupflag_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub2_1_lookupflag_f1.ttx.GSUB
@@ -31,9 +31,9 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="2"/><!-- ignoreBaseGlyphs -->
+        <LookupFlag value="2"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g18" out="g20,g21"/>
           <Substitution in="g19" out="g22,g23"/>
         </MultipleSubst>
diff --git a/Tests/ttLib/tables/data/aots/gsub2_1_multiple_sequences_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub2_1_multiple_sequences_f1.ttx.GSUB
index 1c4cd4c..5ec800e 100644
--- a/Tests/ttLib/tables/data/aots/gsub2_1_multiple_sequences_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub2_1_multiple_sequences_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g18" out="g20,g21"/>
           <Substitution in="g19" out="g22,g23"/>
         </MultipleSubst>
diff --git a/Tests/ttLib/tables/data/aots/gsub2_1_simple_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub2_1_simple_f1.ttx.GSUB
index b2453ec..cae4f66 100644
--- a/Tests/ttLib/tables/data/aots/gsub2_1_simple_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub2_1_simple_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g18" out="g20,g21,g22"/>
         </MultipleSubst>
       </Lookup>
diff --git a/Tests/ttLib/tables/data/aots/gsub3_1_lookupflag_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub3_1_lookupflag_f1.ttx.GDEF
index 08e65de..971a3f1 100644
--- a/Tests/ttLib/tables/data/aots/gsub3_1_lookupflag_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub3_1_lookupflag_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g18" class="1"/>
     </GlyphClassDef>
   </GDEF>
diff --git a/Tests/ttLib/tables/data/aots/gsub3_1_lookupflag_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub3_1_lookupflag_f1.ttx.GSUB
index 531c608..63c53b4 100644
--- a/Tests/ttLib/tables/data/aots/gsub3_1_lookupflag_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub3_1_lookupflag_f1.ttx.GSUB
@@ -31,9 +31,9 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="3"/>
-        <LookupFlag value="2"/><!-- ignoreBaseGlyphs -->
+        <LookupFlag value="2"/>
         <!-- SubTableCount=1 -->
-        <AlternateSubst index="0">
+        <AlternateSubst index="0" Format="1">
           <AlternateSet glyph="g18">
             <Alternate glyph="g20"/>
             <Alternate glyph="g21"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub3_1_multiple_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub3_1_multiple_f1.ttx.GSUB
index 54a5219..1eae117 100644
--- a/Tests/ttLib/tables/data/aots/gsub3_1_multiple_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub3_1_multiple_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="3"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <AlternateSubst index="0">
+        <AlternateSubst index="0" Format="1">
           <AlternateSet glyph="g18">
             <Alternate glyph="g20"/>
             <Alternate glyph="g21"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub3_1_simple_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub3_1_simple_f1.ttx.GSUB
index 9a516b2..7372cd0 100644
--- a/Tests/ttLib/tables/data/aots/gsub3_1_simple_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub3_1_simple_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="3"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <AlternateSubst index="0">
+        <AlternateSubst index="0" Format="1">
           <AlternateSet glyph="g18">
             <Alternate glyph="g20"/>
             <Alternate glyph="g21"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub4_1_lookupflag_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub4_1_lookupflag_f1.ttx.GDEF
index 269092d..ffcc7a1 100644
--- a/Tests/ttLib/tables/data/aots/gsub4_1_lookupflag_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub4_1_lookupflag_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g24" class="1"/>
     </GlyphClassDef>
   </GDEF>
diff --git a/Tests/ttLib/tables/data/aots/gsub4_1_lookupflag_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub4_1_lookupflag_f1.ttx.GSUB
index 7dc3472..0982ef6 100644
--- a/Tests/ttLib/tables/data/aots/gsub4_1_lookupflag_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub4_1_lookupflag_f1.ttx.GSUB
@@ -31,9 +31,9 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="4"/>
-        <LookupFlag value="2"/><!-- ignoreBaseGlyphs -->
+        <LookupFlag value="2"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g18">
             <Ligature components="g19,g20" glyph="g23"/>
           </LigatureSet>
diff --git a/Tests/ttLib/tables/data/aots/gsub4_1_multiple_ligatures_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub4_1_multiple_ligatures_f1.ttx.GSUB
index e9eb9ea..9466f91 100644
--- a/Tests/ttLib/tables/data/aots/gsub4_1_multiple_ligatures_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub4_1_multiple_ligatures_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g18">
             <Ligature components="g19,g20" glyph="g23"/>
             <Ligature components="g19" glyph="g24"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub4_1_multiple_ligatures_f2.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub4_1_multiple_ligatures_f2.ttx.GSUB
index 6756dfd..bc25e84 100644
--- a/Tests/ttLib/tables/data/aots/gsub4_1_multiple_ligatures_f2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub4_1_multiple_ligatures_f2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g18">
             <Ligature components="g19" glyph="g24"/>
             <Ligature components="g19,g20" glyph="g23"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub4_1_multiple_ligsets_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub4_1_multiple_ligsets_f1.ttx.GSUB
index ab04368..0ea6495 100644
--- a/Tests/ttLib/tables/data/aots/gsub4_1_multiple_ligsets_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub4_1_multiple_ligsets_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g18">
             <Ligature components="g19" glyph="g23"/>
           </LigatureSet>
diff --git a/Tests/ttLib/tables/data/aots/gsub4_1_simple_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub4_1_simple_f1.ttx.GSUB
index 7f3012a..ecc8fa6 100644
--- a/Tests/ttLib/tables/data/aots/gsub4_1_simple_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub4_1_simple_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g18">
             <Ligature components="g19,g20" glyph="g23"/>
           </LigatureSet>
diff --git a/Tests/ttLib/tables/data/aots/gsub7_font1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub7_font1.ttx.GSUB
index cf43ec6..3f65d93 100644
--- a/Tests/ttLib/tables/data/aots/gsub7_font1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub7_font1.ttx.GSUB
@@ -35,7 +35,7 @@
         <!-- SubTableCount=1 -->
         <ExtensionSubst index="0" Format="1">
           <ExtensionLookupType value="1"/>
-          <SingleSubst>
+          <SingleSubst Format="1">
             <Substitution in="g18" out="g23"/>
             <Substitution in="g19" out="g24"/>
           </SingleSubst>
diff --git a/Tests/ttLib/tables/data/aots/gsub7_font2.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub7_font2.ttx.GSUB
index 1f488f3..98338ed 100644
--- a/Tests/ttLib/tables/data/aots/gsub7_font2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub7_font2.ttx.GSUB
@@ -35,13 +35,13 @@
         <!-- SubTableCount=2 -->
         <ExtensionSubst index="0" Format="1">
           <ExtensionLookupType value="1"/>
-          <SingleSubst>
+          <SingleSubst Format="1">
             <Substitution in="g18" out="g23"/>
           </SingleSubst>
         </ExtensionSubst>
         <ExtensionSubst index="1" Format="1">
           <ExtensionLookupType value="1"/>
-          <SingleSubst>
+          <SingleSubst Format="1">
             <Substitution in="g19" out="g29"/>
           </SingleSubst>
         </ExtensionSubst>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f1.ttx.GSUB
index 897946e..49ed83d 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <!-- ChainSubRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f2.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f2.ttx.GSUB
index 896736c..7790bf9 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <!-- ChainSubRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f3.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f3.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f3.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f3.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f3.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f3.ttx.GSUB
index 43a5914..c58e3d5 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f3.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f3.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <!-- ChainSubRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f4.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f4.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f4.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f4.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f4.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f4.ttx.GSUB
index d649b63..43a1181 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f4.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_boundary_f4.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g22"/>
           </Coverage>
           <!-- ChainSubRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_lookupflag_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining1_lookupflag_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_lookupflag_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_lookupflag_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_lookupflag_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining1_lookupflag_f1.ttx.GSUB
index dd83bd7..e3bdf7f 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_lookupflag_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_lookupflag_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,16 +70,16 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
       <Lookup index="4">
         <LookupType value="6"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g22"/>
           </Coverage>
           <!-- ChainSubRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f1.ttx.GSUB
index b446f62..a8ceb2b 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <!-- ChainSubRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f2.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f2.ttx.GSUB
index 9b6b835..f73b4ec 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_multiple_subrules_f2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <!-- ChainSubRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_next_glyph_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining1_next_glyph_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_next_glyph_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_next_glyph_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_next_glyph_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining1_next_glyph_f1.ttx.GSUB
index 8b554ab..3858160 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_next_glyph_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_next_glyph_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
             <Glyph value="g23"/>
           </Coverage>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f1.ttx.GSUB
index f7dbe58..d7dbd6b 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g21"/>
           </Coverage>
           <!-- ChainSubRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f2.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f2.ttx.GSUB
index a8894e5..e97a6b1 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_simple_f2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g22"/>
           </Coverage>
           <!-- ChainSubRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_successive_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining1_successive_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_successive_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_successive_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining1_successive_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining1_successive_f1.ttx.GSUB
index 52cf963..146dd2a 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining1_successive_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining1_successive_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- ChainSubRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f1.ttx.GSUB
index 9109e59..ecd0a6b 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -88,7 +88,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -97,7 +97,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -106,7 +106,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f2.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f2.ttx.GSUB
index ead59dc..076cb30 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -88,7 +88,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -97,7 +97,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -106,7 +106,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f3.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f3.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f3.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f3.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f3.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f3.ttx.GSUB
index 8163db1..c6fc1dc 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f3.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f3.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -88,7 +88,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -97,7 +97,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -106,7 +106,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f4.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f4.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f4.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f4.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f4.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f4.ttx.GSUB
index 48f9483..4221c6c 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f4.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_boundary_f4.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -88,7 +88,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -97,7 +97,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -106,7 +106,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_lookupflag_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining2_lookupflag_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_lookupflag_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_lookupflag_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_lookupflag_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining2_lookupflag_f1.ttx.GSUB
index a7f4ce6..eaccba0 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_lookupflag_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_lookupflag_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,16 +70,16 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
       <Lookup index="4">
         <LookupType value="6"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -88,7 +88,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -97,7 +97,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -106,7 +106,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f1.ttx.GSUB
index 34cea46..c0447c2 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -88,7 +88,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -97,7 +97,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -106,7 +106,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f2.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f2.ttx.GSUB
index 21cbe2a..6067dfd 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_multiple_subrules_f2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -88,7 +88,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -97,7 +97,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -106,7 +106,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_next_glyph_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining2_next_glyph_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_next_glyph_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_next_glyph_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_next_glyph_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining2_next_glyph_f1.ttx.GSUB
index d14ac1b..f3dcb64 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_next_glyph_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_next_glyph_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -88,7 +88,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -97,7 +97,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -106,7 +106,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f1.ttx.GSUB
index da6a915..7997e3a 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -88,7 +88,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -97,7 +97,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -106,7 +106,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f2.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f2.ttx.GSUB
index 94f6217..bd3645a 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_simple_f2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -88,7 +88,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -97,7 +97,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -106,7 +106,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_successive_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining2_successive_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_successive_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_successive_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining2_successive_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining2_successive_f1.ttx.GSUB
index 7dbc5e0..fd6ead4 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining2_successive_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining2_successive_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
@@ -88,7 +88,7 @@
             <Glyph value="g25"/>
             <Glyph value="g26"/>
           </Coverage>
-          <BacktrackClassDef>
+          <BacktrackClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -97,7 +97,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </BacktrackClassDef>
-          <InputClassDef>
+          <InputClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
@@ -106,7 +106,7 @@
             <ClassDef glyph="g25" class="25"/>
             <ClassDef glyph="g26" class="26"/>
           </InputClassDef>
-          <LookAheadClassDef>
+          <LookAheadClassDef Format="2">
             <ClassDef glyph="g20" class="20"/>
             <ClassDef glyph="g21" class="21"/>
             <ClassDef glyph="g22" class="22"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f1.ttx.GSUB
index 82eb133..579d6ce 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -80,18 +80,18 @@
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="3">
           <!-- BacktrackGlyphCount=1 -->
-          <BacktrackCoverage index="0">
+          <BacktrackCoverage index="0" Format="1">
             <Glyph value="g20"/>
           </BacktrackCoverage>
           <!-- InputGlyphCount=2 -->
-          <InputCoverage index="0">
+          <InputCoverage index="0" Format="1">
             <Glyph value="g21"/>
           </InputCoverage>
-          <InputCoverage index="1">
+          <InputCoverage index="1" Format="1">
             <Glyph value="g22"/>
           </InputCoverage>
           <!-- LookAheadGlyphCount=1 -->
-          <LookAheadCoverage index="0">
+          <LookAheadCoverage index="0" Format="1">
             <Glyph value="g23"/>
           </LookAheadCoverage>
           <!-- SubstCount=0 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f2.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f2.ttx.GSUB
index b5c1636..5098ceb 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -80,18 +80,18 @@
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="3">
           <!-- BacktrackGlyphCount=1 -->
-          <BacktrackCoverage index="0">
+          <BacktrackCoverage index="0" Format="1">
             <Glyph value="g20"/>
           </BacktrackCoverage>
           <!-- InputGlyphCount=1 -->
-          <InputCoverage index="0">
+          <InputCoverage index="0" Format="1">
             <Glyph value="g21"/>
           </InputCoverage>
           <!-- LookAheadGlyphCount=2 -->
-          <LookAheadCoverage index="0">
+          <LookAheadCoverage index="0" Format="1">
             <Glyph value="g22"/>
           </LookAheadCoverage>
-          <LookAheadCoverage index="1">
+          <LookAheadCoverage index="1" Format="1">
             <Glyph value="g23"/>
           </LookAheadCoverage>
           <!-- SubstCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f3.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f3.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f3.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f3.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f3.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f3.ttx.GSUB
index 76d5a46..3d6b966 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f3.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f3.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -81,14 +81,14 @@
         <ChainContextSubst index="0" Format="3">
           <!-- BacktrackGlyphCount=0 -->
           <!-- InputGlyphCount=1 -->
-          <InputCoverage index="0">
+          <InputCoverage index="0" Format="1">
             <Glyph value="g21"/>
           </InputCoverage>
           <!-- LookAheadGlyphCount=2 -->
-          <LookAheadCoverage index="0">
+          <LookAheadCoverage index="0" Format="1">
             <Glyph value="g22"/>
           </LookAheadCoverage>
-          <LookAheadCoverage index="1">
+          <LookAheadCoverage index="1" Format="1">
             <Glyph value="g23"/>
           </LookAheadCoverage>
           <!-- SubstCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f4.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f4.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f4.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f4.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f4.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f4.ttx.GSUB
index 9346d47..9cf6009 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f4.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining3_boundary_f4.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -80,14 +80,14 @@
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="3">
           <!-- BacktrackGlyphCount=2 -->
-          <BacktrackCoverage index="0">
+          <BacktrackCoverage index="0" Format="1">
             <Glyph value="g21"/>
           </BacktrackCoverage>
-          <BacktrackCoverage index="1">
+          <BacktrackCoverage index="1" Format="1">
             <Glyph value="g20"/>
           </BacktrackCoverage>
           <!-- InputGlyphCount=1 -->
-          <InputCoverage index="0">
+          <InputCoverage index="0" Format="1">
             <Glyph value="g22"/>
           </InputCoverage>
           <!-- LookAheadGlyphCount=0 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining3_lookupflag_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining3_lookupflag_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining3_lookupflag_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining3_lookupflag_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining3_lookupflag_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining3_lookupflag_f1.ttx.GSUB
index c329936..9cc951e 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining3_lookupflag_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining3_lookupflag_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,37 +70,37 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
       <Lookup index="4">
         <LookupType value="6"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="3">
           <!-- BacktrackGlyphCount=2 -->
-          <BacktrackCoverage index="0">
+          <BacktrackCoverage index="0" Format="1">
             <Glyph value="g21"/>
           </BacktrackCoverage>
-          <BacktrackCoverage index="1">
+          <BacktrackCoverage index="1" Format="1">
             <Glyph value="g20"/>
           </BacktrackCoverage>
           <!-- InputGlyphCount=3 -->
-          <InputCoverage index="0">
+          <InputCoverage index="0" Format="1">
             <Glyph value="g22"/>
           </InputCoverage>
-          <InputCoverage index="1">
+          <InputCoverage index="1" Format="1">
             <Glyph value="g23"/>
           </InputCoverage>
-          <InputCoverage index="2">
+          <InputCoverage index="2" Format="1">
             <Glyph value="g24"/>
           </InputCoverage>
           <!-- LookAheadGlyphCount=2 -->
-          <LookAheadCoverage index="0">
+          <LookAheadCoverage index="0" Format="1">
             <Glyph value="g25"/>
           </LookAheadCoverage>
-          <LookAheadCoverage index="1">
+          <LookAheadCoverage index="1" Format="1">
             <Glyph value="g26"/>
           </LookAheadCoverage>
           <!-- SubstCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining3_next_glyph_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining3_next_glyph_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining3_next_glyph_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining3_next_glyph_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining3_next_glyph_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining3_next_glyph_f1.ttx.GSUB
index 46d1f85..00ff357 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining3_next_glyph_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining3_next_glyph_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -80,18 +80,18 @@
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="3">
           <!-- BacktrackGlyphCount=1 -->
-          <BacktrackCoverage index="0">
+          <BacktrackCoverage index="0" Format="1">
             <Glyph value="g22"/>
           </BacktrackCoverage>
           <!-- InputGlyphCount=2 -->
-          <InputCoverage index="0">
+          <InputCoverage index="0" Format="1">
             <Glyph value="g21"/>
           </InputCoverage>
-          <InputCoverage index="1">
+          <InputCoverage index="1" Format="1">
             <Glyph value="g22"/>
           </InputCoverage>
           <!-- LookAheadGlyphCount=1 -->
-          <LookAheadCoverage index="0">
+          <LookAheadCoverage index="0" Format="1">
             <Glyph value="g21"/>
           </LookAheadCoverage>
           <!-- SubstCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f1.ttx.GSUB
index 722dcad..6cbf5f9 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -80,18 +80,18 @@
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="3">
           <!-- BacktrackGlyphCount=1 -->
-          <BacktrackCoverage index="0">
+          <BacktrackCoverage index="0" Format="1">
             <Glyph value="g20"/>
           </BacktrackCoverage>
           <!-- InputGlyphCount=2 -->
-          <InputCoverage index="0">
+          <InputCoverage index="0" Format="1">
             <Glyph value="g21"/>
           </InputCoverage>
-          <InputCoverage index="1">
+          <InputCoverage index="1" Format="1">
             <Glyph value="g22"/>
           </InputCoverage>
           <!-- LookAheadGlyphCount=1 -->
-          <LookAheadCoverage index="0">
+          <LookAheadCoverage index="0" Format="1">
             <Glyph value="g23"/>
           </LookAheadCoverage>
           <!-- SubstCount=2 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f2.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f2.ttx.GSUB
index 5842c55..65fea5d 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining3_simple_f2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -80,27 +80,27 @@
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="3">
           <!-- BacktrackGlyphCount=2 -->
-          <BacktrackCoverage index="0">
+          <BacktrackCoverage index="0" Format="1">
             <Glyph value="g21"/>
           </BacktrackCoverage>
-          <BacktrackCoverage index="1">
+          <BacktrackCoverage index="1" Format="1">
             <Glyph value="g20"/>
           </BacktrackCoverage>
           <!-- InputGlyphCount=3 -->
-          <InputCoverage index="0">
+          <InputCoverage index="0" Format="1">
             <Glyph value="g22"/>
           </InputCoverage>
-          <InputCoverage index="1">
+          <InputCoverage index="1" Format="1">
             <Glyph value="g23"/>
           </InputCoverage>
-          <InputCoverage index="2">
+          <InputCoverage index="2" Format="1">
             <Glyph value="g24"/>
           </InputCoverage>
           <!-- LookAheadGlyphCount=2 -->
-          <LookAheadCoverage index="0">
+          <LookAheadCoverage index="0" Format="1">
             <Glyph value="g25"/>
           </LookAheadCoverage>
-          <LookAheadCoverage index="1">
+          <LookAheadCoverage index="1" Format="1">
             <Glyph value="g26"/>
           </LookAheadCoverage>
           <!-- SubstCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining3_successive_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_chaining3_successive_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining3_successive_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining3_successive_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_chaining3_successive_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_chaining3_successive_f1.ttx.GSUB
index 610ea56..6e8918f 100644
--- a/Tests/ttLib/tables/data/aots/gsub_chaining3_successive_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_chaining3_successive_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -80,24 +80,24 @@
         <!-- SubTableCount=1 -->
         <ChainContextSubst index="0" Format="3">
           <!-- BacktrackGlyphCount=1 -->
-          <BacktrackCoverage index="0">
+          <BacktrackCoverage index="0" Format="1">
             <Glyph value="g25"/>
           </BacktrackCoverage>
           <!-- InputGlyphCount=4 -->
-          <InputCoverage index="0">
+          <InputCoverage index="0" Format="1">
             <Glyph value="g20"/>
           </InputCoverage>
-          <InputCoverage index="1">
+          <InputCoverage index="1" Format="1">
             <Glyph value="g21"/>
           </InputCoverage>
-          <InputCoverage index="2">
+          <InputCoverage index="2" Format="1">
             <Glyph value="g22"/>
           </InputCoverage>
-          <InputCoverage index="3">
+          <InputCoverage index="3" Format="1">
             <Glyph value="g23"/>
           </InputCoverage>
           <!-- LookAheadGlyphCount=1 -->
-          <LookAheadCoverage index="0">
+          <LookAheadCoverage index="0" Format="1">
             <Glyph value="g24"/>
           </LookAheadCoverage>
           <!-- SubstCount=2 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_boundary_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context1_boundary_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_boundary_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_boundary_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_boundary_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context1_boundary_f1.ttx.GSUB
index 6de6506..5ce2dbc 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_boundary_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_boundary_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- SubRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_boundary_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context1_boundary_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_boundary_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_boundary_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_boundary_f2.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context1_boundary_f2.ttx.GSUB
index 7d5772c..f4df5df 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_boundary_f2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_boundary_f2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- SubRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_expansion_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context1_expansion_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_expansion_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_expansion_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_expansion_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context1_expansion_f1.ttx.GSUB
index e8dca8a..e03d5c3 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_expansion_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_expansion_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- SubRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f1.ttx.GSUB
index 579294f..7f7dbae 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,16 +70,16 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
       <Lookup index="4">
         <LookupType value="5"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- SubRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f2.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f2.ttx.GSUB
index e583f6a..921576c 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_lookupflag_f2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,16 +70,16 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
       <Lookup index="4">
         <LookupType value="5"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- SubRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f1.ttx.GSUB
index 2202320..3bcb882 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- SubRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f2.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f2.ttx.GSUB
index df568c3..04e9696 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_multiple_subrules_f2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- SubRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_next_glyph_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context1_next_glyph_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_next_glyph_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_next_glyph_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_next_glyph_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context1_next_glyph_f1.ttx.GSUB
index 518e754..1276fb9 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_next_glyph_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_next_glyph_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- SubRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_simple_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context1_simple_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_simple_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_simple_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_simple_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context1_simple_f1.ttx.GSUB
index 2906b06..4e135b5 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_simple_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_simple_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- SubRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_simple_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context1_simple_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_simple_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_simple_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_simple_f2.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context1_simple_f2.ttx.GSUB
index 554168b..787c216 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_simple_f2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_simple_f2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- SubRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_successive_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context1_successive_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_successive_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_successive_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context1_successive_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context1_successive_f1.ttx.GSUB
index fc66abd..e0b1c54 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context1_successive_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context1_successive_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,7 +79,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <!-- SubRuleSetCount=1 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_boundary_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context2_boundary_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_boundary_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_boundary_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_boundary_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context2_boundary_f1.ttx.GSUB
index e1e12f8..705389b 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_boundary_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_boundary_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,10 +79,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
           </ClassDef>
           <!-- SubClassSetCount=2 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_boundary_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context2_boundary_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_boundary_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_boundary_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_boundary_f2.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context2_boundary_f2.ttx.GSUB
index d2598d9..3a35d50 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_boundary_f2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_boundary_f2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,10 +79,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
           </ClassDef>
           <!-- SubClassSetCount=2 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_classes_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context2_classes_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_classes_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_classes_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_classes_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context2_classes_f1.ttx.GSUB
index 394df78..6716203 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_classes_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_classes_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,11 +79,11 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
             <ClassDef glyph="g21" class="1"/>
             <ClassDef glyph="g22" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_classes_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context2_classes_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_classes_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_classes_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_classes_f2.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context2_classes_f2.ttx.GSUB
index 4de5bc6..deeea52 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_classes_f2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_classes_f2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,13 +79,13 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
             <Glyph value="g21"/>
             <Glyph value="g22"/>
             <Glyph value="g24"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
             <ClassDef glyph="g21" class="1"/>
             <ClassDef glyph="g22" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_expansion_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context2_expansion_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_expansion_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_expansion_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_expansion_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context2_expansion_f1.ttx.GSUB
index 5ab7d08..3952840 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_expansion_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_expansion_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,10 +79,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
             <ClassDef glyph="g21" class="2"/>
             <ClassDef glyph="g22" class="3"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f1.ttx.GSUB
index 4a8d749..80a6237 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,19 +70,19 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
       <Lookup index="4">
         <LookupType value="5"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
             <ClassDef glyph="g21" class="2"/>
             <ClassDef glyph="g22" class="3"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f2.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f2.ttx.GSUB
index a672edf..715a1cd 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_lookupflag_f2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,19 +70,19 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
       <Lookup index="4">
         <LookupType value="5"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
             <ClassDef glyph="g21" class="2"/>
             <ClassDef glyph="g22" class="3"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f1.ttx.GSUB
index 07b5f5e..827db06 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,10 +79,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
             <ClassDef glyph="g21" class="2"/>
             <ClassDef glyph="g22" class="3"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f2.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f2.ttx.GSUB
index 2252761..83d6af5 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_multiple_subrules_f2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,10 +79,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
             <ClassDef glyph="g21" class="2"/>
             <ClassDef glyph="g22" class="3"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_next_glyph_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context2_next_glyph_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_next_glyph_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_next_glyph_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_next_glyph_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context2_next_glyph_f1.ttx.GSUB
index b78220b..09e9dc9 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_next_glyph_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_next_glyph_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,10 +79,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
           </ClassDef>
           <!-- SubClassSetCount=2 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_simple_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context2_simple_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_simple_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_simple_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_simple_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context2_simple_f1.ttx.GSUB
index 35fff94..6bc8a46 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_simple_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_simple_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,10 +79,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
             <ClassDef glyph="g21" class="2"/>
             <ClassDef glyph="g22" class="3"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_simple_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context2_simple_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_simple_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_simple_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_simple_f2.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context2_simple_f2.ttx.GSUB
index 28ab11e..f65bf4d 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_simple_f2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_simple_f2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,10 +79,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
           </ClassDef>
           <!-- SubClassSetCount=2 -->
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_successive_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context2_successive_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_successive_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_successive_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context2_successive_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context2_successive_f1.ttx.GSUB
index a364207..3c7e0f9 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context2_successive_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context2_successive_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -79,10 +79,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <ClassDef>
+          <ClassDef Format="2">
             <ClassDef glyph="g20" class="1"/>
             <ClassDef glyph="g21" class="2"/>
             <ClassDef glyph="g22" class="3"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context3_boundary_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context3_boundary_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context3_boundary_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context3_boundary_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context3_boundary_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context3_boundary_f1.ttx.GSUB
index 9a73fac..843e88d 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context3_boundary_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context3_boundary_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -81,10 +81,10 @@
         <ContextSubst index="0" Format="3">
           <!-- GlyphCount=2 -->
           <!-- SubstCount=0 -->
-          <Coverage index="0">
+          <Coverage index="0" Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <Coverage index="1">
+          <Coverage index="1" Format="1">
             <Glyph value="g20"/>
           </Coverage>
         </ContextSubst>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context3_boundary_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context3_boundary_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context3_boundary_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context3_boundary_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context3_boundary_f2.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context3_boundary_f2.ttx.GSUB
index d45e67b..cba8c31 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context3_boundary_f2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context3_boundary_f2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -81,7 +81,7 @@
         <ContextSubst index="0" Format="3">
           <!-- GlyphCount=1 -->
           <!-- SubstCount=1 -->
-          <Coverage index="0">
+          <Coverage index="0" Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <SubstLookupRecord index="0">
diff --git a/Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f1.ttx.GSUB
index 90b53f4..d485a04 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,24 +70,24 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
       <Lookup index="4">
         <LookupType value="5"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="3">
           <!-- GlyphCount=3 -->
           <!-- SubstCount=3 -->
-          <Coverage index="0">
+          <Coverage index="0" Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <Coverage index="1">
+          <Coverage index="1" Format="1">
             <Glyph value="g21"/>
           </Coverage>
-          <Coverage index="2">
+          <Coverage index="2" Format="1">
             <Glyph value="g22"/>
           </Coverage>
           <SubstLookupRecord index="0">
diff --git a/Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f2.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f2.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f2.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f2.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f2.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f2.ttx.GSUB
index a82c3c0..016350f 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f2.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context3_lookupflag_f2.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,24 +70,24 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
       <Lookup index="4">
         <LookupType value="5"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <ContextSubst index="0" Format="3">
           <!-- GlyphCount=3 -->
           <!-- SubstCount=1 -->
-          <Coverage index="0">
+          <Coverage index="0" Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <Coverage index="1">
+          <Coverage index="1" Format="1">
             <Glyph value="g21"/>
           </Coverage>
-          <Coverage index="2">
+          <Coverage index="2" Format="1">
             <Glyph value="g22"/>
           </Coverage>
           <SubstLookupRecord index="0">
diff --git a/Tests/ttLib/tables/data/aots/gsub_context3_next_glyph_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context3_next_glyph_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context3_next_glyph_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context3_next_glyph_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context3_next_glyph_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context3_next_glyph_f1.ttx.GSUB
index a4f5add..10fcba5 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context3_next_glyph_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context3_next_glyph_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -81,10 +81,10 @@
         <ContextSubst index="0" Format="3">
           <!-- GlyphCount=2 -->
           <!-- SubstCount=1 -->
-          <Coverage index="0">
+          <Coverage index="0" Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <Coverage index="1">
+          <Coverage index="1" Format="1">
             <Glyph value="g20"/>
           </Coverage>
           <SubstLookupRecord index="0">
diff --git a/Tests/ttLib/tables/data/aots/gsub_context3_simple_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context3_simple_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context3_simple_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context3_simple_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context3_simple_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context3_simple_f1.ttx.GSUB
index 15d6c08..93f4bdd 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context3_simple_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context3_simple_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -81,13 +81,13 @@
         <ContextSubst index="0" Format="3">
           <!-- GlyphCount=3 -->
           <!-- SubstCount=3 -->
-          <Coverage index="0">
+          <Coverage index="0" Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <Coverage index="1">
+          <Coverage index="1" Format="1">
             <Glyph value="g21"/>
           </Coverage>
-          <Coverage index="2">
+          <Coverage index="2" Format="1">
             <Glyph value="g22"/>
           </Coverage>
           <SubstLookupRecord index="0">
diff --git a/Tests/ttLib/tables/data/aots/gsub_context3_successive_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/gsub_context3_successive_f1.ttx.GDEF
index b5c2ac3..dba5550 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context3_successive_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/gsub_context3_successive_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g80" class="1"/>
       <ClassDef glyph="g81" class="1"/>
       <ClassDef glyph="g82" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/gsub_context3_successive_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/gsub_context3_successive_f1.ttx.GSUB
index 6558c69..73e3567 100644
--- a/Tests/ttLib/tables/data/aots/gsub_context3_successive_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/gsub_context3_successive_f1.ttx.GSUB
@@ -33,7 +33,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="g20" out="g60"/>
           <Substitution in="g21" out="g61"/>
           <Substitution in="g22" out="g62"/>
@@ -50,7 +50,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -58,9 +58,9 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g21">
             <Ligature components="g22" glyph="g61"/>
           </LigatureSet>
@@ -70,7 +70,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="g21" out="g61,g62,g63"/>
         </MultipleSubst>
       </Lookup>
@@ -81,16 +81,16 @@
         <ContextSubst index="0" Format="3">
           <!-- GlyphCount=4 -->
           <!-- SubstCount=2 -->
-          <Coverage index="0">
+          <Coverage index="0" Format="1">
             <Glyph value="g20"/>
           </Coverage>
-          <Coverage index="1">
+          <Coverage index="1" Format="1">
             <Glyph value="g21"/>
           </Coverage>
-          <Coverage index="2">
+          <Coverage index="2" Format="1">
             <Glyph value="g22"/>
           </Coverage>
-          <Coverage index="3">
+          <Coverage index="3" Format="1">
             <Glyph value="g23"/>
           </Coverage>
           <SubstLookupRecord index="0">
diff --git a/Tests/ttLib/tables/data/aots/lookupflag_ignore_attach_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/lookupflag_ignore_attach_f1.ttx.GDEF
index 736e2d8..802351a 100644
--- a/Tests/ttLib/tables/data/aots/lookupflag_ignore_attach_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/lookupflag_ignore_attach_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g10" class="1"/>
       <ClassDef glyph="g11" class="1"/>
       <ClassDef glyph="g12" class="1"/>
@@ -21,7 +21,7 @@
       <ClassDef glyph="g28" class="3"/>
       <ClassDef glyph="g29" class="3"/>
     </GlyphClassDef>
-    <MarkAttachClassDef>
+    <MarkAttachClassDef Format="2">
       <ClassDef glyph="g20" class="1"/>
       <ClassDef glyph="g21" class="1"/>
       <ClassDef glyph="g22" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/lookupflag_ignore_attach_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/lookupflag_ignore_attach_f1.ttx.GSUB
index 42876ea..f8064cb 100644
--- a/Tests/ttLib/tables/data/aots/lookupflag_ignore_attach_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/lookupflag_ignore_attach_f1.ttx.GSUB
@@ -31,9 +31,9 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="4"/>
-        <LookupFlag value="512"/><!-- markAttachmentType[2] -->
+        <LookupFlag value="512"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g11">
             <Ligature components="g13,g26" glyph="g15"/>
           </LigatureSet>
diff --git a/Tests/ttLib/tables/data/aots/lookupflag_ignore_base_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/lookupflag_ignore_base_f1.ttx.GDEF
index c6abc87..2b0a686 100644
--- a/Tests/ttLib/tables/data/aots/lookupflag_ignore_base_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/lookupflag_ignore_base_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g24" class="1"/>
       <ClassDef glyph="g25" class="1"/>
     </GlyphClassDef>
diff --git a/Tests/ttLib/tables/data/aots/lookupflag_ignore_base_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/lookupflag_ignore_base_f1.ttx.GSUB
index 7dc3472..0982ef6 100644
--- a/Tests/ttLib/tables/data/aots/lookupflag_ignore_base_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/lookupflag_ignore_base_f1.ttx.GSUB
@@ -31,9 +31,9 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="4"/>
-        <LookupFlag value="2"/><!-- ignoreBaseGlyphs -->
+        <LookupFlag value="2"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g18">
             <Ligature components="g19,g20" glyph="g23"/>
           </LigatureSet>
diff --git a/Tests/ttLib/tables/data/aots/lookupflag_ignore_combination_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/lookupflag_ignore_combination_f1.ttx.GDEF
index e81490b..b67d75e 100644
--- a/Tests/ttLib/tables/data/aots/lookupflag_ignore_combination_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/lookupflag_ignore_combination_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g24" class="1"/>
       <ClassDef glyph="g25" class="1"/>
       <ClassDef glyph="g26" class="1"/>
@@ -14,7 +14,7 @@
       <ClassDef glyph="g31" class="3"/>
       <ClassDef glyph="g32" class="3"/>
     </GlyphClassDef>
-    <MarkAttachClassDef>
+    <MarkAttachClassDef Format="2">
       <ClassDef glyph="g25" class="1"/>
       <ClassDef glyph="g26" class="2"/>
       <ClassDef glyph="g28" class="1"/>
diff --git a/Tests/ttLib/tables/data/aots/lookupflag_ignore_combination_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/lookupflag_ignore_combination_f1.ttx.GSUB
index ffdc2ae..95047b3 100644
--- a/Tests/ttLib/tables/data/aots/lookupflag_ignore_combination_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/lookupflag_ignore_combination_f1.ttx.GSUB
@@ -31,9 +31,9 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="4"/>
-        <LookupFlag value="514"/><!-- ignoreBaseGlyphs markAttachmentType[2] -->
+        <LookupFlag value="514"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g18">
             <Ligature components="g19,g20" glyph="g23"/>
           </LigatureSet>
diff --git a/Tests/ttLib/tables/data/aots/lookupflag_ignore_ligatures_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/lookupflag_ignore_ligatures_f1.ttx.GDEF
index b914431..19aa7aa 100644
--- a/Tests/ttLib/tables/data/aots/lookupflag_ignore_ligatures_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/lookupflag_ignore_ligatures_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g24" class="1"/>
       <ClassDef glyph="g25" class="1"/>
       <ClassDef glyph="g26" class="2"/>
diff --git a/Tests/ttLib/tables/data/aots/lookupflag_ignore_ligatures_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/lookupflag_ignore_ligatures_f1.ttx.GSUB
index db7fcc0..3bc1e8d 100644
--- a/Tests/ttLib/tables/data/aots/lookupflag_ignore_ligatures_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/lookupflag_ignore_ligatures_f1.ttx.GSUB
@@ -31,9 +31,9 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="4"/>
-        <LookupFlag value="4"/><!-- ignoreLigatures -->
+        <LookupFlag value="4"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g18">
             <Ligature components="g19,g20" glyph="g23"/>
           </LigatureSet>
diff --git a/Tests/ttLib/tables/data/aots/lookupflag_ignore_marks_f1.ttx.GDEF b/Tests/ttLib/tables/data/aots/lookupflag_ignore_marks_f1.ttx.GDEF
index b914431..19aa7aa 100644
--- a/Tests/ttLib/tables/data/aots/lookupflag_ignore_marks_f1.ttx.GDEF
+++ b/Tests/ttLib/tables/data/aots/lookupflag_ignore_marks_f1.ttx.GDEF
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="g24" class="1"/>
       <ClassDef glyph="g25" class="1"/>
       <ClassDef glyph="g26" class="2"/>
diff --git a/Tests/ttLib/tables/data/aots/lookupflag_ignore_marks_f1.ttx.GSUB b/Tests/ttLib/tables/data/aots/lookupflag_ignore_marks_f1.ttx.GSUB
index b3fd500..28b4682 100644
--- a/Tests/ttLib/tables/data/aots/lookupflag_ignore_marks_f1.ttx.GSUB
+++ b/Tests/ttLib/tables/data/aots/lookupflag_ignore_marks_f1.ttx.GSUB
@@ -31,9 +31,9 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="4"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="g18">
             <Ligature components="g19,g20" glyph="g23"/>
           </LigatureSet>
diff --git a/Tests/ttLib/tables/otBase_test.py b/Tests/ttLib/tables/otBase_test.py
index ce0416e..f1fa5b0 100644
--- a/Tests/ttLib/tables/otBase_test.py
+++ b/Tests/ttLib/tables/otBase_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.textTools import deHexStr
 from fontTools.ttLib.tables.otBase import OTTableReader, OTTableWriter
 import unittest
diff --git a/Tests/ttLib/tables/otConverters_test.py b/Tests/ttLib/tables/otConverters_test.py
index 1aff03b..3b9d5e9 100644
--- a/Tests/ttLib/tables/otConverters_test.py
+++ b/Tests/ttLib/tables/otConverters_test.py
@@ -1,3 +1,7 @@
+# coding: utf-8
+from __future__ import print_function, division, absolute_import, \
+    unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.loggingTools import CapturingLogHandler
 from fontTools.misc.testTools import FakeFont, makeXMLWriter
 from fontTools.misc.textTools import deHexStr
diff --git a/Tests/ttLib/tables/otTables_test.py b/Tests/ttLib/tables/otTables_test.py
index 9202aa5..f39e27c 100644
--- a/Tests/ttLib/tables/otTables_test.py
+++ b/Tests/ttLib/tables/otTables_test.py
@@ -1,9 +1,11 @@
+# coding: utf-8
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import getXML, parseXML, FakeFont
 from fontTools.misc.textTools import deHexStr, hexStr
 from fontTools.misc.xmlWriter import XMLWriter
 from fontTools.ttLib.tables.otBase import OTTableReader, OTTableWriter
 import fontTools.ttLib.tables.otTables as otTables
-from io import StringIO
 import unittest
 
 
@@ -168,7 +170,7 @@
         table = otTables.MultipleSubst()
         table.Format = 1
         for name, attrs, content in parseXML(
-                '<Coverage>'
+                '<Coverage Format="1">'
                 '  <Glyph value="o"/>'
                 '  <Glyph value="l"/>'
                 '</Coverage>'
@@ -545,37 +547,6 @@
         })
 
 
-class SplitMultipleSubstTest:
-    def overflow(self, itemName, itemRecord):
-        from fontTools.otlLib.builder import buildMultipleSubstSubtable
-        from fontTools.ttLib.tables.otBase import OverflowErrorRecord
-
-        oldSubTable = buildMultipleSubstSubtable({'e': 1, 'a': 2, 'b': 3, 'c': 4, 'd': 5})
-        oldSubTable.Format = 1
-        newSubTable = otTables.MultipleSubst()
-
-        ok = otTables.splitMultipleSubst(oldSubTable, newSubTable, OverflowErrorRecord((None, None, None, itemName, itemRecord)))
-
-        assert ok
-        assert oldSubTable.Format == newSubTable.Format
-        return oldSubTable.mapping, newSubTable.mapping
-
-    def test_Coverage(self):
-        oldMapping, newMapping = self.overflow('Coverage', None)
-        assert oldMapping == {'a': 2, 'b': 3}
-        assert newMapping == {'c': 4, 'd': 5, 'e': 1}
-
-    def test_RangeRecord(self):
-        oldMapping, newMapping = self.overflow('RangeRecord', None)
-        assert oldMapping == {'a': 2, 'b': 3}
-        assert newMapping == {'c': 4, 'd': 5, 'e': 1}
-
-    def test_Sequence(self):
-        oldMapping, newMapping = self.overflow('Sequence', 4)
-        assert oldMapping == {'a': 2, 'b': 3,'c': 4}
-        assert newMapping == {'d': 5, 'e': 1}
-
-
 def test_splitMarkBasePos():
 	from fontTools.otlLib.builder import buildAnchor, buildMarkBasePosSubtable
 
@@ -598,92 +569,26 @@
 	glyphMap = {g: i for i, g in enumerate(glyphOrder)}
 
 	oldSubTable = buildMarkBasePosSubtable(marks, bases, glyphMap)
+	oldSubTable.MarkCoverage.Format = oldSubTable.BaseCoverage.Format = 1
 	newSubTable = otTables.MarkBasePos()
 
 	ok = otTables.splitMarkBasePos(oldSubTable, newSubTable, overflowRecord=None)
 
 	assert ok
-
-	assert getXML(oldSubTable.toXML) == [
-		'<MarkBasePos Format="1">',
-		'  <MarkCoverage>',
-		'    <Glyph value="acutecomb"/>',
-		'    <Glyph value="gravecomb"/>',
-		'  </MarkCoverage>',
-		'  <BaseCoverage>',
-		'    <Glyph value="a"/>',
-		'    <Glyph value="c"/>',
-		'  </BaseCoverage>',
-		'  <!-- ClassCount=1 -->',
-		'  <MarkArray>',
-		'    <!-- MarkCount=2 -->',
-		'    <MarkRecord index="0">',
-		'      <Class value="0"/>',
-		'      <MarkAnchor Format="1">',
-		'        <XCoordinate value="0"/>',
-		'        <YCoordinate value="600"/>',
-		'      </MarkAnchor>',
-		'    </MarkRecord>',
-		'    <MarkRecord index="1">',
-		'      <Class value="0"/>',
-		'      <MarkAnchor Format="1">',
-		'        <XCoordinate value="0"/>',
-		'        <YCoordinate value="590"/>',
-		'      </MarkAnchor>',
-		'    </MarkRecord>',
-		'  </MarkArray>',
-		'  <BaseArray>',
-		'    <!-- BaseCount=2 -->',
-		'    <BaseRecord index="0">',
-		'      <BaseAnchor index="0" Format="1">',
-		'        <XCoordinate value="350"/>',
-		'        <YCoordinate value="500"/>',
-		'      </BaseAnchor>',
-		'    </BaseRecord>',
-		'    <BaseRecord index="1">',
-		'      <BaseAnchor index="0" Format="1">',
-		'        <XCoordinate value="300"/>',
-		'        <YCoordinate value="700"/>',
-		'      </BaseAnchor>',
-		'    </BaseRecord>',
-		'  </BaseArray>',
-		'</MarkBasePos>',
+	assert oldSubTable.Format == newSubTable.Format
+	assert oldSubTable.MarkCoverage.glyphs == [
+		"acutecomb", "gravecomb"
 	]
-
-	assert getXML(newSubTable.toXML) == [
-		'<MarkBasePos Format="1">',
-		'  <MarkCoverage>',
-		'    <Glyph value="cedillacomb"/>',
-		'  </MarkCoverage>',
-		'  <BaseCoverage>',
-		'    <Glyph value="a"/>',
-		'    <Glyph value="c"/>',
-		'  </BaseCoverage>',
-		'  <!-- ClassCount=1 -->',
-		'  <MarkArray>',
-		'    <!-- MarkCount=1 -->',
-		'    <MarkRecord index="0">',
-		'      <Class value="0"/>',
-		'      <MarkAnchor Format="1">',
-		'        <XCoordinate value="0"/>',
-		'        <YCoordinate value="0"/>',
-		'      </MarkAnchor>',
-		'    </MarkRecord>',
-		'  </MarkArray>',
-		'  <BaseArray>',
-		'    <!-- BaseCount=2 -->',
-		'    <BaseRecord index="0">',
-		'      <BaseAnchor index="0" empty="1"/>',
-		'    </BaseRecord>',
-		'    <BaseRecord index="1">',
-		'      <BaseAnchor index="0" Format="1">',
-		'        <XCoordinate value="300"/>',
-		'        <YCoordinate value="0"/>',
-		'      </BaseAnchor>',
-		'    </BaseRecord>',
-		'  </BaseArray>',
-		'</MarkBasePos>',
-	]
+	assert newSubTable.MarkCoverage.glyphs == ["cedillacomb"]
+	assert newSubTable.MarkCoverage.Format == 1
+	assert oldSubTable.BaseCoverage.glyphs == newSubTable.BaseCoverage.glyphs
+	assert newSubTable.BaseCoverage.Format == 1
+	assert oldSubTable.ClassCount == newSubTable.ClassCount == 1
+	assert oldSubTable.MarkArray.MarkCount == 2
+	assert newSubTable.MarkArray.MarkCount == 1
+	assert oldSubTable.BaseArray.BaseCount == newSubTable.BaseArray.BaseCount
+	assert newSubTable.BaseArray.BaseRecord[0].BaseAnchor[0] is None
+	assert newSubTable.BaseArray.BaseRecord[1].BaseAnchor[0] == buildAnchor(300, 0)
 
 
 if __name__ == "__main__":
diff --git a/Tests/ttLib/tables/tables_test.py b/Tests/ttLib/tables/tables_test.py
index f66323f..9d03814 100644
--- a/Tests/ttLib/tables/tables_test.py
+++ b/Tests/ttLib/tables/tables_test.py
@@ -1,5 +1,7 @@
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.ttLib import TTFont, tagToXML
-from io import StringIO
 import os
 import sys
 import re
@@ -253,13 +255,13 @@
 
 
 def dump_ttx(font, tableTag):
-    f = StringIO()
+    f = UnicodeIO()
     font.saveXML(f, newlinestr='\n', tables=[tableTag])
     return ttLibVersion_RE.sub('', f.getvalue())
 
 
 def load_ttx(ttx):
-    f = StringIO()
+    f = UnicodeIO()
     f.write(ttx)
     f.seek(0)
     font = TTFont()
diff --git a/Tests/ttLib/tables/ttProgram_test.py b/Tests/ttLib/tables/ttProgram_test.py
index be6e86a..9a7d232 100644
--- a/Tests/ttLib/tables/ttProgram_test.py
+++ b/Tests/ttLib/tables/ttProgram_test.py
@@ -1,9 +1,11 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.xmlWriter import XMLWriter
 from fontTools.ttLib.tables.ttProgram import Program
 from fontTools.misc.textTools import deHexStr
 import array
-from io import StringIO
 import os
+import re
 import unittest
 
 CURR_DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
@@ -103,7 +105,7 @@
         p = Program()
         p.fromBytecode(BYTECODE)
         ttfont = TestFont()
-        buf = StringIO()
+        buf = UnicodeIO()
         writer = XMLWriter(buf, newlinestr='\n')
         try:
             p.toXML(writer, ttfont)
diff --git a/Tests/ttLib/ttFont_test.py b/Tests/ttLib/ttFont_test.py
deleted file mode 100644
index 47cedeb..0000000
--- a/Tests/ttLib/ttFont_test.py
+++ /dev/null
@@ -1,48 +0,0 @@
-import io
-from fontTools.ttLib import TTFont, newTable, registerCustomTableClass, unregisterCustomTableClass
-from fontTools.ttLib.tables.DefaultTable import DefaultTable
-
-
-class CustomTableClass(DefaultTable):
-
-    def decompile(self, data, ttFont):
-        self.numbers = list(data)
-
-    def compile(self, ttFont):
-        return bytes(self.numbers)
-
-    # not testing XML read/write
-
-
-table_C_U_S_T_ = CustomTableClass  # alias for testing
-
-
-TABLETAG = "CUST"
-
-
-def test_registerCustomTableClass():
-    font = TTFont()
-    font[TABLETAG] = newTable(TABLETAG)
-    font[TABLETAG].data = b"\x00\x01\xff"
-    f = io.BytesIO()
-    font.save(f)
-    f.seek(0)
-    assert font[TABLETAG].data == b"\x00\x01\xff"
-    registerCustomTableClass(TABLETAG, "ttFont_test", "CustomTableClass")
-    try:
-        font = TTFont(f)
-        assert font[TABLETAG].numbers == [0, 1, 255]
-        assert font[TABLETAG].compile(font) == b"\x00\x01\xff"
-    finally:
-        unregisterCustomTableClass(TABLETAG)
-
-
-def test_registerCustomTableClassStandardName():
-    registerCustomTableClass(TABLETAG, "ttFont_test")
-    try:
-        font = TTFont()
-        font[TABLETAG] = newTable(TABLETAG)
-        font[TABLETAG].numbers = [4, 5, 6]
-        assert font[TABLETAG].compile(font) == b"\x04\x05\x06"
-    finally:
-        unregisterCustomTableClass(TABLETAG)
diff --git a/Tests/ttLib/woff2_test.py b/Tests/ttLib/woff2_test.py
index c0d60ce..4a474ae 100644
--- a/Tests/ttLib/woff2_test.py
+++ b/Tests/ttLib/woff2_test.py
@@ -1,7 +1,7 @@
-from fontTools.misc.py23 import Tag, bytechr, byteord
+from __future__ import print_function, division, absolute_import, unicode_literals
+from fontTools.misc.py23 import *
 from fontTools import ttLib
 from fontTools.ttLib import woff2
-from fontTools.ttLib.tables import _g_l_y_f
 from fontTools.ttLib.woff2 import (
 	WOFF2Reader, woff2DirectorySize, woff2DirectoryFormat,
 	woff2FlagsSize, woff2UnknownTagSize, woff2Base128MaxSize, WOFF2DirectoryEntry,
@@ -12,7 +12,6 @@
 from fontTools.misc import sstruct
 from fontTools import fontBuilder
 from fontTools.pens.ttGlyphPen import TTGlyphPen
-from io import BytesIO
 import struct
 import os
 import random
@@ -23,10 +22,7 @@
 
 haveBrotli = False
 try:
-	try:
-		import brotlicffi as brotli
-	except ImportError:
-		import brotli
+	import brotli
 	haveBrotli = True
 except ImportError:
 	pass
@@ -205,7 +201,7 @@
 	# drop DSIG but keep a copy
 	DSIG_copy = copy.deepcopy(font['DSIG'])
 	del font['DSIG']
-	# override TTFont attributes
+	# ovverride TTFont attributes
 	origFlavor = font.flavor
 	origRecalcBBoxes = font.recalcBBoxes
 	origRecalcTimestamp = font.recalcTimestamp
@@ -1204,38 +1200,6 @@
 		assert tmp.getvalue() == tmp2.getvalue()
 		assert ttFont2.reader.flavorData.transformedTables == {"hmtx"}
 
-	def test_roundtrip_no_glyf_and_loca_tables(self):
-		ttx = os.path.join(
-			os.path.dirname(current_dir), "subset", "data", "google_color.ttx"
-		)
-		ttFont = ttLib.TTFont()
-		ttFont.importXML(ttx)
-
-		assert "glyf" not in ttFont
-		assert "loca" not in ttFont
-
-		ttFont.flavor = "woff2"
-		tmp = BytesIO()
-		ttFont.save(tmp)
-
-		tmp2, ttFont2 = self.roundtrip(tmp)
-		assert tmp.getvalue() == tmp2.getvalue()
-		assert ttFont.flavor == "woff2"
-
-	def test_roundtrip_off_curve_despite_overlap_bit(self):
-		ttx = os.path.join(data_dir, "woff2_overlap_offcurve_in.ttx")
-		ttFont = ttLib.TTFont()
-		ttFont.importXML(ttx)
-
-		assert ttFont["glyf"]["A"].flags[0] == _g_l_y_f.flagOverlapSimple
-
-		ttFont.flavor = "woff2"
-		tmp = BytesIO()
-		ttFont.save(tmp)
-
-		_, ttFont2 = self.roundtrip(tmp)
-		assert ttFont2.flavor == "woff2"
-		assert ttFont2["glyf"]["A"].flags[0] == 0
 
 class MainTest(object):
 
diff --git a/Tests/ttx/ttx_test.py b/Tests/ttx/ttx_test.py
index c246347..97307fb 100644
--- a/Tests/ttx/ttx_test.py
+++ b/Tests/ttx/ttx_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.misc.testTools import parseXML
 from fontTools.misc.timeTools import timestampSinceEpoch
 from fontTools.ttLib import TTFont, TTLibError
@@ -17,10 +19,7 @@
 except ImportError:
     zopfli = None
 try:
-    try:
-        import brotlicffi as brotli
-    except ImportError:
-        import brotli
+    import brotli
 except ImportError:
     brotli = None
 
diff --git a/Tests/ufoLib/GLIF1_test.py b/Tests/ufoLib/GLIF1_test.py
index 85fcc71..707c209 100644
--- a/Tests/ufoLib/GLIF1_test.py
+++ b/Tests/ufoLib/GLIF1_test.py
@@ -1,8 +1,14 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import, unicode_literals
 import unittest
 from fontTools.ufoLib.glifLib import GlifLibError, readGlyphFromString, writeGlyphToString
 from .testSupport import Glyph, stripText
 from itertools import islice
 
+try:
+	basestring
+except NameError:
+	basestring = str
 # ----------
 # Test Cases
 # ----------
@@ -10,11 +16,11 @@
 class TestGLIF1(unittest.TestCase):
 
 	def assertEqual(self, first, second, msg=None):
-		if isinstance(first, str):
+		if isinstance(first, basestring):
 			first = stripText(first)
-		if isinstance(second, str):
+		if isinstance(second, basestring):
 			second = stripText(second)
-		return super().assertEqual(first, second, msg=msg)
+		return super(TestGLIF1, self).assertEqual(first, second, msg=msg)
 
 	def pyToGLIF(self, py):
 		py = stripText(py)
diff --git a/Tests/ufoLib/GLIF2_test.py b/Tests/ufoLib/GLIF2_test.py
index ab9495d..2daa453 100644
--- a/Tests/ufoLib/GLIF2_test.py
+++ b/Tests/ufoLib/GLIF2_test.py
@@ -1,8 +1,14 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import, unicode_literals
 import unittest
 from fontTools.ufoLib.glifLib import GlifLibError, readGlyphFromString, writeGlyphToString
 from .testSupport import Glyph, stripText
 from itertools import islice
 
+try:
+	basestring
+except NameError:
+	basestring = str
 # ----------
 # Test Cases
 # ----------
@@ -10,11 +16,11 @@
 class TestGLIF2(unittest.TestCase):
 
 	def assertEqual(self, first, second, msg=None):
-		if isinstance(first, str):
+		if isinstance(first, basestring):
 			first = stripText(first)
-		if isinstance(second, str):
+		if isinstance(second, basestring):
 			second = stripText(second)
-		return super().assertEqual(first, second, msg=msg)
+		return super(TestGLIF2, self).assertEqual(first, second, msg=msg)
 
 	def pyToGLIF(self, py):
 		py = stripText(py)
diff --git a/Tests/ufoLib/UFO1_test.py b/Tests/ufoLib/UFO1_test.py
index 5feb045..6194270 100644
--- a/Tests/ufoLib/UFO1_test.py
+++ b/Tests/ufoLib/UFO1_test.py
@@ -1,3 +1,5 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import, unicode_literals
 import os
 import shutil
 import unittest
@@ -8,7 +10,7 @@
 from .testSupport import fontInfoVersion1, fontInfoVersion2
 
 
-class TestInfoObject: pass
+class TestInfoObject(object): pass
 
 
 class ReadFontInfoVersion1TestCase(unittest.TestCase):
diff --git a/Tests/ufoLib/UFO2_test.py b/Tests/ufoLib/UFO2_test.py
index 68b4baf..04309ba 100644
--- a/Tests/ufoLib/UFO2_test.py
+++ b/Tests/ufoLib/UFO2_test.py
@@ -1,3 +1,5 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import, unicode_literals
 import os
 import shutil
 import unittest
@@ -8,7 +10,7 @@
 from .testSupport import fontInfoVersion2
 
 
-class TestInfoObject: pass
+class TestInfoObject(object): pass
 
 
 class ReadFontInfoVersion2TestCase(unittest.TestCase):
diff --git a/Tests/ufoLib/UFO3_test.py b/Tests/ufoLib/UFO3_test.py
index c421802..3cfd7c8 100644
--- a/Tests/ufoLib/UFO3_test.py
+++ b/Tests/ufoLib/UFO3_test.py
@@ -1,15 +1,18 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import, unicode_literals
 import os
 import shutil
 import unittest
 import tempfile
 from io import open
+from fontTools.misc.py23 import unicode
 from fontTools.ufoLib import UFOReader, UFOWriter, UFOLibError
 from fontTools.ufoLib.glifLib import GlifLibError
 from fontTools.misc import plistlib
 from .testSupport import fontInfoVersion3
 
 
-class TestInfoObject: pass
+class TestInfoObject(object): pass
 
 
 # --------------
@@ -3940,26 +3943,6 @@
 		result = list(writer.getGlyphSet("layer 2", defaultLayer=False).keys())
 		self.assertEqual(expected, result)
 
-	def testGetGlyphSetNoContents(self):
-		self.makeUFO()
-		os.remove(os.path.join(self.ufoPath, "glyphs.layer 1", "contents.plist"))
-
-		reader = UFOReader(self.ufoPath, validate=True)
-		with self.assertRaises(GlifLibError):
-			reader.getGlyphSet("layer 1")
-
-		writer = UFOWriter(self.ufoPath, validate=True)
-		with self.assertRaises(GlifLibError):
-			writer.getGlyphSet("layer 1", defaultLayer=False, expectContentsFile=True)
-
-		# There's a separate code path for < v3 UFOs.
-		with open(os.path.join(self.ufoPath, "metainfo.plist"), "wb") as f:
-			plistlib.dump(dict(creator="test", formatVersion=2), f)
-		os.remove(os.path.join(self.ufoPath, "glyphs", "contents.plist"))
-		writer = UFOWriter(self.ufoPath, validate=True, formatVersion=2)
-		with self.assertRaises(GlifLibError):
-			writer.getGlyphSet(expectContentsFile=True)
-
 	# make a new font with two layers
 
 	def testNewFontOneLayer(self):
@@ -4125,14 +4108,16 @@
 		self.makeUFO()
 		writer = UFOWriter(self.ufoPath)
 		writer.deleteGlyphSet("public.default")
-		writer.writeLayerContents(["layer 1", "layer 2"])
 		# directories
 		path = os.path.join(self.ufoPath, "glyphs")
-		self.assertEqual(False, os.path.exists(path))
+		exists = os.path.exists(path)
+		self.assertEqual(False, exists)
 		path = os.path.join(self.ufoPath, "glyphs.layer 1")
-		self.assertEqual(True, os.path.exists(path))
+		exists = os.path.exists(path)
+		self.assertEqual(True, exists)
 		path = os.path.join(self.ufoPath, "glyphs.layer 2")
-		self.assertEqual(True, os.path.exists(path))
+		exists = os.path.exists(path)
+		self.assertEqual(True, exists)
 		# layer contents
 		path = os.path.join(self.ufoPath, "layercontents.plist")
 		with open(path, "rb") as f:
@@ -4142,7 +4127,7 @@
 
 	# remove unknown layer
 
-	def testRemoveDefaultLayer2(self):
+	def testRemoveDefaultLayer(self):
 		self.makeUFO()
 		writer = UFOWriter(self.ufoPath)
 		self.assertRaises(UFOLibError, writer.deleteGlyphSet, "does not exist")
@@ -4156,7 +4141,8 @@
 			]
 		)
 		writer = UFOWriter(self.ufoPath)
-		writer.writeLayerContents(["public.default", "layer 2", "layer 1"])
+		# if passed bytes string, it'll be decoded to ASCII unicode string
+		writer.writeLayerContents(["public.default", "layer 2", b"layer 1"])
 		path = os.path.join(self.ufoPath, "layercontents.plist")
 		with open(path, "rb") as f:
 			result = plistlib.load(f)
@@ -4166,8 +4152,8 @@
 			["layer 1", "glyphs.layer 1"],
 		]
 		self.assertEqual(expected, result)
-		for layerName, _ in result:
-			assert isinstance(layerName, str)
+		for layerName, directory in result:
+			assert isinstance(layerName, unicode)
 
 # -----
 # /data
@@ -4212,19 +4198,6 @@
 		fileObject = reader.getReadFileForPath("data/org.unifiedfontobject.doesNotExist")
 		self.assertEqual(fileObject, None)
 
-	def testUFOReaderKernGroupDuplicatesRemoved(self):
-		# Non-kerning group duplicates are kept
-		# Kerning group duplicates are removed
-		expected_groups = {
-			"group1" : ["A"],
-			"group2" : ["B", "C", "B"],
-			"public.kern1.A" : ["A"],
-			"public.kern2.B" : ["B", "A", "C"],
-		}
-		reader = UFOReader(self.getFontPath())
-		groups = reader.readGroups()
-		self.assertEqual(expected_groups, groups)
-
 
 class UFO3WriteDataTestCase(unittest.TestCase):
 
@@ -4338,7 +4311,7 @@
 # layerinfo.plist
 # ---------------
 
-class TestLayerInfoObject:
+class TestLayerInfoObject(object):
 
 	color = guidelines = lib = None
 
diff --git a/Tests/ufoLib/UFOConversion_test.py b/Tests/ufoLib/UFOConversion_test.py
index 98a0812..2e288b9 100644
--- a/Tests/ufoLib/UFOConversion_test.py
+++ b/Tests/ufoLib/UFOConversion_test.py
@@ -1,3 +1,5 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import, unicode_literals
 import os
 import shutil
 import unittest
@@ -120,7 +122,7 @@
 # kerning up conversion
 # ---------------------
 
-class TestInfoObject: pass
+class TestInfoObject(object): pass
 
 
 class KerningUpConversionTestCase(unittest.TestCase):
@@ -137,9 +139,7 @@
 		("A", "public.kern2.CGroup"): 3,
 		("A", "public.kern2.DGroup"): 4,
 		("A", "A"): 1,
-		("A", "B"): 2,
-		("X", "A"): 13,
-		("X", "public.kern2.CGroup"): 14
+		("A", "B"): 2
 	}
 
 	expectedGroups = {
@@ -150,8 +150,7 @@
 		"public.kern1.CGroup": ["C", "Ccedilla"],
 		"public.kern2.CGroup": ["C", "Ccedilla"],
 		"public.kern2.DGroup": ["D"],
-		"Not A Kerning Group" : ["A"],
-		"X": ["X", "X.sc"]
+		"Not A Kerning Group" : ["A"]
 	}
 
 	def setUp(self):
@@ -166,20 +165,6 @@
 		self.clearUFO()
 		if not os.path.exists(self.ufoPath):
 			os.mkdir(self.ufoPath)
-
-		# glyphs
-		glyphsPath = os.path.join(self.ufoPath, "glyphs")
-		if not os.path.exists(glyphsPath):
-			os.mkdir(glyphsPath)
-		glyphFile = "X_.glif"
-		glyphsContents = dict(X=glyphFile)
-		path = os.path.join(glyphsPath, "contents.plist")
-		with open(path, "wb") as f:
-			plistlib.dump(glyphsContents, f)
-		path = os.path.join(glyphsPath, glyphFile)
-		with open(path, "w") as f:
-			f.write('<?xml version="1.0" encoding="UTF-8"?>\n')
-
 		# metainfo.plist
 		metaInfo = dict(creator="test", formatVersion=formatVersion)
 		path = os.path.join(self.ufoPath, "metainfo.plist")
@@ -204,10 +189,6 @@
 				"B" : 10,
 				"CGroup" : 11,
 				"DGroup" : 12
-			},
-			"X": {
-				"A" : 13,
-				"CGroup" : 14
 			}
 		}
 		path = os.path.join(self.ufoPath, "kerning.plist")
@@ -218,8 +199,7 @@
 			"BGroup" : ["B"],
 			"CGroup" : ["C", "Ccedilla"],
 			"DGroup" : ["D"],
-			"Not A Kerning Group" : ["A"],
-			"X" : ["X", "X.sc"]  # a group with a name that is also a glyph name
+			"Not A Kerning Group" : ["A"]
 		}
 		path = os.path.join(self.ufoPath, "groups.plist")
 		with open(path, "wb") as f:
diff --git a/Tests/ufoLib/UFOZ_test.py b/Tests/ufoLib/UFOZ_test.py
index 5136210..b32bba3 100644
--- a/Tests/ufoLib/UFOZ_test.py
+++ b/Tests/ufoLib/UFOZ_test.py
@@ -1,3 +1,5 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import, unicode_literals
 from fontTools.misc.py23 import tostr
 from fontTools.ufoLib import UFOReader, UFOWriter, UFOFileStructure
 from fontTools.ufoLib.errors import UFOLibError, GlifLibError
@@ -37,7 +39,7 @@
         yield tmp.getsyspath(TEST_UFOZ)
 
 
-class TestUFOZ:
+class TestUFOZ(object):
 
     def test_read(self, testufoz):
         with UFOReader(testufoz) as reader:
@@ -53,7 +55,7 @@
 
 def test_pathlike(testufo):
 
-    class PathLike:
+    class PathLike(object):
 
         def __init__(self, s):
             self._path = s
@@ -83,7 +85,7 @@
     return m
 
 
-class TestMemoryFS:
+class TestMemoryFS(object):
 
     def test_init_reader(self, memufo):
         with UFOReader(memufo) as reader:
diff --git a/Tests/ufoLib/filenames_test.py b/Tests/ufoLib/filenames_test.py
index a9415a1..a1d6d92 100644
--- a/Tests/ufoLib/filenames_test.py
+++ b/Tests/ufoLib/filenames_test.py
@@ -1,3 +1,4 @@
+from __future__ import absolute_import, unicode_literals
 import unittest
 from fontTools.ufoLib.filenames import userNameToFileName, handleClash1, handleClash2
 
diff --git a/Tests/ufoLib/glifLib_test.py b/Tests/ufoLib/glifLib_test.py
index 3af0256..3bcd07c 100644
--- a/Tests/ufoLib/glifLib_test.py
+++ b/Tests/ufoLib/glifLib_test.py
@@ -1,4 +1,4 @@
-import logging
+from __future__ import absolute_import, unicode_literals
 import os
 import tempfile
 import shutil
@@ -8,10 +8,7 @@
 from fontTools.ufoLib.glifLib import (
 	GlyphSet, glyphNameToFileName, readGlyphFromString, writeGlyphToString,
 )
-from fontTools.ufoLib.errors import GlifLibError, UnsupportedGLIFFormat, UnsupportedUFOFormat
 from fontTools.misc.etree import XML_DECLARATION
-from fontTools.pens.recordingPen import RecordingPointPen
-import pytest
 
 GLYPHSETDIR = getDemoFontGlyphSetPath()
 
@@ -54,16 +51,6 @@
 				added, removed,
 				"%s.glif file differs after round tripping" % glyphName)
 
-	def testContentsExist(self):
-		with self.assertRaises(GlifLibError):
-			GlyphSet(
-				self.dstDir,
-				ufoFormatVersion=2,
-				validateRead=True,
-				validateWrite=True,
-				expectContentsFile=True,
-			)
-
 	def testRebuildContents(self):
 		gset = GlyphSet(GLYPHSETDIR, validateRead=True, validateWrite=True)
 		contents = gset.contents
@@ -122,65 +109,43 @@
 				self.assertEqual(g.unicodes, unicodes[glyphName])
 
 
-class FileNameTest:
+class FileNameTests(unittest.TestCase):
 
-	def test_default_file_name_scheme(self):
-		assert glyphNameToFileName("a", None) == "a.glif"
-		assert glyphNameToFileName("A", None) == "A_.glif"
-		assert glyphNameToFileName("Aring", None) == "A_ring.glif"
-		assert glyphNameToFileName("F_A_B", None) == "F__A__B_.glif"
-		assert glyphNameToFileName("A.alt", None) == "A_.alt.glif"
-		assert glyphNameToFileName("A.Alt", None) == "A_.A_lt.glif"
-		assert glyphNameToFileName(".notdef", None) == "_notdef.glif"
-		assert glyphNameToFileName("T_H", None) =="T__H_.glif"
-		assert glyphNameToFileName("T_h", None) =="T__h.glif"
-		assert glyphNameToFileName("t_h", None) =="t_h.glif"
-		assert glyphNameToFileName("F_F_I", None) == "F__F__I_.glif"
-		assert glyphNameToFileName("f_f_i", None) == "f_f_i.glif"
-		assert glyphNameToFileName("AE", None) == "A_E_.glif"
-		assert glyphNameToFileName("Ae", None) == "A_e.glif"
-		assert glyphNameToFileName("ae", None) == "ae.glif"
-		assert glyphNameToFileName("aE", None) == "aE_.glif"
-		assert glyphNameToFileName("a.alt", None) == "a.alt.glif"
-		assert glyphNameToFileName("A.aLt", None) == "A_.aL_t.glif"
-		assert glyphNameToFileName("A.alT", None) == "A_.alT_.glif"
-		assert glyphNameToFileName("Aacute_V.swash", None) == "A_acute_V_.swash.glif"
-		assert glyphNameToFileName(".notdef", None) == "_notdef.glif"
-		assert glyphNameToFileName("con", None) == "_con.glif"
-		assert glyphNameToFileName("CON", None) == "C_O_N_.glif"
-		assert glyphNameToFileName("con.alt", None) == "_con.alt.glif"
-		assert glyphNameToFileName("alt.con", None) == "alt._con.glif"
-
-	def test_conflicting_case_insensitive_file_names(self, tmp_path):
-		src = GlyphSet(GLYPHSETDIR)
-		dst = GlyphSet(tmp_path)
-		glyph = src["a"]
-
-		dst.writeGlyph("a", glyph)
-		dst.writeGlyph("A", glyph)
-		dst.writeGlyph("a_", glyph)
-		dst.writeGlyph("A_", glyph)
-		dst.writeGlyph("i_j", glyph)
-
-		assert dst.contents == {
-			'a': 'a.glif',
-			'A': 'A_.glif',
-			'a_': 'a_000000000000001.glif',
-			'A_': 'A__.glif',
-			'i_j': 'i_j.glif',
-		}
-
-		# make sure filenames are unique even on case-insensitive filesystems
-		assert len({fileName.lower() for fileName in dst.contents.values()}) == 5
+	def testDefaultFileNameScheme(self):
+		self.assertEqual(glyphNameToFileName("a", None), "a.glif")
+		self.assertEqual(glyphNameToFileName("A", None), "A_.glif")
+		self.assertEqual(glyphNameToFileName("Aring", None), "A_ring.glif")
+		self.assertEqual(glyphNameToFileName("F_A_B", None), "F__A__B_.glif")
+		self.assertEqual(glyphNameToFileName("A.alt", None), "A_.alt.glif")
+		self.assertEqual(glyphNameToFileName("A.Alt", None), "A_.A_lt.glif")
+		self.assertEqual(glyphNameToFileName(".notdef", None), "_notdef.glif")
+		self.assertEqual(glyphNameToFileName("T_H", None), "T__H_.glif")
+		self.assertEqual(glyphNameToFileName("T_h", None), "T__h.glif")
+		self.assertEqual(glyphNameToFileName("t_h", None), "t_h.glif")
+		self.assertEqual(glyphNameToFileName("F_F_I", None), "F__F__I_.glif")
+		self.assertEqual(glyphNameToFileName("f_f_i", None), "f_f_i.glif")
+		self.assertEqual(glyphNameToFileName("AE", None), "A_E_.glif")
+		self.assertEqual(glyphNameToFileName("Ae", None), "A_e.glif")
+		self.assertEqual(glyphNameToFileName("ae", None), "ae.glif")
+		self.assertEqual(glyphNameToFileName("aE", None), "aE_.glif")
+		self.assertEqual(glyphNameToFileName("a.alt", None), "a.alt.glif")
+		self.assertEqual(glyphNameToFileName("A.aLt", None), "A_.aL_t.glif")
+		self.assertEqual(glyphNameToFileName("A.alT", None), "A_.alT_.glif")
+		self.assertEqual(glyphNameToFileName("Aacute_V.swash", None), "A_acute_V_.swash.glif")
+		self.assertEqual(glyphNameToFileName(".notdef", None), "_notdef.glif")
+		self.assertEqual(glyphNameToFileName("con", None), "_con.glif")
+		self.assertEqual(glyphNameToFileName("CON", None), "C_O_N_.glif")
+		self.assertEqual(glyphNameToFileName("con.alt", None), "_con.alt.glif")
+		self.assertEqual(glyphNameToFileName("alt.con", None), "alt._con.glif")
 
 
-class _Glyph:
+class _Glyph(object):
 	pass
 
 
-class ReadWriteFuncTest:
+class ReadWriteFuncTest(unittest.TestCase):
 
-	def test_roundtrip(self):
+	def testRoundTrip(self):
 		glyph = _Glyph()
 		glyph.name = "a"
 		glyph.unicodes = [0x0061]
@@ -189,126 +154,11 @@
 
 		glyph2 = _Glyph()
 		readGlyphFromString(s1, glyph2)
-		assert glyph.__dict__ == glyph2.__dict__
+		self.assertEqual(glyph.__dict__, glyph2.__dict__)
 
 		s2 = writeGlyphToString(glyph2.name, glyph2)
-		assert s1 == s2
+		self.assertEqual(s1, s2)
 
-	def test_xml_declaration(self):
+	def testXmlDeclaration(self):
 		s = writeGlyphToString("a", _Glyph())
-		assert s.startswith(XML_DECLARATION % "UTF-8")
-
-	def test_parse_xml_remove_comments(self):
-		s = b"""<?xml version='1.0' encoding='UTF-8'?>
-		<!-- a comment -->
-		<glyph name="A" format="2">
-			<advance width="1290"/>
-			<unicode hex="0041"/>
-			<!-- another comment -->
-		</glyph>
-		"""
-
-		g = _Glyph()
-		readGlyphFromString(s, g)
-
-		assert g.name == "A"
-		assert g.width == 1290
-		assert g.unicodes == [0x0041]
-
-	def test_read_unsupported_format_version(self, caplog):
-		s = """<?xml version='1.0' encoding='utf-8'?>
-		<glyph name="A" format="0" formatMinor="0">
-			<advance width="500"/>
-			<unicode hex="0041"/>
-		</glyph>
-		"""
-
-		with pytest.raises(UnsupportedGLIFFormat):
-			readGlyphFromString(s, _Glyph())  # validate=True by default
-
-		with pytest.raises(UnsupportedGLIFFormat):
-			readGlyphFromString(s, _Glyph(), validate=True)
-
-		caplog.clear()
-		with caplog.at_level(logging.WARNING, logger="fontTools.ufoLib.glifLib"):
-			readGlyphFromString(s, _Glyph(), validate=False)
-
-		assert len(caplog.records) == 1
-		assert "Unsupported GLIF format" in caplog.text
-		assert "Assuming the latest supported version" in caplog.text
-
-	def test_read_allow_format_versions(self):
-		s = """<?xml version='1.0' encoding='utf-8'?>
-		<glyph name="A" format="2">
-			<advance width="500"/>
-			<unicode hex="0041"/>
-		</glyph>
-		"""
-
-		# these two calls are are equivalent
-		readGlyphFromString(s, _Glyph(), formatVersions=[1, 2])
-		readGlyphFromString(s, _Glyph(), formatVersions=[(1, 0), (2, 0)])
-
-		# if at least one supported formatVersion, unsupported ones are ignored
-		readGlyphFromString(s, _Glyph(), formatVersions=[(2, 0), (123, 456)])
-
-		with pytest.raises(
-			ValueError,
-			match="None of the requested GLIF formatVersions are supported"
-		):
-			readGlyphFromString(s, _Glyph(), formatVersions=[0, 2001])
-
-		with pytest.raises(GlifLibError, match="Forbidden GLIF format version"):
-			readGlyphFromString(s, _Glyph(), formatVersions=[1])
-
-	def test_read_ensure_x_y(self):
-		"""Ensure that a proper GlifLibError is raised when point coordinates are
-		missing, regardless of validation setting."""
-
-		s = """<?xml version='1.0' encoding='utf-8'?>
-		<glyph name="A" format="2">
-			<outline>
-				<contour>
-					<point x="545" y="0" type="line"/>
-					<point x="638" type="line"/>
-				</contour>
-			</outline>
-		</glyph>
-		"""
-		pen = RecordingPointPen() 
-
-		with pytest.raises(GlifLibError, match="Required y attribute"):
-			readGlyphFromString(s, _Glyph(), pen)
-
-		with pytest.raises(GlifLibError, match="Required y attribute"):
-			readGlyphFromString(s, _Glyph(), pen, validate=False)
-
-def test_GlyphSet_unsupported_ufoFormatVersion(tmp_path, caplog):
-	with pytest.raises(UnsupportedUFOFormat):
-		GlyphSet(tmp_path, ufoFormatVersion=0)
-	with pytest.raises(UnsupportedUFOFormat):
-		GlyphSet(tmp_path, ufoFormatVersion=(0, 1))
-
-
-def test_GlyphSet_writeGlyph_formatVersion(tmp_path):
-	src = GlyphSet(GLYPHSETDIR)
-	dst = GlyphSet(tmp_path, ufoFormatVersion=(2, 0))
-	glyph = src["A"]
-
-	# no explicit formatVersion passed: use the more recent GLIF formatVersion
-	# that is supported by given ufoFormatVersion (GLIF 1 for UFO 2)
-	dst.writeGlyph("A", glyph)
-	glif = dst.getGLIF("A")
-	assert b'format="1"' in glif
-	assert b'formatMinor' not in glif  # omitted when 0
-
-	# explicit, unknown formatVersion
-	with pytest.raises(UnsupportedGLIFFormat):
-		dst.writeGlyph("A", glyph, formatVersion=(0, 0))
-
-	# explicit, known formatVersion but unsupported by given ufoFormatVersion
-	with pytest.raises(
-		UnsupportedGLIFFormat,
-		match="Unsupported GLIF format version .*for UFO format version",
-	):
-		dst.writeGlyph("A", glyph, formatVersion=(2, 0))
+		self.assertTrue(s.startswith(XML_DECLARATION % "UTF-8"))
diff --git a/Tests/ufoLib/testSupport.py b/Tests/ufoLib/testSupport.py
index 49f6a53..2982ce8 100755
--- a/Tests/ufoLib/testSupport.py
+++ b/Tests/ufoLib/testSupport.py
@@ -1,8 +1,13 @@
 """Miscellaneous helpers for our test suite."""
 
+from __future__ import absolute_import, unicode_literals
 import os
 from fontTools.ufoLib.utils import numberTypes
 
+try:
+	basestring
+except NameError:
+	basestring = str
 
 def getDemoFontPath():
 	"""Return the path to Data/DemoFont.ufo/."""
@@ -17,7 +22,7 @@
 
 # GLIF test tools
 
-class Glyph:
+class Glyph(object):
 
 	def __init__(self):
 		self.name = None
@@ -35,11 +40,11 @@
 		args = _listToString(args)
 		kwargs = _dictToString(kwargs)
 		if args and kwargs:
-			return f"pointPen.{command}(*{args}, **{kwargs})"
+			return "pointPen.%s(*%s, **%s)" % (command, args, kwargs)
 		elif len(args):
-			return f"pointPen.{command}(*{args})"
+			return "pointPen.%s(*%s)" % (command, args)
 		elif len(kwargs):
-			return f"pointPen.{command}(**{kwargs})"
+			return "pointPen.%s(**%s)" % (command, kwargs)
 		else:
 			return "pointPen.%s()" % command
 
@@ -98,9 +103,9 @@
 			value = _tupleToString(value)
 		elif isinstance(value, numberTypes):
 			value = repr(value)
-		elif isinstance(value, str):
+		elif isinstance(value, basestring):
 			value = "\"%s\"" % value
-		text.append(f"{key} : {value}")
+		text.append("%s : %s" % (key, value))
 	if not text:
 		return ""
 	return "{%s}" % ", ".join(text)
@@ -116,7 +121,7 @@
 			value = _tupleToString(value)
 		elif isinstance(value, numberTypes):
 			value = repr(value)
-		elif isinstance(value, str):
+		elif isinstance(value, basestring):
 			value = "\"%s\"" % value
 		text.append(value)
 	if not text:
@@ -134,7 +139,7 @@
 			value = _tupleToString(value)
 		elif isinstance(value, numberTypes):
 			value = repr(value)
-		elif isinstance(value, str):
+		elif isinstance(value, basestring):
 			value = "\"%s\"" % value
 		text.append(value)
 	if not text:
diff --git "a/Tests/ufoLib/testdata/TestFont1 \050UFO3\051.ufoz" "b/Tests/ufoLib/testdata/TestFont1 \050UFO3\051.ufoz"
deleted file mode 100644
index d78d494..0000000
--- "a/Tests/ufoLib/testdata/TestFont1 \050UFO3\051.ufoz"
+++ /dev/null
Binary files differ
diff --git a/Tests/ufoLib/testdata/UFO3-Read Data.ufo/groups.plist b/Tests/ufoLib/testdata/UFO3-Read Data.ufo/groups.plist
deleted file mode 100644
index d61c281..0000000
--- a/Tests/ufoLib/testdata/UFO3-Read Data.ufo/groups.plist
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>group1</key>
-	<array>
-		<string>A</string>
-	</array>
-	<key>group2</key>
-	<array>
-		<string>B</string>
-		<string>C</string>
-		<string>B</string>
-	</array>
-	<key>public.kern1.A</key>
-	<array>
-		<string>A</string>
-	</array>
-	<key>public.kern2.B</key>
-	<array>
-		<string>B</string>
-		<string>A</string>
-		<string>B</string>
-		<string>A</string>
-		<string>C</string>
-	</array>
-</dict>
-</plist>
diff --git a/Tests/ufoLib/ufoLib_test.py b/Tests/ufoLib/ufoLib_test.py
deleted file mode 100644
index 430e7a7..0000000
--- a/Tests/ufoLib/ufoLib_test.py
+++ /dev/null
@@ -1,98 +0,0 @@
-import logging
-import shutil
-
-from fontTools.misc import plistlib
-from fontTools.ufoLib import UFOReader, UFOWriter, UFOFormatVersion
-from fontTools.ufoLib.errors import UFOLibError, UnsupportedUFOFormat
-import pytest
-
-
-@pytest.fixture
-def ufo_path(tmp_path):
-    ufodir = tmp_path / "TestFont.ufo"
-    ufodir.mkdir()
-    with (ufodir / "metainfo.plist").open("wb") as f:
-        plistlib.dump({"creator": "pytest", "formatVersion": 3}, f)
-    (ufodir / "glyphs").mkdir()
-    with (ufodir / "layercontents.plist").open("wb") as f:
-        plistlib.dump([("public.default", "glyphs")], f)
-    return ufodir
-
-
-def test_formatVersion_deprecated(ufo_path):
-    reader = UFOReader(ufo_path)
-
-    with pytest.warns(DeprecationWarning) as warnings:
-        assert reader.formatVersion == 3
-
-    assert len(warnings) == 1
-    assert "is deprecated; use the 'formatVersionTuple'" in warnings[0].message.args[0]
-
-
-def test_formatVersionTuple(ufo_path):
-    reader = UFOReader(ufo_path)
-
-    assert reader.formatVersionTuple == (3, 0)
-    assert reader.formatVersionTuple.major == 3
-    assert reader.formatVersionTuple.minor == 0
-    assert str(reader.formatVersionTuple) == "3.0"
-
-
-def test_readMetaInfo_errors(ufo_path):
-    (ufo_path / "metainfo.plist").unlink()
-    with pytest.raises(UFOLibError, match="'metainfo.plist' is missing"):
-        UFOReader(ufo_path)
-
-    (ufo_path / "metainfo.plist").write_bytes(plistlib.dumps({}))
-    with pytest.raises(UFOLibError, match="Missing required formatVersion"):
-        UFOReader(ufo_path)
-
-    (ufo_path / "metainfo.plist").write_bytes(plistlib.dumps([]))
-    with pytest.raises(UFOLibError, match="metainfo.plist is not properly formatted"):
-        UFOReader(ufo_path)
-
-
-def test_readMetaInfo_unsupported_format_version(ufo_path, caplog):
-    metainfo = {"formatVersion": 10, "formatVersionMinor": 15}
-    (ufo_path / "metainfo.plist").write_bytes(plistlib.dumps(metainfo))
-
-    with pytest.raises(UnsupportedUFOFormat):
-        UFOReader(ufo_path)  # validate=True by default
-
-    with pytest.raises(UnsupportedUFOFormat):
-        UFOReader(ufo_path, validate=True)
-
-    caplog.clear()
-    with caplog.at_level(logging.WARNING, logger="fontTools.ufoLib"):
-        UFOReader(ufo_path, validate=False)
-
-    assert len(caplog.records) == 1
-    assert "Unsupported UFO format" in caplog.text
-    assert "Assuming the latest supported version" in caplog.text
-
-
-def test_UFOWriter_formatVersion(tmp_path):
-    ufo_path = tmp_path / "TestFont.ufo"
-    with UFOWriter(ufo_path, formatVersion=3) as writer:
-        assert writer.formatVersionTuple == (3, 0)
-
-    shutil.rmtree(str(ufo_path))
-    with UFOWriter(ufo_path, formatVersion=(2, 0)) as writer:
-        assert writer.formatVersionTuple == (2, 0)
-
-
-def test_UFOWriter_formatVersion_default_latest(tmp_path):
-    writer = UFOWriter(tmp_path / "TestFont.ufo")
-    assert writer.formatVersionTuple == UFOFormatVersion.default()
-
-
-def test_UFOWriter_unsupported_format_version(tmp_path):
-    with pytest.raises(UnsupportedUFOFormat):
-        UFOWriter(tmp_path, formatVersion=(123, 456))
-
-
-def test_UFOWriter_previous_higher_format_version(ufo_path):
-    with pytest.raises(
-        UnsupportedUFOFormat, match="UFO located at this path is a higher version"
-    ):
-        UFOWriter(ufo_path, formatVersion=(2, 0))
diff --git a/Tests/unicodedata_test.py b/Tests/unicodedata_test.py
index 05f7de6..fde3338 100644
--- a/Tests/unicodedata_test.py
+++ b/Tests/unicodedata_test.py
@@ -1,3 +1,7 @@
+from __future__ import (
+    print_function, division, absolute_import, unicode_literals)
+from fontTools.misc.py23 import *
+
 from fontTools import unicodedata
 
 import pytest
@@ -5,161 +9,161 @@
 
 def test_script():
     assert unicodedata.script("a") == "Latn"
-    assert unicodedata.script(chr(0)) == "Zyyy"
-    assert unicodedata.script(chr(0x0378)) == "Zzzz"
-    assert unicodedata.script(chr(0x10FFFF)) == "Zzzz"
+    assert unicodedata.script(unichr(0)) == "Zyyy"
+    assert unicodedata.script(unichr(0x0378)) == "Zzzz"
+    assert unicodedata.script(unichr(0x10FFFF)) == "Zzzz"
 
     # these were randomly sampled, one character per script
-    assert unicodedata.script(chr(0x1E918)) == 'Adlm'
-    assert unicodedata.script(chr(0x1170D)) == 'Ahom'
-    assert unicodedata.script(chr(0x145A0)) == 'Hluw'
-    assert unicodedata.script(chr(0x0607)) == 'Arab'
-    assert unicodedata.script(chr(0x056C)) == 'Armn'
-    assert unicodedata.script(chr(0x10B27)) == 'Avst'
-    assert unicodedata.script(chr(0x1B41)) == 'Bali'
-    assert unicodedata.script(chr(0x168AD)) == 'Bamu'
-    assert unicodedata.script(chr(0x16ADD)) == 'Bass'
-    assert unicodedata.script(chr(0x1BE5)) == 'Batk'
-    assert unicodedata.script(chr(0x09F3)) == 'Beng'
-    assert unicodedata.script(chr(0x11C5B)) == 'Bhks'
-    assert unicodedata.script(chr(0x3126)) == 'Bopo'
-    assert unicodedata.script(chr(0x1103B)) == 'Brah'
-    assert unicodedata.script(chr(0x2849)) == 'Brai'
-    assert unicodedata.script(chr(0x1A0A)) == 'Bugi'
-    assert unicodedata.script(chr(0x174E)) == 'Buhd'
-    assert unicodedata.script(chr(0x18EE)) == 'Cans'
-    assert unicodedata.script(chr(0x102B7)) == 'Cari'
-    assert unicodedata.script(chr(0x1053D)) == 'Aghb'
-    assert unicodedata.script(chr(0x11123)) == 'Cakm'
-    assert unicodedata.script(chr(0xAA1F)) == 'Cham'
-    assert unicodedata.script(chr(0xAB95)) == 'Cher'
-    assert unicodedata.script(chr(0x1F0C7)) == 'Zyyy'
-    assert unicodedata.script(chr(0x2C85)) == 'Copt'
-    assert unicodedata.script(chr(0x12014)) == 'Xsux'
-    assert unicodedata.script(chr(0x1082E)) == 'Cprt'
-    assert unicodedata.script(chr(0xA686)) == 'Cyrl'
-    assert unicodedata.script(chr(0x10417)) == 'Dsrt'
-    assert unicodedata.script(chr(0x093E)) == 'Deva'
-    assert unicodedata.script(chr(0x1BC4B)) == 'Dupl'
-    assert unicodedata.script(chr(0x1310C)) == 'Egyp'
-    assert unicodedata.script(chr(0x1051C)) == 'Elba'
-    assert unicodedata.script(chr(0x2DA6)) == 'Ethi'
-    assert unicodedata.script(chr(0x10AD)) == 'Geor'
-    assert unicodedata.script(chr(0x2C52)) == 'Glag'
-    assert unicodedata.script(chr(0x10343)) == 'Goth'
-    assert unicodedata.script(chr(0x11371)) == 'Gran'
-    assert unicodedata.script(chr(0x03D0)) == 'Grek'
-    assert unicodedata.script(chr(0x0AAA)) == 'Gujr'
-    assert unicodedata.script(chr(0x0A4C)) == 'Guru'
-    assert unicodedata.script(chr(0x23C9F)) == 'Hani'
-    assert unicodedata.script(chr(0xC259)) == 'Hang'
-    assert unicodedata.script(chr(0x1722)) == 'Hano'
-    assert unicodedata.script(chr(0x108F5)) == 'Hatr'
-    assert unicodedata.script(chr(0x05C2)) == 'Hebr'
-    assert unicodedata.script(chr(0x1B072)) == 'Hira'
-    assert unicodedata.script(chr(0x10847)) == 'Armi'
-    assert unicodedata.script(chr(0x033A)) == 'Zinh'
-    assert unicodedata.script(chr(0x10B66)) == 'Phli'
-    assert unicodedata.script(chr(0x10B4B)) == 'Prti'
-    assert unicodedata.script(chr(0xA98A)) == 'Java'
-    assert unicodedata.script(chr(0x110B2)) == 'Kthi'
-    assert unicodedata.script(chr(0x0CC6)) == 'Knda'
-    assert unicodedata.script(chr(0x3337)) == 'Kana'
-    assert unicodedata.script(chr(0xA915)) == 'Kali'
-    assert unicodedata.script(chr(0x10A2E)) == 'Khar'
-    assert unicodedata.script(chr(0x17AA)) == 'Khmr'
-    assert unicodedata.script(chr(0x11225)) == 'Khoj'
-    assert unicodedata.script(chr(0x112B6)) == 'Sind'
-    assert unicodedata.script(chr(0x0ED7)) == 'Laoo'
-    assert unicodedata.script(chr(0xAB3C)) == 'Latn'
-    assert unicodedata.script(chr(0x1C48)) == 'Lepc'
-    assert unicodedata.script(chr(0x1923)) == 'Limb'
-    assert unicodedata.script(chr(0x1071D)) == 'Lina'
-    assert unicodedata.script(chr(0x100EC)) == 'Linb'
-    assert unicodedata.script(chr(0xA4E9)) == 'Lisu'
-    assert unicodedata.script(chr(0x10284)) == 'Lyci'
-    assert unicodedata.script(chr(0x10926)) == 'Lydi'
-    assert unicodedata.script(chr(0x11161)) == 'Mahj'
-    assert unicodedata.script(chr(0x0D56)) == 'Mlym'
-    assert unicodedata.script(chr(0x0856)) == 'Mand'
-    assert unicodedata.script(chr(0x10AF0)) == 'Mani'
-    assert unicodedata.script(chr(0x11CB0)) == 'Marc'
-    assert unicodedata.script(chr(0x11D28)) == 'Gonm'
-    assert unicodedata.script(chr(0xABDD)) == 'Mtei'
-    assert unicodedata.script(chr(0x1E897)) == 'Mend'
-    assert unicodedata.script(chr(0x109B0)) == 'Merc'
-    assert unicodedata.script(chr(0x10993)) == 'Mero'
-    assert unicodedata.script(chr(0x16F5D)) == 'Plrd'
-    assert unicodedata.script(chr(0x1160B)) == 'Modi'
-    assert unicodedata.script(chr(0x18A8)) == 'Mong'
-    assert unicodedata.script(chr(0x16A48)) == 'Mroo'
-    assert unicodedata.script(chr(0x1128C)) == 'Mult'
-    assert unicodedata.script(chr(0x105B)) == 'Mymr'
-    assert unicodedata.script(chr(0x108AF)) == 'Nbat'
-    assert unicodedata.script(chr(0x19B3)) == 'Talu'
-    assert unicodedata.script(chr(0x1143D)) == 'Newa'
-    assert unicodedata.script(chr(0x07F4)) == 'Nkoo'
-    assert unicodedata.script(chr(0x1B192)) == 'Nshu'
-    assert unicodedata.script(chr(0x169C)) == 'Ogam'
-    assert unicodedata.script(chr(0x1C56)) == 'Olck'
-    assert unicodedata.script(chr(0x10CE9)) == 'Hung'
-    assert unicodedata.script(chr(0x10316)) == 'Ital'
-    assert unicodedata.script(chr(0x10A93)) == 'Narb'
-    assert unicodedata.script(chr(0x1035A)) == 'Perm'
-    assert unicodedata.script(chr(0x103D5)) == 'Xpeo'
-    assert unicodedata.script(chr(0x10A65)) == 'Sarb'
-    assert unicodedata.script(chr(0x10C09)) == 'Orkh'
-    assert unicodedata.script(chr(0x0B60)) == 'Orya'
-    assert unicodedata.script(chr(0x104CF)) == 'Osge'
-    assert unicodedata.script(chr(0x104A8)) == 'Osma'
-    assert unicodedata.script(chr(0x16B12)) == 'Hmng'
-    assert unicodedata.script(chr(0x10879)) == 'Palm'
-    assert unicodedata.script(chr(0x11AF1)) == 'Pauc'
-    assert unicodedata.script(chr(0xA869)) == 'Phag'
-    assert unicodedata.script(chr(0x10909)) == 'Phnx'
-    assert unicodedata.script(chr(0x10B81)) == 'Phlp'
-    assert unicodedata.script(chr(0xA941)) == 'Rjng'
-    assert unicodedata.script(chr(0x16C3)) == 'Runr'
-    assert unicodedata.script(chr(0x0814)) == 'Samr'
-    assert unicodedata.script(chr(0xA88C)) == 'Saur'
-    assert unicodedata.script(chr(0x111C8)) == 'Shrd'
-    assert unicodedata.script(chr(0x1045F)) == 'Shaw'
-    assert unicodedata.script(chr(0x115AD)) == 'Sidd'
-    assert unicodedata.script(chr(0x1D8C0)) == 'Sgnw'
-    assert unicodedata.script(chr(0x0DB9)) == 'Sinh'
-    assert unicodedata.script(chr(0x110F9)) == 'Sora'
-    assert unicodedata.script(chr(0x11A60)) == 'Soyo'
-    assert unicodedata.script(chr(0x1B94)) == 'Sund'
-    assert unicodedata.script(chr(0xA81F)) == 'Sylo'
-    assert unicodedata.script(chr(0x0740)) == 'Syrc'
-    assert unicodedata.script(chr(0x1714)) == 'Tglg'
-    assert unicodedata.script(chr(0x1761)) == 'Tagb'
-    assert unicodedata.script(chr(0x1965)) == 'Tale'
-    assert unicodedata.script(chr(0x1A32)) == 'Lana'
-    assert unicodedata.script(chr(0xAA86)) == 'Tavt'
-    assert unicodedata.script(chr(0x116A5)) == 'Takr'
-    assert unicodedata.script(chr(0x0B8E)) == 'Taml'
-    assert unicodedata.script(chr(0x1754D)) == 'Tang'
-    assert unicodedata.script(chr(0x0C40)) == 'Telu'
-    assert unicodedata.script(chr(0x07A4)) == 'Thaa'
-    assert unicodedata.script(chr(0x0E42)) == 'Thai'
-    assert unicodedata.script(chr(0x0F09)) == 'Tibt'
-    assert unicodedata.script(chr(0x2D3A)) == 'Tfng'
-    assert unicodedata.script(chr(0x114B0)) == 'Tirh'
-    assert unicodedata.script(chr(0x1038B)) == 'Ugar'
-    assert unicodedata.script(chr(0xA585)) == 'Vaii'
-    assert unicodedata.script(chr(0x118CF)) == 'Wara'
-    assert unicodedata.script(chr(0xA066)) == 'Yiii'
-    assert unicodedata.script(chr(0x11A31)) == 'Zanb'
+    assert unicodedata.script(unichr(0x1E918)) == 'Adlm'
+    assert unicodedata.script(unichr(0x1170D)) == 'Ahom'
+    assert unicodedata.script(unichr(0x145A0)) == 'Hluw'
+    assert unicodedata.script(unichr(0x0607)) == 'Arab'
+    assert unicodedata.script(unichr(0x056C)) == 'Armn'
+    assert unicodedata.script(unichr(0x10B27)) == 'Avst'
+    assert unicodedata.script(unichr(0x1B41)) == 'Bali'
+    assert unicodedata.script(unichr(0x168AD)) == 'Bamu'
+    assert unicodedata.script(unichr(0x16ADD)) == 'Bass'
+    assert unicodedata.script(unichr(0x1BE5)) == 'Batk'
+    assert unicodedata.script(unichr(0x09F3)) == 'Beng'
+    assert unicodedata.script(unichr(0x11C5B)) == 'Bhks'
+    assert unicodedata.script(unichr(0x3126)) == 'Bopo'
+    assert unicodedata.script(unichr(0x1103B)) == 'Brah'
+    assert unicodedata.script(unichr(0x2849)) == 'Brai'
+    assert unicodedata.script(unichr(0x1A0A)) == 'Bugi'
+    assert unicodedata.script(unichr(0x174E)) == 'Buhd'
+    assert unicodedata.script(unichr(0x18EE)) == 'Cans'
+    assert unicodedata.script(unichr(0x102B7)) == 'Cari'
+    assert unicodedata.script(unichr(0x1053D)) == 'Aghb'
+    assert unicodedata.script(unichr(0x11123)) == 'Cakm'
+    assert unicodedata.script(unichr(0xAA1F)) == 'Cham'
+    assert unicodedata.script(unichr(0xAB95)) == 'Cher'
+    assert unicodedata.script(unichr(0x1F0C7)) == 'Zyyy'
+    assert unicodedata.script(unichr(0x2C85)) == 'Copt'
+    assert unicodedata.script(unichr(0x12014)) == 'Xsux'
+    assert unicodedata.script(unichr(0x1082E)) == 'Cprt'
+    assert unicodedata.script(unichr(0xA686)) == 'Cyrl'
+    assert unicodedata.script(unichr(0x10417)) == 'Dsrt'
+    assert unicodedata.script(unichr(0x093E)) == 'Deva'
+    assert unicodedata.script(unichr(0x1BC4B)) == 'Dupl'
+    assert unicodedata.script(unichr(0x1310C)) == 'Egyp'
+    assert unicodedata.script(unichr(0x1051C)) == 'Elba'
+    assert unicodedata.script(unichr(0x2DA6)) == 'Ethi'
+    assert unicodedata.script(unichr(0x10AD)) == 'Geor'
+    assert unicodedata.script(unichr(0x2C52)) == 'Glag'
+    assert unicodedata.script(unichr(0x10343)) == 'Goth'
+    assert unicodedata.script(unichr(0x11371)) == 'Gran'
+    assert unicodedata.script(unichr(0x03D0)) == 'Grek'
+    assert unicodedata.script(unichr(0x0AAA)) == 'Gujr'
+    assert unicodedata.script(unichr(0x0A4C)) == 'Guru'
+    assert unicodedata.script(unichr(0x23C9F)) == 'Hani'
+    assert unicodedata.script(unichr(0xC259)) == 'Hang'
+    assert unicodedata.script(unichr(0x1722)) == 'Hano'
+    assert unicodedata.script(unichr(0x108F5)) == 'Hatr'
+    assert unicodedata.script(unichr(0x05C2)) == 'Hebr'
+    assert unicodedata.script(unichr(0x1B072)) == 'Hira'
+    assert unicodedata.script(unichr(0x10847)) == 'Armi'
+    assert unicodedata.script(unichr(0x033A)) == 'Zinh'
+    assert unicodedata.script(unichr(0x10B66)) == 'Phli'
+    assert unicodedata.script(unichr(0x10B4B)) == 'Prti'
+    assert unicodedata.script(unichr(0xA98A)) == 'Java'
+    assert unicodedata.script(unichr(0x110B2)) == 'Kthi'
+    assert unicodedata.script(unichr(0x0CC6)) == 'Knda'
+    assert unicodedata.script(unichr(0x3337)) == 'Kana'
+    assert unicodedata.script(unichr(0xA915)) == 'Kali'
+    assert unicodedata.script(unichr(0x10A2E)) == 'Khar'
+    assert unicodedata.script(unichr(0x17AA)) == 'Khmr'
+    assert unicodedata.script(unichr(0x11225)) == 'Khoj'
+    assert unicodedata.script(unichr(0x112B6)) == 'Sind'
+    assert unicodedata.script(unichr(0x0ED7)) == 'Laoo'
+    assert unicodedata.script(unichr(0xAB3C)) == 'Latn'
+    assert unicodedata.script(unichr(0x1C48)) == 'Lepc'
+    assert unicodedata.script(unichr(0x1923)) == 'Limb'
+    assert unicodedata.script(unichr(0x1071D)) == 'Lina'
+    assert unicodedata.script(unichr(0x100EC)) == 'Linb'
+    assert unicodedata.script(unichr(0xA4E9)) == 'Lisu'
+    assert unicodedata.script(unichr(0x10284)) == 'Lyci'
+    assert unicodedata.script(unichr(0x10926)) == 'Lydi'
+    assert unicodedata.script(unichr(0x11161)) == 'Mahj'
+    assert unicodedata.script(unichr(0x0D56)) == 'Mlym'
+    assert unicodedata.script(unichr(0x0856)) == 'Mand'
+    assert unicodedata.script(unichr(0x10AF0)) == 'Mani'
+    assert unicodedata.script(unichr(0x11CB0)) == 'Marc'
+    assert unicodedata.script(unichr(0x11D28)) == 'Gonm'
+    assert unicodedata.script(unichr(0xABDD)) == 'Mtei'
+    assert unicodedata.script(unichr(0x1E897)) == 'Mend'
+    assert unicodedata.script(unichr(0x109B0)) == 'Merc'
+    assert unicodedata.script(unichr(0x10993)) == 'Mero'
+    assert unicodedata.script(unichr(0x16F5D)) == 'Plrd'
+    assert unicodedata.script(unichr(0x1160B)) == 'Modi'
+    assert unicodedata.script(unichr(0x18A8)) == 'Mong'
+    assert unicodedata.script(unichr(0x16A48)) == 'Mroo'
+    assert unicodedata.script(unichr(0x1128C)) == 'Mult'
+    assert unicodedata.script(unichr(0x105B)) == 'Mymr'
+    assert unicodedata.script(unichr(0x108AF)) == 'Nbat'
+    assert unicodedata.script(unichr(0x19B3)) == 'Talu'
+    assert unicodedata.script(unichr(0x1143D)) == 'Newa'
+    assert unicodedata.script(unichr(0x07F4)) == 'Nkoo'
+    assert unicodedata.script(unichr(0x1B192)) == 'Nshu'
+    assert unicodedata.script(unichr(0x169C)) == 'Ogam'
+    assert unicodedata.script(unichr(0x1C56)) == 'Olck'
+    assert unicodedata.script(unichr(0x10CE9)) == 'Hung'
+    assert unicodedata.script(unichr(0x10316)) == 'Ital'
+    assert unicodedata.script(unichr(0x10A93)) == 'Narb'
+    assert unicodedata.script(unichr(0x1035A)) == 'Perm'
+    assert unicodedata.script(unichr(0x103D5)) == 'Xpeo'
+    assert unicodedata.script(unichr(0x10A65)) == 'Sarb'
+    assert unicodedata.script(unichr(0x10C09)) == 'Orkh'
+    assert unicodedata.script(unichr(0x0B60)) == 'Orya'
+    assert unicodedata.script(unichr(0x104CF)) == 'Osge'
+    assert unicodedata.script(unichr(0x104A8)) == 'Osma'
+    assert unicodedata.script(unichr(0x16B12)) == 'Hmng'
+    assert unicodedata.script(unichr(0x10879)) == 'Palm'
+    assert unicodedata.script(unichr(0x11AF1)) == 'Pauc'
+    assert unicodedata.script(unichr(0xA869)) == 'Phag'
+    assert unicodedata.script(unichr(0x10909)) == 'Phnx'
+    assert unicodedata.script(unichr(0x10B81)) == 'Phlp'
+    assert unicodedata.script(unichr(0xA941)) == 'Rjng'
+    assert unicodedata.script(unichr(0x16C3)) == 'Runr'
+    assert unicodedata.script(unichr(0x0814)) == 'Samr'
+    assert unicodedata.script(unichr(0xA88C)) == 'Saur'
+    assert unicodedata.script(unichr(0x111C8)) == 'Shrd'
+    assert unicodedata.script(unichr(0x1045F)) == 'Shaw'
+    assert unicodedata.script(unichr(0x115AD)) == 'Sidd'
+    assert unicodedata.script(unichr(0x1D8C0)) == 'Sgnw'
+    assert unicodedata.script(unichr(0x0DB9)) == 'Sinh'
+    assert unicodedata.script(unichr(0x110F9)) == 'Sora'
+    assert unicodedata.script(unichr(0x11A60)) == 'Soyo'
+    assert unicodedata.script(unichr(0x1B94)) == 'Sund'
+    assert unicodedata.script(unichr(0xA81F)) == 'Sylo'
+    assert unicodedata.script(unichr(0x0740)) == 'Syrc'
+    assert unicodedata.script(unichr(0x1714)) == 'Tglg'
+    assert unicodedata.script(unichr(0x1761)) == 'Tagb'
+    assert unicodedata.script(unichr(0x1965)) == 'Tale'
+    assert unicodedata.script(unichr(0x1A32)) == 'Lana'
+    assert unicodedata.script(unichr(0xAA86)) == 'Tavt'
+    assert unicodedata.script(unichr(0x116A5)) == 'Takr'
+    assert unicodedata.script(unichr(0x0B8E)) == 'Taml'
+    assert unicodedata.script(unichr(0x1754D)) == 'Tang'
+    assert unicodedata.script(unichr(0x0C40)) == 'Telu'
+    assert unicodedata.script(unichr(0x07A4)) == 'Thaa'
+    assert unicodedata.script(unichr(0x0E42)) == 'Thai'
+    assert unicodedata.script(unichr(0x0F09)) == 'Tibt'
+    assert unicodedata.script(unichr(0x2D3A)) == 'Tfng'
+    assert unicodedata.script(unichr(0x114B0)) == 'Tirh'
+    assert unicodedata.script(unichr(0x1038B)) == 'Ugar'
+    assert unicodedata.script(unichr(0xA585)) == 'Vaii'
+    assert unicodedata.script(unichr(0x118CF)) == 'Wara'
+    assert unicodedata.script(unichr(0xA066)) == 'Yiii'
+    assert unicodedata.script(unichr(0x11A31)) == 'Zanb'
 
 
 def test_script_extension():
     assert unicodedata.script_extension("a") == {"Latn"}
-    assert unicodedata.script_extension(chr(0)) == {"Zyyy"}
-    assert unicodedata.script_extension(chr(0x0378)) == {"Zzzz"}
-    assert unicodedata.script_extension(chr(0x10FFFF)) == {"Zzzz"}
+    assert unicodedata.script_extension(unichr(0)) == {"Zyyy"}
+    assert unicodedata.script_extension(unichr(0x0378)) == {"Zzzz"}
+    assert unicodedata.script_extension(unichr(0x10FFFF)) == {"Zzzz"}
 
-    assert unicodedata.script_extension("\u0660") == {'Arab', 'Thaa', 'Yezi'}
+    assert unicodedata.script_extension("\u0660") == {'Arab', 'Thaa'}
     assert unicodedata.script_extension("\u0964") == {
         'Beng', 'Deva', 'Dogr', 'Gong', 'Gonm', 'Gran', 'Gujr', 'Guru', 'Knda',
         'Mahj', 'Mlym', 'Nand', 'Orya', 'Sind', 'Sinh', 'Sylo', 'Takr', 'Taml',
diff --git a/Tests/varLib/builder_test.py b/Tests/varLib/builder_test.py
index 80607ea..09fd290 100644
--- a/Tests/varLib/builder_test.py
+++ b/Tests/varLib/builder_test.py
@@ -1,3 +1,4 @@
+from __future__ import print_function, division, absolute_import
 from fontTools.varLib.builder import buildVarData
 import pytest
 
diff --git a/Tests/varLib/data/FeatureVars.designspace b/Tests/varLib/data/FeatureVars.designspace
index 902fade..9c958a5 100644
--- a/Tests/varLib/data/FeatureVars.designspace
+++ b/Tests/varLib/data/FeatureVars.designspace
@@ -6,7 +6,7 @@
             <labelname xml:lang="en">Contrast</labelname>
         </axis>
     </axes>
-    <rules processing="last">
+    <rules>
         <rule name="dollar-stroke">
             <conditionset>
                 <condition name="weight" minimum="500" /> <!-- intentionally omitted maximum -->
diff --git a/Tests/varLib/data/FeatureVarsCustomTag.designspace b/Tests/varLib/data/FeatureVarsCustomTag.designspace
deleted file mode 100644
index 45b06f3..0000000
--- a/Tests/varLib/data/FeatureVarsCustomTag.designspace
+++ /dev/null
@@ -1,77 +0,0 @@
-<?xml version='1.0' encoding='utf-8'?>
-<designspace format="3">
-    <axes>
-        <axis default="368.0" maximum="1000.0" minimum="0.0" name="weight" tag="wght" />
-        <axis default="0.0" maximum="100.0" minimum="0.0" name="contrast" tag="cntr">
-            <labelname xml:lang="en">Contrast</labelname>
-        </axis>
-    </axes>
-    <rules processing="last">
-        <rule name="dollar-stroke">
-            <conditionset>
-                <condition name="weight" minimum="500" /> <!-- intentionally omitted maximum -->
-            </conditionset>
-            <sub name="uni0024" with="uni0024.nostroke" />
-        </rule>
-        <rule name="to-lowercase">
-            <conditionset>
-                <condition name="contrast" minimum="75" maximum="100" />
-            </conditionset>
-            <sub name="uni0041" with="uni0061" />
-        </rule>
-        <rule name="to-uppercase">
-            <conditionset>
-                <condition name="weight" minimum="0" maximum="200" />
-                <condition name="contrast" minimum="0" maximum="25" />
-            </conditionset>
-            <sub name="uni0061" with="uni0041" />
-        </rule>
-    </rules>
-    <sources>
-        <source familyname="Test Family" filename="master_ufo/TestFamily-Master0.ufo" name="master_0" stylename="Master0">
-            <location>
-                <dimension name="weight" xvalue="0" />
-                <dimension name="contrast" xvalue="0" />
-            </location>
-        </source>
-        <source familyname="Test Family" filename="master_ufo/TestFamily-Master1.ufo" name="master_1" stylename="Master1">
-            <lib copy="1" />
-            <groups copy="1" />
-            <info copy="1" />
-            <location>
-                <dimension name="weight" xvalue="368" />
-                <dimension name="contrast" xvalue="0" />
-            </location>
-        </source>
-        <source familyname="Test Family" filename="master_ufo/TestFamily-Master2.ufo" name="master_2" stylename="Master2">
-            <location>
-                <dimension name="weight" xvalue="1000" />
-                <dimension name="contrast" xvalue="0" />
-            </location>
-        </source>
-        <source familyname="Test Family" filename="master_ufo/TestFamily-Master3.ufo" name="master_3" stylename="Master3">
-            <location>
-                <dimension name="weight" xvalue="1000" />
-                <dimension name="contrast" xvalue="100" />
-            </location>
-        </source>
-        <source familyname="Test Family" filename="master_ufo/TestFamily-Master0.ufo" name="master_0" stylename="Master0">
-            <location>
-                <dimension name="weight" xvalue="0" />
-                <dimension name="contrast" xvalue="100" />
-            </location>
-        </source>
-        <source familyname="Test Family" filename="master_ufo/TestFamily-Master4.ufo" name="master_4" stylename="Master4">
-            <location>
-                <dimension name="weight" xvalue="368" />
-                <dimension name="contrast" xvalue="100" />
-            </location>
-        </source>
-    </sources>
-    <lib>
-        <dict>
-            <key>com.github.fonttools.varLib.featureVarsFeatureTag</key>
-            <string>calt</string>
-        </dict>
-    </lib>
-</designspace>
diff --git a/Tests/varLib/data/FeatureVarsWholeRange.designspace b/Tests/varLib/data/FeatureVarsWholeRange.designspace
deleted file mode 100644
index 2d8802c..0000000
--- a/Tests/varLib/data/FeatureVarsWholeRange.designspace
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version='1.0' encoding='utf-8'?>
-<designspace format="3">
-    <axes>
-        <axis default="368.0" maximum="1000.0" minimum="0.0" name="weight" tag="wght" />
-    </axes>
-    <rules processing="last">
-        <rule name="always">
-            <conditionset>
-                <condition name="weight" minimum="0" maximum="1000" />
-            </conditionset>
-            <sub name="uni0024" with="uni0024.nostroke" />
-        </rule>
-    </rules>
-    <sources>
-        <source familyname="Test Family" filename="master_ufo/TestFamily-Master0.ufo" name="master_0" stylename="Master0">
-            <location>
-                <dimension name="weight" xvalue="0" />
-            </location>
-        </source>
-        <source familyname="Test Family" filename="master_ufo/TestFamily-Master1.ufo" name="master_1" stylename="Master1">
-            <lib copy="1" />
-            <groups copy="1" />
-            <info copy="1" />
-            <location>
-                <dimension name="weight" xvalue="368" />
-            </location>
-        </source>
-        <source familyname="Test Family" filename="master_ufo/TestFamily-Master3.ufo" name="master_3" stylename="Master3">
-            <location>
-                <dimension name="weight" xvalue="1000" />
-            </location>
-        </source>
-    </sources>
-</designspace>
diff --git a/Tests/varLib/data/FeatureVarsWholeRangeEmpty.designspace b/Tests/varLib/data/FeatureVarsWholeRangeEmpty.designspace
deleted file mode 100644
index a692daa..0000000
--- a/Tests/varLib/data/FeatureVarsWholeRangeEmpty.designspace
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version='1.0' encoding='utf-8'?>
-<designspace format="3">
-    <axes>
-        <axis default="368.0" maximum="1000.0" minimum="0.0" name="weight" tag="wght" />
-    </axes>
-    <rules processing="last">
-        <rule name="always">
-            <conditionset>
-            </conditionset>
-            <sub name="uni0024" with="uni0024.nostroke" />
-        </rule>
-    </rules>
-    <sources>
-        <source familyname="Test Family" filename="master_ufo/TestFamily-Master0.ufo" name="master_0" stylename="Master0">
-            <location>
-                <dimension name="weight" xvalue="0" />
-            </location>
-        </source>
-        <source familyname="Test Family" filename="master_ufo/TestFamily-Master1.ufo" name="master_1" stylename="Master1">
-            <lib copy="1" />
-            <groups copy="1" />
-            <info copy="1" />
-            <location>
-                <dimension name="weight" xvalue="368" />
-            </location>
-        </source>
-        <source familyname="Test Family" filename="master_ufo/TestFamily-Master3.ufo" name="master_3" stylename="Master3">
-            <location>
-                <dimension name="weight" xvalue="1000" />
-            </location>
-        </source>
-    </sources>
-</designspace>
diff --git a/Tests/varLib/data/IncompatibleArrays.designspace b/Tests/varLib/data/IncompatibleArrays.designspace
deleted file mode 100644
index 399810e..0000000
--- a/Tests/varLib/data/IncompatibleArrays.designspace
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version='1.0' encoding='UTF-8'?>
-<designspace format="4.1">
-  <axes>
-    <axis tag="wght" name="Weight" minimum="200" maximum="700" default="200"/>
-  </axes>
-  <sources>
-    <source filename="master_incompatible_arrays/IncompatibleArrays-Regular.ttx" name="Simple Two Axis Regular" familyname="Simple Two Axis" stylename="Regular">
-      <lib copy="1"/>
-      <groups copy="1"/>
-      <features copy="1"/>
-      <info copy="1"/>
-      <location>
-        <dimension name="Weight" xvalue="200"/>
-      </location>
-    </source>
-    <source filename="master_incompatible_arrays/IncompatibleArrays-Bold.ttx" name="Simple Two Axis Bold" familyname="Simple Two Axis" stylename="Bold">
-      <location>
-        <dimension name="Weight" xvalue="700"/>
-      </location>
-    </source>
-  </sources>
-</designspace>
diff --git a/Tests/varLib/data/IncompatibleFeatures.designspace b/Tests/varLib/data/IncompatibleFeatures.designspace
deleted file mode 100644
index ab27516..0000000
--- a/Tests/varLib/data/IncompatibleFeatures.designspace
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version='1.0' encoding='UTF-8'?>
-<designspace format="4.1">
-  <axes>
-    <axis tag="wght" name="Weight" minimum="200" maximum="700" default="200"/>
-  </axes>
-  <sources>
-    <source filename="master_incompatible_features/IncompatibleFeatures-Regular.ttx" name="Simple Two Axis Regular" familyname="Simple Two Axis" stylename="Regular">
-      <lib copy="1"/>
-      <groups copy="1"/>
-      <features copy="1"/>
-      <info copy="1"/>
-      <location>
-        <dimension name="Weight" xvalue="200"/>
-      </location>
-    </source>
-    <source filename="master_incompatible_features/IncompatibleFeatures-Bold.ttx" name="Simple Two Axis Bold" familyname="Simple Two Axis" stylename="Bold">
-      <location>
-        <dimension name="Weight" xvalue="700"/>
-      </location>
-    </source>
-  </sources>
-</designspace>
diff --git a/Tests/varLib/data/IncompatibleLookupTypes.designspace b/Tests/varLib/data/IncompatibleLookupTypes.designspace
deleted file mode 100644
index c7d3575..0000000
--- a/Tests/varLib/data/IncompatibleLookupTypes.designspace
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version='1.0' encoding='UTF-8'?>
-<designspace format="4.1">
-  <axes>
-    <axis tag="wght" name="Weight" minimum="200" maximum="700" default="200"/>
-  </axes>
-  <sources>
-    <source filename="master_incompatible_lookup_types/IncompatibleLookupTypes-Regular.ttx" name="Simple Two Axis Regular" familyname="Simple Two Axis" stylename="Regular">
-      <lib copy="1"/>
-      <groups copy="1"/>
-      <features copy="1"/>
-      <info copy="1"/>
-      <location>
-        <dimension name="Weight" xvalue="200"/>
-      </location>
-    </source>
-    <source filename="master_incompatible_lookup_types/IncompatibleLookupTypes-Bold.ttx" name="Simple Two Axis Bold" familyname="Simple Two Axis" stylename="Bold">
-      <location>
-        <dimension name="Weight" xvalue="700"/>
-      </location>
-    </source>
-  </sources>
-</designspace>
diff --git a/Tests/varLib/instancer/data/PartialInstancerTest-VF.ttx b/Tests/varLib/data/PartialInstancerTest-VF.ttx
similarity index 98%
rename from Tests/varLib/instancer/data/PartialInstancerTest-VF.ttx
rename to Tests/varLib/data/PartialInstancerTest-VF.ttx
index 268b506..92540e0 100644
--- a/Tests/varLib/instancer/data/PartialInstancerTest-VF.ttx
+++ b/Tests/varLib/data/PartialInstancerTest-VF.ttx
@@ -479,9 +479,6 @@
     <namerecord nameID="296" platformID="3" platEncID="1" langID="0x409">
       TestVariableFont-XCdBd
     </namerecord>
-    <namerecord nameID="297" platformID="3" platEncID="1" langID="0x409">
-      Normal
-    </namerecord>
   </name>
 
   <post>
@@ -767,15 +764,6 @@
         <Value value="0.0"/>
         <LinkedValue value="1.0"/>
       </AxisValue>
-      <AxisValue index="3" Format="4">
-        <!-- AxisCount=1 -->
-        <Flags value="2"/>
-        <ValueNameID value="297"/>  <!-- Normal -->
-        <AxisValueRecord index="0">
-          <AxisIndex value="1"/>
-          <Value value="100.0"/>
-        </AxisValueRecord>
-      </AxisValue>
     </AxisValueArray>
     <ElidedFallbackNameID value="2"/>  <!-- Regular -->
   </STAT>
diff --git a/Tests/varLib/instancer/data/PartialInstancerTest2-VF.ttx b/Tests/varLib/data/PartialInstancerTest2-VF.ttx
similarity index 93%
rename from Tests/varLib/instancer/data/PartialInstancerTest2-VF.ttx
rename to Tests/varLib/data/PartialInstancerTest2-VF.ttx
index cd7ffa0..0f19bde 100644
--- a/Tests/varLib/instancer/data/PartialInstancerTest2-VF.ttx
+++ b/Tests/varLib/data/PartialInstancerTest2-VF.ttx
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.0">
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.41">
 
   <GlyphOrder>
     <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
@@ -14,16 +14,16 @@
     <!-- Most of this table will be recalculated by the compiler -->
     <tableVersion value="1.0"/>
     <fontRevision value="2.001"/>
-    <checkSumAdjustment value="0x605c3e60"/>
+    <checkSumAdjustment value="0x6b1f158e"/>
     <magicNumber value="0x5f0f3cf5"/>
     <flags value="00000000 00000011"/>
     <unitsPerEm value="1000"/>
     <created value="Tue Mar 15 19:50:39 2016"/>
-    <modified value="Thu Oct 17 14:43:10 2019"/>
-    <xMin value="0"/>
-    <yMin value="0"/>
-    <xMax value="638"/>
-    <yMax value="944"/>
+    <modified value="Tue May 21 16:23:19 2019"/>
+    <xMin value="-621"/>
+    <yMin value="-389"/>
+    <xMax value="2800"/>
+    <yMax value="1067"/>
     <macStyle value="00000000 00000000"/>
     <lowestRecPPEM value="6"/>
     <fontDirectionHint value="2"/>
@@ -36,10 +36,10 @@
     <ascent value="1069"/>
     <descent value="-293"/>
     <lineGap value="0"/>
-    <advanceWidthMax value="639"/>
-    <minLeftSideBearing value="0"/>
-    <minRightSideBearing value="1"/>
-    <xMaxExtent value="638"/>
+    <advanceWidthMax value="2840"/>
+    <minLeftSideBearing value="-621"/>
+    <minRightSideBearing value="-620"/>
+    <xMaxExtent value="2800"/>
     <caretSlopeRise value="1"/>
     <caretSlopeRun value="0"/>
     <caretOffset value="0"/>
@@ -55,10 +55,10 @@
     <!-- Most of this table will be recalculated by the compiler -->
     <tableVersion value="0x10000"/>
     <numGlyphs value="5"/>
-    <maxPoints value="19"/>
-    <maxContours value="2"/>
-    <maxCompositePoints value="32"/>
-    <maxCompositeContours value="3"/>
+    <maxPoints value="202"/>
+    <maxContours value="24"/>
+    <maxCompositePoints value="315"/>
+    <maxCompositeContours value="21"/>
     <maxZones value="1"/>
     <maxTwilightPoints value="0"/>
     <maxStorage value="0"/>
@@ -66,8 +66,8 @@
     <maxInstructionDefs value="0"/>
     <maxStackElements value="0"/>
     <maxSizeOfInstructions value="0"/>
-    <maxComponentElements value="2"/>
-    <maxComponentDepth value="1"/>
+    <maxComponentElements value="8"/>
+    <maxComponentDepth value="8"/>
   </maxp>
 
   <OS_2>
@@ -107,8 +107,8 @@
     <ulUnicodeRange4 value="00000000 00010000 00000000 00000000"/>
     <achVendID value="GOOG"/>
     <fsSelection value="00000001 01000000"/>
-    <usFirstCharIndex value="65"/>
-    <usLastCharIndex value="192"/>
+    <usFirstCharIndex value="0"/>
+    <usLastCharIndex value="65533"/>
     <sTypoAscender value="1069"/>
     <sTypoDescender value="-293"/>
     <sTypoLineGap value="0"/>
@@ -539,7 +539,7 @@
 
   <GDEF>
     <Version value="0x00010003"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="1">
       <ClassDef glyph="A" class="1"/>
       <ClassDef glyph="Agrave" class="1"/>
       <ClassDef glyph="T" class="1"/>
@@ -547,13 +547,13 @@
     <MarkGlyphSetsDef>
       <MarkSetTableFormat value="1"/>
       <!-- MarkSetCount=4 -->
-      <Coverage index="0">
+      <Coverage index="0" Format="1">
       </Coverage>
-      <Coverage index="1">
+      <Coverage index="1" Format="1">
       </Coverage>
-      <Coverage index="2">
+      <Coverage index="2" Format="1">
       </Coverage>
-      <Coverage index="3">
+      <Coverage index="3" Format="1">
       </Coverage>
     </MarkGlyphSetsDef>
     <VarStore Format="1">
@@ -649,22 +649,22 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
             <Glyph value="T"/>
             <Glyph value="Agrave"/>
           </Coverage>
           <ValueFormat1 value="68"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="1">
             <ClassDef glyph="A" class="1"/>
             <ClassDef glyph="Agrave" class="1"/>
             <ClassDef glyph="T" class="2"/>
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="1">
             <ClassDef glyph="A" class="1"/>
             <ClassDef glyph="Agrave" class="1"/>
             <ClassDef glyph="T" class="2"/>
@@ -1037,104 +1037,15 @@
       <Axis index="0">
         <AxisTag value="wght"/>
         <AxisNameID value="256"/>  <!-- Weight -->
-        <AxisOrdering value="1"/>
+        <AxisOrdering value="0"/>
       </Axis>
       <Axis index="1">
         <AxisTag value="wdth"/>
         <AxisNameID value="257"/>  <!-- Width -->
-        <AxisOrdering value="0"/>
+        <AxisOrdering value="1"/>
       </Axis>
     </DesignAxisRecord>
-    <!-- AxisValueCount=13 -->
-    <AxisValueArray>
-      <AxisValue index="0" Format="1">
-        <AxisIndex value="0"/>
-        <Flags value="0"/>
-        <ValueNameID value="258"/>  <!-- Thin -->
-        <Value value="100.0"/>
-      </AxisValue>
-      <AxisValue index="1" Format="1">
-        <AxisIndex value="0"/>
-        <Flags value="0"/>
-        <ValueNameID value="259"/>  <!-- ExtraLight -->
-        <Value value="200.0"/>
-      </AxisValue>
-      <AxisValue index="2" Format="1">
-        <AxisIndex value="0"/>
-        <Flags value="0"/>
-        <ValueNameID value="260"/>  <!-- Light -->
-        <Value value="300.0"/>
-      </AxisValue>
-      <AxisValue index="3" Format="3">
-        <AxisIndex value="0"/>
-        <Flags value="2"/>
-        <ValueNameID value="261"/>  <!-- Regular -->
-        <Value value="400.0"/>
-        <LinkedValue value="700.0"/>
-      </AxisValue>
-      <AxisValue index="4" Format="1">
-        <AxisIndex value="0"/>
-        <Flags value="0"/>
-        <ValueNameID value="262"/>  <!-- Medium -->
-        <Value value="500.0"/>
-      </AxisValue>
-      <AxisValue index="5" Format="1">
-        <AxisIndex value="0"/>
-        <Flags value="0"/>
-        <ValueNameID value="263"/>  <!-- SemiBold -->
-        <Value value="600.0"/>
-      </AxisValue>
-      <AxisValue index="6" Format="1">
-        <AxisIndex value="0"/>
-        <Flags value="0"/>
-        <ValueNameID value="264"/>  <!-- Bold -->
-        <Value value="700.0"/>
-      </AxisValue>
-      <AxisValue index="7" Format="1">
-        <AxisIndex value="0"/>
-        <Flags value="0"/>
-        <ValueNameID value="265"/>  <!-- ExtraBold -->
-        <Value value="800.0"/>
-      </AxisValue>
-      <AxisValue index="8" Format="1">
-        <AxisIndex value="0"/>
-        <Flags value="0"/>
-        <ValueNameID value="266"/>  <!-- Black -->
-        <Value value="900.0"/>
-      </AxisValue>
-      <AxisValue index="9" Format="2">
-        <AxisIndex value="1"/>
-        <Flags value="2"/>
-        <ValueNameID value="261"/>  <!-- Regular -->
-        <NominalValue value="100.0"/>
-        <RangeMinValue value="93.75"/>
-        <RangeMaxValue value="100.0"/>
-      </AxisValue>
-      <AxisValue index="10" Format="2">
-        <AxisIndex value="1"/>
-        <Flags value="0"/>
-        <ValueNameID value="270"/>  <!-- SemiCondensed -->
-        <NominalValue value="87.5"/>
-        <RangeMinValue value="81.25"/>
-        <RangeMaxValue value="93.75"/>
-      </AxisValue>
-      <AxisValue index="11" Format="2">
-        <AxisIndex value="1"/>
-        <Flags value="0"/>
-        <ValueNameID value="279"/>  <!-- Condensed -->
-        <NominalValue value="75.0"/>
-        <RangeMinValue value="68.75"/>
-        <RangeMaxValue value="81.25"/>
-      </AxisValue>
-      <AxisValue index="12" Format="2">
-        <AxisIndex value="1"/>
-        <Flags value="0"/>
-        <ValueNameID value="288"/>  <!-- ExtraCondensed -->
-        <NominalValue value="62.5"/>
-        <RangeMinValue value="62.5"/>
-        <RangeMaxValue value="68.75"/>
-      </AxisValue>
-    </AxisValueArray>
+    <!-- AxisValueCount=0 -->
     <ElidedFallbackNameID value="2"/>  <!-- Regular -->
   </STAT>
 
diff --git a/Tests/varLib/data/SingleMaster.designspace b/Tests/varLib/data/SingleMaster.designspace
deleted file mode 100644
index 53bdeab..0000000
--- a/Tests/varLib/data/SingleMaster.designspace
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version='1.0' encoding='utf-8'?>
-<designspace format="3">
-    <axes>
-        <axis default="400" maximum="400" minimum="400" name="weight" tag="wght" />
-    </axes>
-    <sources>
-        <source familyname="Test Family" filename="master_ufo/TestFamily-Master0.ufo" name="master_0">
-            <location>
-                <dimension name="weight" xvalue="400" />
-            </location>
-        </source>
-    </sources>
-</designspace>
diff --git a/Tests/varLib/data/TestBASE.designspace b/Tests/varLib/data/TestBASE.designspace
deleted file mode 100644
index 6a584a5..0000000
--- a/Tests/varLib/data/TestBASE.designspace
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version='1.0' encoding='utf-8'?>
-<designspace format="3">
-	<axes>
-		<axis default="0" maximum="900" minimum="0" name="weight" tag="wght" />
-	</axes>
-	<sources>
-		<source filename="master_base_test/TestBASE.0.ufo" stylename="w0.00">
-			<info copy="1" />
-			<location>
-				<dimension name="weight" xvalue="0.00" />
-			</location>
-		</source>
-		<source filename="master_base_test/TestBASE.900.ufo" stylename="w900.00">
-			
-			<location>
-				<dimension name="weight" xvalue="900.00" />
-			</location>
-		</source>
-	</sources>
-	<instances>
-		<instance familyname="TestBASE" filename="instances/TestBASE-Thin.otf" postscriptfontname="TestBASE-Thin" stylename="ExtraLight">
-			<location>
-				<dimension name="weight" xvalue="0" />
-			</location>
-			<kerning />
-			<info />
-		</instance>
-		<instance familyname="TestBASE" filename="instances/TestBase-Black.otf" postscriptfontname="TestBASE-Black" stylename="Heavy">
-			<location>
-				<dimension name="weight" xvalue="900" />
-			</location>
-			<kerning />
-			<info />
-		</instance>
-	</instances>
-</designspace>
diff --git a/Tests/varLib/data/TestCFF2Input.designspace b/Tests/varLib/data/TestCFF2Input.designspace
deleted file mode 100644
index ebbf14a..0000000
--- a/Tests/varLib/data/TestCFF2Input.designspace
+++ /dev/null
@@ -1,93 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<designspace format="3">
-    <axes>
-        <axis default="400.0" maximum="900.0" minimum="200.0" name="weight" tag="wght">
-            <map input="200" output="0" />   <!-- ExtraLight -->
-            <map input="300" output="100" /> <!-- Light -->
-            <map input="400" output="368" /> <!-- Regular -->
-            <map input="500" output="486" /> <!-- Medium -->
-            <map input="600" output="600" /> <!-- Semibold -->
-            <map input="700" output="824" /> <!-- Bold -->
-            <map input="900" output="1000" /><!-- Black -->
-        </axis>
-    </axes>
-    <rules>
-        <rule name="named.rule.1">
-            <conditionset>
-                <condition maximum="600" minimum="0" name="weight" />
-            </conditionset>
-            <sub name="dollar" with="dollar.a" />
-        </rule>
-    </rules>
-    <sources>
-        <source filename="master_cff2_input/TestCFF2_ExtraLight.ufo" name="master_0">
-            <lib copy="1" />
-            <location>
-                <dimension name="weight" xvalue="0" />
-            </location>
-        </source>
-        <source filename="master_cff2_input/TestCFF2_Regular.ufo" name="master_1">
-            <glyph mute="1" name="T" />
-            <info copy="1" />
-            <location>
-                <dimension name="weight" xvalue="368" />
-            </location>
-        </source>
-        <source filename="master_cff2_input/TestCFF2_Black.ufo" name="master_2">
-            <location>
-                <dimension name="weight" xvalue="1000" />
-            </location>
-        </source>
-    </sources>
-    <instances>
-        <instance familyname="Test CFF2 Roman" postscriptfontname="TestCFF2Roman-ExtraLight" stylename="ExtraLight">
-            <location>
-                <dimension name="weight" xvalue="0" />
-            </location>
-            <kerning />
-            <info />
-        </instance>
-        <instance familyname="Test CFF2 Roman" postscriptfontname="TestCFF2Roman-Light" stylename="Light">
-            <location>
-                <dimension name="weight" xvalue="100" />
-            </location>
-            <kerning />
-            <info />
-        </instance>
-        <instance familyname="Test CFF2 Roman" postscriptfontname="TestCFF2Roman-Regular" stylename="Regular">
-            <location>
-                <dimension name="weight" xvalue="368" />
-            </location>
-            <kerning />
-            <info />
-        </instance>
-        <instance familyname="Test CFF2 Roman" postscriptfontname="TestCFF2Roman-Medium" stylename="Medium">
-            <location>
-                <dimension name="weight" xvalue="486" />
-            </location>
-            <kerning />
-            <info />
-        </instance>
-        <instance familyname="Test CFF2 Roman" postscriptfontname="TestCFF2Roman-Semibold" stylename="Semibold">
-            <location>
-                <dimension name="weight" xvalue="600" />
-            </location>
-            <kerning />
-            <info />
-        </instance>
-        <instance familyname="Test CFF2 Roman" postscriptfontname="TestCFF2Roman-Bold" stylename="Bold">
-            <location>
-                <dimension name="weight" xvalue="824" />
-            </location>
-            <kerning />
-            <info />
-        </instance>
-        <instance familyname="Test CFF2 Roman" postscriptfontname="TestCFF2Roman-Black" stylename="Black">
-            <location>
-                <dimension name="weight" xvalue="1000" />
-            </location>
-            <kerning />
-            <info />
-        </instance>
-    </instances>
-</designspace>
diff --git a/Tests/varLib/data/VarLibLocationTest.designspace b/Tests/varLib/data/VarLibLocationTest.designspace
deleted file mode 100644
index b73e1b5..0000000
--- a/Tests/varLib/data/VarLibLocationTest.designspace
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version='1.0' encoding='utf-8'?>
-<designspace format="4.0">
-    <axes>
-        <axis default="100" maximum="900" minimum="100" name="weight" tag="wght">
-            <map input="500" output="105"/>
-            <map input="300" output="57"/>
-            <map input="900" output="158"/>
-            <map input="100" output="0"/>
-        </axis>
-        <axis default="50" maximum="100" minimum="0" name="width" tag="wdth" />
-    </axes>
-    <sources>
-        <source filename="A.ufo">
-            <location>
-                <dimension name="weight" xvalue="0" />
-                <dimension name="width" xvalue="50" />
-            </location>
-        </source>
-    </sources>
-    <instances>
-        <instance filename="C.ufo" familyname="C" stylename="CCC">
-            <location>
-            </location>
-        </instance>
-    </instances>
-</designspace>
diff --git a/Tests/varLib/data/master_base_test/TestBASE.0.ttx b/Tests/varLib/data/master_base_test/TestBASE.0.ttx
deleted file mode 100644
index 07f827f..0000000
--- a/Tests/varLib/data/master_base_test/TestBASE.0.ttx
+++ /dev/null
@@ -1,700 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.4">
-
-  <GlyphOrder>
-    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="space"/>
-    <GlyphID id="2" name="A"/>
-    <GlyphID id="3" name="uni5B89"/>
-    <GlyphID id="4" name="uni304B"/>
-  </GlyphOrder>
-
-  <head>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="1.0"/>
-    <fontRevision value="1.0"/>
-    <checkSumAdjustment value="0xf10ba20c"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00000011"/>
-    <unitsPerEm value="1000"/>
-    <created value="Thu Mar 19 17:38:24 2020"/>
-    <modified value="Thu Mar 19 12:05:00 2020"/>
-    <xMin value="-2"/>
-    <yMin value="-200"/>
-    <xMax value="801"/>
-    <yMax value="800"/>
-    <macStyle value="00000000 00000000"/>
-    <lowestRecPPEM value="7"/>
-    <fontDirectionHint value="2"/>
-    <indexToLocFormat value="0"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="1096"/>
-    <descent value="-161"/>
-    <lineGap value="0"/>
-    <advanceWidthMax value="1000"/>
-    <minLeftSideBearing value="-2"/>
-    <minRightSideBearing value="0"/>
-    <xMaxExtent value="801"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfHMetrics value="4"/>
-  </hhea>
-
-  <maxp>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="0x10000"/>
-    <numGlyphs value="5"/>
-    <maxPoints value="73"/>
-    <maxContours value="10"/>
-    <maxCompositePoints value="0"/>
-    <maxCompositeContours value="0"/>
-    <maxZones value="1"/>
-    <maxTwilightPoints value="2"/>
-    <maxStorage value="30"/>
-    <maxFunctionDefs value="6"/>
-    <maxInstructionDefs value="0"/>
-    <maxStackElements value="100"/>
-    <maxSizeOfInstructions value="0"/>
-    <maxComponentElements value="0"/>
-    <maxComponentDepth value="0"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="3"/>
-    <xAvgCharWidth value="740"/>
-    <usWeightClass value="100"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00001000"/>
-    <ySubscriptXSize value="650"/>
-    <ySubscriptYSize value="600"/>
-    <ySubscriptXOffset value="0"/>
-    <ySubscriptYOffset value="75"/>
-    <ySuperscriptXSize value="650"/>
-    <ySuperscriptYSize value="600"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="350"/>
-    <yStrikeoutSize value="50"/>
-    <yStrikeoutPosition value="300"/>
-    <sFamilyClass value="0"/>
-    <panose>
-      <bFamilyType value="0"/>
-      <bSerifStyle value="0"/>
-      <bWeight value="2"/>
-      <bProportion value="0"/>
-      <bContrast value="0"/>
-      <bStrokeVariation value="0"/>
-      <bArmStyle value="0"/>
-      <bLetterForm value="0"/>
-      <bMidline value="0"/>
-      <bXHeight value="0"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="UKWN"/>
-    <fsSelection value="00000000 01000000"/>
-    <usFirstCharIndex value="32"/>
-    <usLastCharIndex value="23433"/>
-    <sTypoAscender value="1096"/>
-    <sTypoDescender value="-161"/>
-    <sTypoLineGap value="0"/>
-    <usWinAscent value="1096"/>
-    <usWinDescent value="161"/>
-    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
-    <sxHeight value="500"/>
-    <sCapHeight value="700"/>
-    <usDefaultChar value="0"/>
-    <usBreakChar value="32"/>
-    <usMaxContext value="0"/>
-  </OS_2>
-
-  <hmtx>
-    <mtx name=".notdef" width="500" lsb="93"/>
-    <mtx name="A" width="600" lsb="-2"/>
-    <mtx name="space" width="600" lsb="0"/>
-    <mtx name="uni304B" width="1000" lsb="199"/>
-    <mtx name="uni5B89" width="1000" lsb="198"/>
-  </hmtx>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_4 platformID="0" platEncID="3" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x304b" name="uni304B"/><!-- HIRAGANA LETTER KA -->
-      <map code="0x5b89" name="uni5B89"/><!-- CJK UNIFIED IDEOGRAPH-5B89 -->
-    </cmap_format_4>
-    <cmap_format_4 platformID="3" platEncID="1" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x304b" name="uni304B"/><!-- HIRAGANA LETTER KA -->
-      <map code="0x5b89" name="uni5B89"/><!-- CJK UNIFIED IDEOGRAPH-5B89 -->
-    </cmap_format_4>
-  </cmap>
-
-  <loca>
-    <!-- The 'loca' table will be calculated by the compiler -->
-  </loca>
-
-  <glyf>
-
-    <!-- The xMin, yMin, xMax and yMax values
-         will be recalculated by the compiler. -->
-
-    <TTGlyph name=".notdef" xMin="93" yMin="-200" xMax="410" yMax="800">
-      <contour>
-        <pt x="410" y="800" on="1"/>
-        <pt x="410" y="-200" on="1"/>
-        <pt x="93" y="-200" on="1"/>
-        <pt x="93" y="800" on="1"/>
-      </contour>
-      <contour>
-        <pt x="333" y="733" on="1"/>
-        <pt x="168" y="733" on="1"/>
-        <pt x="168" y="700" on="1"/>
-        <pt x="233" y="700" on="1"/>
-        <pt x="233" y="663" on="1"/>
-        <pt x="167" y="663" on="1"/>
-        <pt x="167" y="630" on="1"/>
-        <pt x="333" y="630" on="1"/>
-        <pt x="333" y="663" on="1"/>
-        <pt x="267" y="663" on="1"/>
-        <pt x="267" y="700" on="1"/>
-        <pt x="333" y="700" on="1"/>
-      </contour>
-      <contour>
-        <pt x="267" y="604" on="1"/>
-        <pt x="167" y="604" on="1"/>
-        <pt x="167" y="500" on="1"/>
-        <pt x="333" y="500" on="1"/>
-        <pt x="333" y="534" on="1"/>
-        <pt x="267" y="534" on="1"/>
-      </contour>
-      <contour>
-        <pt x="233" y="570" on="1"/>
-        <pt x="233" y="534" on="1"/>
-        <pt x="200" y="534" on="1"/>
-        <pt x="200" y="570" on="1"/>
-      </contour>
-      <contour>
-        <pt x="333" y="473" on="1"/>
-        <pt x="167" y="473" on="1"/>
-        <pt x="167" y="440" on="1"/>
-        <pt x="233" y="440" on="1"/>
-        <pt x="233" y="403" on="1"/>
-        <pt x="167" y="403" on="1"/>
-        <pt x="167" y="370" on="1"/>
-        <pt x="267" y="370" on="1"/>
-        <pt x="267" y="440" on="1"/>
-        <pt x="333" y="440" on="1"/>
-      </contour>
-      <contour>
-        <pt x="333" y="413" on="1"/>
-        <pt x="300" y="413" on="1"/>
-        <pt x="300" y="347" on="1"/>
-        <pt x="167" y="347" on="1"/>
-        <pt x="167" y="313" on="1"/>
-        <pt x="333" y="313" on="1"/>
-      </contour>
-      <contour>
-        <pt x="333" y="291" on="1"/>
-        <pt x="233" y="291" on="1"/>
-        <pt x="233" y="235" on="1"/>
-        <pt x="267" y="235" on="1"/>
-        <pt x="267" y="258" on="1"/>
-        <pt x="300" y="258" on="1"/>
-        <pt x="300" y="211" on="1"/>
-        <pt x="200" y="211" on="1"/>
-        <pt x="200" y="291" on="1"/>
-        <pt x="167" y="291" on="1"/>
-        <pt x="167" y="178" on="1"/>
-        <pt x="333" y="178" on="1"/>
-      </contour>
-      <contour>
-        <pt x="333" y="118" on="1"/>
-        <pt x="167" y="118" on="1"/>
-        <pt x="167" y="5" on="1"/>
-        <pt x="333" y="5" on="1"/>
-      </contour>
-      <contour>
-        <pt x="300" y="85" on="1"/>
-        <pt x="300" y="38" on="1"/>
-        <pt x="200" y="38" on="1"/>
-        <pt x="200" y="85" on="1"/>
-      </contour>
-      <contour>
-        <pt x="333" y="-18" on="1"/>
-        <pt x="167" y="-18" on="1"/>
-        <pt x="167" y="-51" on="1"/>
-        <pt x="237" y="-51" on="1"/>
-        <pt x="167" y="-98" on="1"/>
-        <pt x="167" y="-131" on="1"/>
-        <pt x="333" y="-131" on="1"/>
-        <pt x="333" y="-98" on="1"/>
-        <pt x="231" y="-98" on="1"/>
-        <pt x="301" y="-51" on="1"/>
-        <pt x="333" y="-51" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="A" xMin="-2" yMin="0" xMax="600" yMax="700">
-      <contour>
-        <pt x="-2" y="700" on="1"/>
-        <pt x="600" y="700" on="1"/>
-        <pt x="600" y="0" on="1"/>
-        <pt x="-2" y="0" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="space"/><!-- contains no outline data -->
-
-    <TTGlyph name="uni304B" xMin="199" yMin="-20" xMax="801" yMax="630">
-      <contour>
-        <pt x="199" y="630" on="1"/>
-        <pt x="801" y="630" on="1"/>
-        <pt x="801" y="-20" on="1"/>
-        <pt x="199" y="-20" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="uni5B89" xMin="198" yMin="-51" xMax="800" yMax="649">
-      <contour>
-        <pt x="198" y="649" on="1"/>
-        <pt x="800" y="649" on="1"/>
-        <pt x="800" y="-51" on="1"/>
-        <pt x="198" y="-51" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-  </glyf>
-
-  <name>
-    <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      TestBASE
-    </namerecord>
-    <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Thin
-    </namerecord>
-    <namerecord nameID="3" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      1.000;UKWN;TestBASE-Thin
-    </namerecord>
-    <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      TestBASE Thin
-    </namerecord>
-    <namerecord nameID="5" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Version 1.000
-    </namerecord>
-    <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      TestBASE-Thin
-    </namerecord>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      TestBASE Thin
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      1.000;UKWN;TestBASE-Thin
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      TestBASE Thin
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version 1.000
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      TestBASE-Thin
-    </namerecord>
-    <namerecord nameID="16" platformID="3" platEncID="1" langID="0x409">
-      TestBASE
-    </namerecord>
-    <namerecord nameID="17" platformID="3" platEncID="1" langID="0x409">
-      Thin
-    </namerecord>
-  </name>
-
-  <post>
-    <formatType value="2.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-75"/>
-    <underlineThickness value="50"/>
-    <isFixedPitch value="0"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="0"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="0"/>
-    <psNames>
-      <!-- This file uses unique glyph names based on the information
-           found in the 'post' table. Since these names might not be unique,
-           we have to invent artificial names in case of clashes. In order to
-           be able to retain the original information, we need a name to
-           ps name mapping for those cases where they differ. That's what
-           you see below.
-            -->
-    </psNames>
-    <extraNames>
-      <!-- following are the name that are not taken from the standard Mac glyph order -->
-      <psName name="uni5B89"/>
-      <psName name="uni304B"/>
-    </extraNames>
-  </post>
-
-  <BASE>
-    <Version value="0x00010000"/>
-    <HorizAxis>
-      <BaseTagList>
-        <!-- BaseTagCount=5 -->
-        <BaselineTag index="0" value="icfb"/>
-        <BaselineTag index="1" value="icft"/>
-        <BaselineTag index="2" value="ideo"/>
-        <BaselineTag index="3" value="idtp"/>
-        <BaselineTag index="4" value="romn"/>
-      </BaseTagList>
-      <BaseScriptList>
-        <!-- BaseScriptCount=6 -->
-        <BaseScriptRecord index="0">
-          <BaseScriptTag value="DFLT"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="2"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-75"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="835"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="-120"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="880"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="1">
-          <BaseScriptTag value="cyrl"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="4"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-75"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="835"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="-120"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="880"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="2">
-          <BaseScriptTag value="grek"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="4"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-75"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="835"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="-120"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="880"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="3">
-          <BaseScriptTag value="hani"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="2"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-75"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="835"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="-120"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="880"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="4">
-          <BaseScriptTag value="kana"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="2"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-75"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="835"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="-120"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="880"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="5">
-          <BaseScriptTag value="latn"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="4"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-75"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="835"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="-120"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="880"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-      </BaseScriptList>
-    </HorizAxis>
-    <VertAxis>
-      <BaseTagList>
-        <!-- BaseTagCount=5 -->
-        <BaselineTag index="0" value="icfb"/>
-        <BaselineTag index="1" value="icft"/>
-        <BaselineTag index="2" value="ideo"/>
-        <BaselineTag index="3" value="idtp"/>
-        <BaselineTag index="4" value="romn"/>
-      </BaseTagList>
-      <BaseScriptList>
-        <!-- BaseScriptCount=6 -->
-        <BaseScriptRecord index="0">
-          <BaseScriptTag value="DFLT"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="2"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="45"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="955"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="1000"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="120"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="1">
-          <BaseScriptTag value="cyrl"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="4"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="45"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="955"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="1000"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="120"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="2">
-          <BaseScriptTag value="grek"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="4"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="45"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="955"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="1000"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="120"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="3">
-          <BaseScriptTag value="hani"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="2"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="45"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="955"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="1000"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="120"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="4">
-          <BaseScriptTag value="kana"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="2"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="45"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="955"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="1000"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="120"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="5">
-          <BaseScriptTag value="latn"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="4"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="45"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="955"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="1000"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="120"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-      </BaseScriptList>
-    </VertAxis>
-  </BASE>
-
-  <GSUB>
-    <Version value="0x00010000"/>
-  </GSUB>
-
-  <DSIG>
-    <!-- note that the Digital Signature will be invalid after recompilation! -->
-    <tableHeader flag="0x0" numSigs="0" version="1"/>
-  </DSIG>
-
-</ttFont>
diff --git a/Tests/varLib/data/master_base_test/TestBASE.900.ttx b/Tests/varLib/data/master_base_test/TestBASE.900.ttx
deleted file mode 100644
index 8b27fb6..0000000
--- a/Tests/varLib/data/master_base_test/TestBASE.900.ttx
+++ /dev/null
@@ -1,700 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.4">
-
-  <GlyphOrder>
-    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="space"/>
-    <GlyphID id="2" name="A"/>
-    <GlyphID id="3" name="uni5B89"/>
-    <GlyphID id="4" name="uni304B"/>
-  </GlyphOrder>
-
-  <head>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="1.0"/>
-    <fontRevision value="1.0"/>
-    <checkSumAdjustment value="0xc8faf2b8"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00000011"/>
-    <unitsPerEm value="1000"/>
-    <created value="Thu Mar 19 17:38:24 2020"/>
-    <modified value="Thu Mar 19 12:04:56 2020"/>
-    <xMin value="-2"/>
-    <yMin value="-200"/>
-    <xMax value="801"/>
-    <yMax value="800"/>
-    <macStyle value="00000000 00000000"/>
-    <lowestRecPPEM value="7"/>
-    <fontDirectionHint value="2"/>
-    <indexToLocFormat value="0"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="1000"/>
-    <descent value="-200"/>
-    <lineGap value="0"/>
-    <advanceWidthMax value="1000"/>
-    <minLeftSideBearing value="-2"/>
-    <minRightSideBearing value="0"/>
-    <xMaxExtent value="801"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfHMetrics value="4"/>
-  </hhea>
-
-  <maxp>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="0x10000"/>
-    <numGlyphs value="5"/>
-    <maxPoints value="73"/>
-    <maxContours value="10"/>
-    <maxCompositePoints value="0"/>
-    <maxCompositeContours value="0"/>
-    <maxZones value="1"/>
-    <maxTwilightPoints value="2"/>
-    <maxStorage value="30"/>
-    <maxFunctionDefs value="6"/>
-    <maxInstructionDefs value="0"/>
-    <maxStackElements value="100"/>
-    <maxSizeOfInstructions value="0"/>
-    <maxComponentElements value="0"/>
-    <maxComponentDepth value="0"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="3"/>
-    <xAvgCharWidth value="740"/>
-    <usWeightClass value="900"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00001000"/>
-    <ySubscriptXSize value="650"/>
-    <ySubscriptYSize value="600"/>
-    <ySubscriptXOffset value="0"/>
-    <ySubscriptYOffset value="75"/>
-    <ySuperscriptXSize value="650"/>
-    <ySuperscriptYSize value="600"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="350"/>
-    <yStrikeoutSize value="50"/>
-    <yStrikeoutPosition value="300"/>
-    <sFamilyClass value="0"/>
-    <panose>
-      <bFamilyType value="0"/>
-      <bSerifStyle value="0"/>
-      <bWeight value="10"/>
-      <bProportion value="0"/>
-      <bContrast value="0"/>
-      <bStrokeVariation value="0"/>
-      <bArmStyle value="0"/>
-      <bLetterForm value="0"/>
-      <bMidline value="0"/>
-      <bXHeight value="0"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="UKWN"/>
-    <fsSelection value="00000000 01000000"/>
-    <usFirstCharIndex value="32"/>
-    <usLastCharIndex value="23433"/>
-    <sTypoAscender value="800"/>
-    <sTypoDescender value="-200"/>
-    <sTypoLineGap value="200"/>
-    <usWinAscent value="1000"/>
-    <usWinDescent value="200"/>
-    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
-    <sxHeight value="500"/>
-    <sCapHeight value="700"/>
-    <usDefaultChar value="0"/>
-    <usBreakChar value="32"/>
-    <usMaxContext value="0"/>
-  </OS_2>
-
-  <hmtx>
-    <mtx name=".notdef" width="500" lsb="93"/>
-    <mtx name="A" width="600" lsb="-2"/>
-    <mtx name="space" width="600" lsb="0"/>
-    <mtx name="uni304B" width="1000" lsb="199"/>
-    <mtx name="uni5B89" width="1000" lsb="198"/>
-  </hmtx>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_4 platformID="0" platEncID="3" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x304b" name="uni304B"/><!-- HIRAGANA LETTER KA -->
-      <map code="0x5b89" name="uni5B89"/><!-- CJK UNIFIED IDEOGRAPH-5B89 -->
-    </cmap_format_4>
-    <cmap_format_4 platformID="3" platEncID="1" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x304b" name="uni304B"/><!-- HIRAGANA LETTER KA -->
-      <map code="0x5b89" name="uni5B89"/><!-- CJK UNIFIED IDEOGRAPH-5B89 -->
-    </cmap_format_4>
-  </cmap>
-
-  <loca>
-    <!-- The 'loca' table will be calculated by the compiler -->
-  </loca>
-
-  <glyf>
-
-    <!-- The xMin, yMin, xMax and yMax values
-         will be recalculated by the compiler. -->
-
-    <TTGlyph name=".notdef" xMin="93" yMin="-200" xMax="410" yMax="800">
-      <contour>
-        <pt x="410" y="800" on="1"/>
-        <pt x="410" y="-200" on="1"/>
-        <pt x="93" y="-200" on="1"/>
-        <pt x="93" y="800" on="1"/>
-      </contour>
-      <contour>
-        <pt x="333" y="733" on="1"/>
-        <pt x="168" y="733" on="1"/>
-        <pt x="168" y="700" on="1"/>
-        <pt x="233" y="700" on="1"/>
-        <pt x="233" y="663" on="1"/>
-        <pt x="167" y="663" on="1"/>
-        <pt x="167" y="630" on="1"/>
-        <pt x="333" y="630" on="1"/>
-        <pt x="333" y="663" on="1"/>
-        <pt x="267" y="663" on="1"/>
-        <pt x="267" y="700" on="1"/>
-        <pt x="333" y="700" on="1"/>
-      </contour>
-      <contour>
-        <pt x="267" y="604" on="1"/>
-        <pt x="167" y="604" on="1"/>
-        <pt x="167" y="500" on="1"/>
-        <pt x="333" y="500" on="1"/>
-        <pt x="333" y="534" on="1"/>
-        <pt x="267" y="534" on="1"/>
-      </contour>
-      <contour>
-        <pt x="233" y="570" on="1"/>
-        <pt x="233" y="534" on="1"/>
-        <pt x="200" y="534" on="1"/>
-        <pt x="200" y="570" on="1"/>
-      </contour>
-      <contour>
-        <pt x="333" y="473" on="1"/>
-        <pt x="167" y="473" on="1"/>
-        <pt x="167" y="440" on="1"/>
-        <pt x="233" y="440" on="1"/>
-        <pt x="233" y="403" on="1"/>
-        <pt x="167" y="403" on="1"/>
-        <pt x="167" y="370" on="1"/>
-        <pt x="267" y="370" on="1"/>
-        <pt x="267" y="440" on="1"/>
-        <pt x="333" y="440" on="1"/>
-      </contour>
-      <contour>
-        <pt x="333" y="413" on="1"/>
-        <pt x="300" y="413" on="1"/>
-        <pt x="300" y="347" on="1"/>
-        <pt x="167" y="347" on="1"/>
-        <pt x="167" y="313" on="1"/>
-        <pt x="333" y="313" on="1"/>
-      </contour>
-      <contour>
-        <pt x="333" y="291" on="1"/>
-        <pt x="233" y="291" on="1"/>
-        <pt x="233" y="235" on="1"/>
-        <pt x="267" y="235" on="1"/>
-        <pt x="267" y="258" on="1"/>
-        <pt x="300" y="258" on="1"/>
-        <pt x="300" y="211" on="1"/>
-        <pt x="200" y="211" on="1"/>
-        <pt x="200" y="291" on="1"/>
-        <pt x="167" y="291" on="1"/>
-        <pt x="167" y="178" on="1"/>
-        <pt x="333" y="178" on="1"/>
-      </contour>
-      <contour>
-        <pt x="333" y="118" on="1"/>
-        <pt x="167" y="118" on="1"/>
-        <pt x="167" y="5" on="1"/>
-        <pt x="333" y="5" on="1"/>
-      </contour>
-      <contour>
-        <pt x="300" y="85" on="1"/>
-        <pt x="300" y="38" on="1"/>
-        <pt x="200" y="38" on="1"/>
-        <pt x="200" y="85" on="1"/>
-      </contour>
-      <contour>
-        <pt x="333" y="-18" on="1"/>
-        <pt x="167" y="-18" on="1"/>
-        <pt x="167" y="-51" on="1"/>
-        <pt x="237" y="-51" on="1"/>
-        <pt x="167" y="-98" on="1"/>
-        <pt x="167" y="-131" on="1"/>
-        <pt x="333" y="-131" on="1"/>
-        <pt x="333" y="-98" on="1"/>
-        <pt x="231" y="-98" on="1"/>
-        <pt x="301" y="-51" on="1"/>
-        <pt x="333" y="-51" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="A" xMin="-2" yMin="0" xMax="600" yMax="700">
-      <contour>
-        <pt x="-2" y="700" on="1"/>
-        <pt x="600" y="700" on="1"/>
-        <pt x="600" y="0" on="1"/>
-        <pt x="-2" y="0" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="space"/><!-- contains no outline data -->
-
-    <TTGlyph name="uni304B" xMin="199" yMin="-20" xMax="801" yMax="630">
-      <contour>
-        <pt x="199" y="630" on="1"/>
-        <pt x="801" y="630" on="1"/>
-        <pt x="801" y="-20" on="1"/>
-        <pt x="199" y="-20" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="uni5B89" xMin="198" yMin="-51" xMax="800" yMax="649">
-      <contour>
-        <pt x="198" y="649" on="1"/>
-        <pt x="800" y="649" on="1"/>
-        <pt x="800" y="-51" on="1"/>
-        <pt x="198" y="-51" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-  </glyf>
-
-  <name>
-    <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      TestBASE
-    </namerecord>
-    <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Black
-    </namerecord>
-    <namerecord nameID="3" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      1.000;UKWN;TestBASE-Black
-    </namerecord>
-    <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      TestBASE Black
-    </namerecord>
-    <namerecord nameID="5" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Version 1.000
-    </namerecord>
-    <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      TestBASE-Black
-    </namerecord>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      TestBASE Black
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      1.000;UKWN;TestBASE-Black
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      TestBASE Black
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version 1.000
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      TestBASE-Black
-    </namerecord>
-    <namerecord nameID="16" platformID="3" platEncID="1" langID="0x409">
-      TestBASE
-    </namerecord>
-    <namerecord nameID="17" platformID="3" platEncID="1" langID="0x409">
-      Black
-    </namerecord>
-  </name>
-
-  <post>
-    <formatType value="2.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-75"/>
-    <underlineThickness value="50"/>
-    <isFixedPitch value="0"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="0"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="0"/>
-    <psNames>
-      <!-- This file uses unique glyph names based on the information
-           found in the 'post' table. Since these names might not be unique,
-           we have to invent artificial names in case of clashes. In order to
-           be able to retain the original information, we need a name to
-           ps name mapping for those cases where they differ. That's what
-           you see below.
-            -->
-    </psNames>
-    <extraNames>
-      <!-- following are the name that are not taken from the standard Mac glyph order -->
-      <psName name="uni5B89"/>
-      <psName name="uni304B"/>
-    </extraNames>
-  </post>
-
-  <BASE>
-    <Version value="0x00010000"/>
-    <HorizAxis>
-      <BaseTagList>
-        <!-- BaseTagCount=5 -->
-        <BaselineTag index="0" value="icfb"/>
-        <BaselineTag index="1" value="icft"/>
-        <BaselineTag index="2" value="ideo"/>
-        <BaselineTag index="3" value="idtp"/>
-        <BaselineTag index="4" value="romn"/>
-      </BaseTagList>
-      <BaseScriptList>
-        <!-- BaseScriptCount=6 -->
-        <BaseScriptRecord index="0">
-          <BaseScriptTag value="DFLT"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="2"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-92"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="852"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="-120"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="880"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="1">
-          <BaseScriptTag value="cyrl"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="4"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-92"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="852"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="-120"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="880"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="2">
-          <BaseScriptTag value="grek"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="4"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-92"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="852"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="-120"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="880"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="3">
-          <BaseScriptTag value="hani"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="2"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-92"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="852"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="-120"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="880"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="4">
-          <BaseScriptTag value="kana"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="2"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-92"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="852"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="-120"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="880"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="5">
-          <BaseScriptTag value="latn"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="4"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-92"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="852"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="-120"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="880"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-      </BaseScriptList>
-    </HorizAxis>
-    <VertAxis>
-      <BaseTagList>
-        <!-- BaseTagCount=5 -->
-        <BaselineTag index="0" value="icfb"/>
-        <BaselineTag index="1" value="icft"/>
-        <BaselineTag index="2" value="ideo"/>
-        <BaselineTag index="3" value="idtp"/>
-        <BaselineTag index="4" value="romn"/>
-      </BaseTagList>
-      <BaseScriptList>
-        <!-- BaseScriptCount=6 -->
-        <BaseScriptRecord index="0">
-          <BaseScriptTag value="DFLT"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="2"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="28"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="972"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="1000"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="120"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="1">
-          <BaseScriptTag value="cyrl"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="4"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="28"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="972"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="1000"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="120"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="2">
-          <BaseScriptTag value="grek"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="4"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="28"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="972"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="1000"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="120"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="3">
-          <BaseScriptTag value="hani"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="2"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="28"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="972"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="1000"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="120"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="4">
-          <BaseScriptTag value="kana"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="2"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="28"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="972"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="1000"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="120"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="5">
-          <BaseScriptTag value="latn"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="4"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="28"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="972"/>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="1000"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="120"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-      </BaseScriptList>
-    </VertAxis>
-  </BASE>
-
-  <GSUB>
-    <Version value="0x00010000"/>
-  </GSUB>
-
-  <DSIG>
-    <!-- note that the Digital Signature will be invalid after recompilation! -->
-    <tableHeader flag="0x0" numSigs="0" version="1"/>
-  </DSIG>
-
-</ttFont>
diff --git a/Tests/varLib/data/master_cff2/TestCFF2_Black.ttx b/Tests/varLib/data/master_cff2/TestCFF2_Black.ttx
index 8b633f1..7270a16 100644
--- a/Tests/varLib/data/master_cff2/TestCFF2_Black.ttx
+++ b/Tests/varLib/data/master_cff2/TestCFF2_Black.ttx
@@ -495,7 +495,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="dollar" out="dollar.a"/>
         </SingleSubst>
       </Lookup>
diff --git a/Tests/varLib/data/master_cff2/TestCFF2_ExtraLight.ttx b/Tests/varLib/data/master_cff2/TestCFF2_ExtraLight.ttx
index aae43aa..41dbb75 100644
--- a/Tests/varLib/data/master_cff2/TestCFF2_ExtraLight.ttx
+++ b/Tests/varLib/data/master_cff2/TestCFF2_ExtraLight.ttx
@@ -495,7 +495,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="dollar" out="dollar.a"/>
         </SingleSubst>
       </Lookup>
diff --git a/Tests/varLib/data/master_cff2/TestCFF2_Regular.ttx b/Tests/varLib/data/master_cff2/TestCFF2_Regular.ttx
index 471eb24..49d116c 100644
--- a/Tests/varLib/data/master_cff2/TestCFF2_Regular.ttx
+++ b/Tests/varLib/data/master_cff2/TestCFF2_Regular.ttx
@@ -493,7 +493,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="dollar" out="dollar.a"/>
         </SingleSubst>
       </Lookup>
diff --git a/Tests/varLib/data/master_cff2_input/TestCFF2_Black.ttx b/Tests/varLib/data/master_cff2_input/TestCFF2_Black.ttx
deleted file mode 100644
index 3280eea..0000000
--- a/Tests/varLib/data/master_cff2_input/TestCFF2_Black.ttx
+++ /dev/null
@@ -1,510 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="OTTO" ttLibVersion="4.2">
-
-  <GlyphOrder>
-    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="A"/>
-    <GlyphID id="2" name="T"/>
-    <GlyphID id="3" name="dollar.a"/>
-    <GlyphID id="4" name="dollar"/>
-  </GlyphOrder>
-
-  <head>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="1.0"/>
-    <fontRevision value="1.01"/>
-    <checkSumAdjustment value="0x26378952"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00000011"/>
-    <unitsPerEm value="1000"/>
-    <created value="Thu Nov 29 14:52:09 2018"/>
-    <modified value="Thu Nov 29 14:52:09 2018"/>
-    <xMin value="0"/>
-    <yMin value="-116"/>
-    <xMax value="600"/>
-    <yMax value="750"/>
-    <macStyle value="00000000 00000000"/>
-    <lowestRecPPEM value="3"/>
-    <fontDirectionHint value="2"/>
-    <indexToLocFormat value="0"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="984"/>
-    <descent value="-273"/>
-    <lineGap value="0"/>
-    <advanceWidthMax value="600"/>
-    <minLeftSideBearing value="0"/>
-    <minRightSideBearing value="0"/>
-    <xMaxExtent value="600"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfHMetrics value="5"/>
-  </hhea>
-
-  <maxp>
-    <tableVersion value="0x5000"/>
-    <numGlyphs value="5"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="3"/>
-    <xAvgCharWidth value="592"/>
-    <usWeightClass value="900"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00000000"/>
-    <ySubscriptXSize value="650"/>
-    <ySubscriptYSize value="600"/>
-    <ySubscriptXOffset value="0"/>
-    <ySubscriptYOffset value="75"/>
-    <ySuperscriptXSize value="650"/>
-    <ySuperscriptYSize value="600"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="350"/>
-    <yStrikeoutSize value="50"/>
-    <yStrikeoutPosition value="300"/>
-    <sFamilyClass value="0"/>
-    <panose>
-      <bFamilyType value="2"/>
-      <bSerifStyle value="11"/>
-      <bWeight value="8"/>
-      <bProportion value="9"/>
-      <bContrast value="3"/>
-      <bStrokeVariation value="4"/>
-      <bArmStyle value="3"/>
-      <bLetterForm value="2"/>
-      <bMidline value="2"/>
-      <bXHeight value="4"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="ADBO"/>
-    <fsSelection value="00000000 00000000"/>
-    <usFirstCharIndex value="36"/>
-    <usLastCharIndex value="84"/>
-    <sTypoAscender value="750"/>
-    <sTypoDescender value="-250"/>
-    <sTypoLineGap value="0"/>
-    <usWinAscent value="984"/>
-    <usWinDescent value="273"/>
-    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
-    <sxHeight value="500"/>
-    <sCapHeight value="660"/>
-    <usDefaultChar value="0"/>
-    <usBreakChar value="32"/>
-    <usMaxContext value="1"/>
-  </OS_2>
-
-  <name>
-    <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Source Code Variable
-    </namerecord>
-    <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      1.010;ADBO;SourceCode_Black
-    </namerecord>
-    <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Source Code Variable
-    </namerecord>
-    <namerecord nameID="5" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Version 1.010;hotconv 1.0.109;makeotfexe 2.5.65596
-    </namerecord>
-    <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      SourceCode_Black
-    </namerecord>
-    <namerecord nameID="17" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Roman Master 2
-    </namerecord>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      Source Code Variable
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      1.010;ADBO;SourceCode_Black
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      Source Code Variable
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version 1.010;hotconv 1.0.109;makeotfexe 2.5.65596
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      SourceCode_Black
-    </namerecord>
-    <namerecord nameID="17" platformID="3" platEncID="1" langID="0x409">
-      Roman Master 2
-    </namerecord>
-  </name>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_4 platformID="0" platEncID="3" language="0">
-      <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x54" name="T"/><!-- LATIN CAPITAL LETTER T -->
-    </cmap_format_4>
-    <cmap_format_6 platformID="1" platEncID="0" language="0">
-      <map code="0x24" name="dollar"/>
-      <map code="0x41" name="A"/>
-      <map code="0x54" name="T"/>
-    </cmap_format_6>
-    <cmap_format_4 platformID="3" platEncID="1" language="0">
-      <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x54" name="T"/><!-- LATIN CAPITAL LETTER T -->
-    </cmap_format_4>
-  </cmap>
-
-  <post>
-    <formatType value="2.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-75"/>
-    <underlineThickness value="50"/>
-    <isFixedPitch value="1"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="0"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="0"/>
-    <psNames>
-      <!-- This file uses unique glyph names based on the information
-           found in the 'post' table. Since these names might not be unique,
-           we have to invent artificial names in case of clashes. In order to
-           be able to retain the original information, we need a name to
-           ps name mapping for those cases where they differ. That's what
-           you see below.
-            -->
-    </psNames>
-    <extraNames>
-      <!-- following are the name that are not taken from the standard Mac glyph order -->
-      <psName name="dollar.a"/>
-    </extraNames>
-  </post>
-
-  <CFF2>
-    <major value="2"/>
-    <minor value="0"/>
-    <CFFFont name="CFF2Font">
-      <FontMatrix value="0.001 0 0 0.001 0 0"/>
-      <FDArray>
-        <FontDict index="0">
-          <Private>
-            <BlueValues value="-12 0 500 512 580 592 634 646 650 662 696 708"/>
-            <OtherBlues value="-188 -176"/>
-            <FamilyBlues value="-12 0 486 498 574 586 638 650 656 668 712 724"/>
-            <FamilyOtherBlues value="-217 -205"/>
-            <BlueScale value="0.0625"/>
-            <BlueShift value="7"/>
-            <BlueFuzz value="0"/>
-            <StdHW value="134"/>
-            <StdVW value="172"/>
-          </Private>
-        </FontDict>
-      </FDArray>
-      <CharStrings>
-        <CharString name=".notdef">
-          24 0 rmoveto
-          552 0 rlineto
-          0 660 rlineto
-          -552 0 rlineto
-          0 -660 rlineto
-          212 104 rmoveto
-          26 56 rlineto
-          36 96 rlineto
-          4 0 rlineto
-          36 -96 rlineto
-          26 -56 rlineto
-          -128 0 rlineto
-          -100 68 rmoveto
-          0 336 rlineto
-          82 -168 rlineto
-          -82 -168 rlineto
-          162 252 rmoveto
-          -40 96 rlineto
-          -18 36 rlineto
-          120 0 rlineto
-          -18 -36 rlineto
-          -40 -96 rlineto
-          -4 0 rlineto
-          84 -84 rmoveto
-          82 168 rlineto
-          0 -336 rlineto
-          -82 168 rlineto
-        </CharString>
-        <CharString name="A">
-          0 0 rmoveto
-          176 0 rlineto
-          73 316 rlineto
-          14 62 17 78 14 66 rrcurveto
-          4 0 rlineto
-          14 -66 19 -78 14 -62 rrcurveto
-          73 -316 rlineto
-          182 0 rlineto
-          -196 650 rlineto
-          -208 0 rlineto
-          -196 -650 rlineto
-          141 138 rmoveto
-          316 0 rlineto
-          0 133 rlineto
-          -316 0 rlineto
-          0 -133 rlineto
-        </CharString>
-        <CharString name="T">
-          214 0 rmoveto
-          172 0 rlineto
-          0 506 rlineto
-          187 0 rlineto
-          0 144 rlineto
-          -546 0 rlineto
-          0 -144 rlineto
-          187 0 rlineto
-          0 -506 rlineto
-        </CharString>
-        <CharString name="dollar">
-          -107 260 39 rmoveto
-          -65 0 -28 11 -49 24 rrcurveto
-          89 -53 rlineto
-          -15 89 rlineto
-          -9 52 -22 18 -43 0 rrcurveto
-          -26 0 -27 -14 -14 -38 rrcurveto
-          0 -90 71 -54 139 0 rrcurveto
-          163 0 99 84 0 117 rrcurveto
-          0 98 -58 68 -142 45 rrcurveto
-          -33 10 rlineto
-          -72 22 -24 24 0 49 rrcurveto
-          0 61 47 23 67 0 rrcurveto
-          42 0 27 -4 52 -24 rrcurveto
-          -85 47 rlineto
-          10 -67 rlineto
-          11 -75 37 -14 39 0 rrcurveto
-          26 0 29 15 5 41 rrcurveto
-          -8 88 -76 48 -121 0 rrcurveto
-          -158 0 -85 -80 0 -115 rrcurveto
-          0 -93 66 -69 121 -39 rrcurveto
-          32 -11 rlineto
-          80 -28 23 -19 0 -53 rrcurveto
-          0 -55 -43 -39 -72 0 rrcurveto
-          64 275 rmoveto
-          0 417 rlineto
-          -71 0 rlineto
-          0 -417 rlineto
-          71 0 rlineto
-          -79 -429 rmoveto
-          71 0 rlineto
-          0 429 rlineto
-          -71 0 rlineto
-          0 -429 rlineto
-        </CharString>
-        <CharString name="dollar.a">
-          292 34 rmoveto
-          163 0 83 80 0 100 rrcurveto
-          0 182 -302 -4 0 56 rrcurveto
-          0 21 18 11 36 0 rrcurveto
-          55 0 39 -16 52 -32 rrcurveto
-          84 98 rlineto
-          -53 52 -69 36 -97 0 rrcurveto
-          -141 0 -88 -68 0 -104 rrcurveto
-          0 -188 302 12 0 -68 rrcurveto
-          0 -20 -19 -10 -37 0 rrcurveto
-          -61 0 -55 20 -72 40 rrcurveto
-          -74 -116 rlineto
-          65 -54 101 -28 70 0 rrcurveto
-          -19 -150 rmoveto
-          160 854 rlineto
-          -100 12 rlineto
-          -160 -854 rlineto
-          100 -12 rlineto
-        </CharString>
-      </CharStrings>
-    </CFFFont>
-
-    <GlobalSubrs>
-      <!-- The 'index' attribute is only for humans; it is ignored when parsed. -->
-    </GlobalSubrs>
-  </CFF2>
-
-  <BASE>
-    <Version value="0x00010000"/>
-    <HorizAxis>
-      <BaseTagList>
-        <!-- BaseTagCount=2 -->
-        <BaselineTag index="0" value="ideo"/>
-        <BaselineTag index="1" value="romn"/>
-      </BaseTagList>
-      <BaseScriptList>
-        <!-- BaseScriptCount=4 -->
-        <BaseScriptRecord index="0">
-          <BaseScriptTag value="DFLT"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="1"/>
-              <!-- BaseCoordCount=2 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-170"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="1">
-          <BaseScriptTag value="cyrl"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="1"/>
-              <!-- BaseCoordCount=2 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-170"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="2">
-          <BaseScriptTag value="grek"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="1"/>
-              <!-- BaseCoordCount=2 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-170"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="3">
-          <BaseScriptTag value="latn"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="1"/>
-              <!-- BaseCoordCount=2 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-170"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-      </BaseScriptList>
-    </HorizAxis>
-  </BASE>
-
-  <GPOS>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=1 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="size"/>
-        <Feature>
-          <FeatureParamsSize>
-            <DesignSize value="10.0"/>
-            <SubfamilyID value="0"/>
-            <SubfamilyNameID value="0"/>
-            <RangeStart value="0.0"/>
-            <RangeEnd value="0.0"/>
-          </FeatureParamsSize>
-          <!-- LookupCount=0 -->
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=0 -->
-    </LookupList>
-  </GPOS>
-
-  <GSUB>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=1 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="test"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="0"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=1 -->
-      <Lookup index="0">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="dollar" out="dollar.a"/>
-        </SingleSubst>
-      </Lookup>
-    </LookupList>
-  </GSUB>
-
-  <hmtx>
-    <mtx name=".notdef" width="600" lsb="24"/>
-    <mtx name="A" width="600" lsb="0"/>
-    <mtx name="T" width="600" lsb="27"/>
-    <mtx name="dollar" width="560" lsb="51"/>
-    <mtx name="dollar.a" width="600" lsb="56"/>
-  </hmtx>
-
-  <DSIG>
-    <!-- note that the Digital Signature will be invalid after recompilation! -->
-    <tableHeader flag="0x0" numSigs="0" version="1"/>
-  </DSIG>
-
-</ttFont>
diff --git a/Tests/varLib/data/master_cff2_input/TestCFF2_ExtraLight.ttx b/Tests/varLib/data/master_cff2_input/TestCFF2_ExtraLight.ttx
deleted file mode 100644
index fbcf91a..0000000
--- a/Tests/varLib/data/master_cff2_input/TestCFF2_ExtraLight.ttx
+++ /dev/null
@@ -1,510 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="OTTO" ttLibVersion="4.2">
-
-  <GlyphOrder>
-    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="A"/>
-    <GlyphID id="2" name="T"/>
-    <GlyphID id="3" name="dollar.a"/>
-    <GlyphID id="4" name="dollar"/>
-  </GlyphOrder>
-
-  <head>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="1.0"/>
-    <fontRevision value="1.01"/>
-    <checkSumAdjustment value="0xeb345d38"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00000011"/>
-    <unitsPerEm value="1000"/>
-    <created value="Thu Nov 29 14:52:09 2018"/>
-    <modified value="Thu Nov 29 14:52:09 2018"/>
-    <xMin value="50"/>
-    <yMin value="-115"/>
-    <xMax value="550"/>
-    <yMax value="762"/>
-    <macStyle value="00000000 00000000"/>
-    <lowestRecPPEM value="3"/>
-    <fontDirectionHint value="2"/>
-    <indexToLocFormat value="0"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="984"/>
-    <descent value="-273"/>
-    <lineGap value="0"/>
-    <advanceWidthMax value="600"/>
-    <minLeftSideBearing value="50"/>
-    <minRightSideBearing value="50"/>
-    <xMaxExtent value="550"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfHMetrics value="5"/>
-  </hhea>
-
-  <maxp>
-    <tableVersion value="0x5000"/>
-    <numGlyphs value="5"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="3"/>
-    <xAvgCharWidth value="578"/>
-    <usWeightClass value="200"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00000000"/>
-    <ySubscriptXSize value="650"/>
-    <ySubscriptYSize value="600"/>
-    <ySubscriptXOffset value="0"/>
-    <ySubscriptYOffset value="75"/>
-    <ySuperscriptXSize value="650"/>
-    <ySuperscriptYSize value="600"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="350"/>
-    <yStrikeoutSize value="50"/>
-    <yStrikeoutPosition value="286"/>
-    <sFamilyClass value="0"/>
-    <panose>
-      <bFamilyType value="2"/>
-      <bSerifStyle value="11"/>
-      <bWeight value="3"/>
-      <bProportion value="9"/>
-      <bContrast value="3"/>
-      <bStrokeVariation value="4"/>
-      <bArmStyle value="3"/>
-      <bLetterForm value="2"/>
-      <bMidline value="2"/>
-      <bXHeight value="4"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="ADBO"/>
-    <fsSelection value="00000000 00000000"/>
-    <usFirstCharIndex value="36"/>
-    <usLastCharIndex value="84"/>
-    <sTypoAscender value="750"/>
-    <sTypoDescender value="-250"/>
-    <sTypoLineGap value="0"/>
-    <usWinAscent value="984"/>
-    <usWinDescent value="273"/>
-    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
-    <sxHeight value="478"/>
-    <sCapHeight value="660"/>
-    <usDefaultChar value="0"/>
-    <usBreakChar value="32"/>
-    <usMaxContext value="1"/>
-  </OS_2>
-
-  <name>
-    <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Source Code Variable
-    </namerecord>
-    <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      1.010;ADBO;SourceCode_ExtraLight
-    </namerecord>
-    <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Source Code Variable
-    </namerecord>
-    <namerecord nameID="5" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Version 1.010;hotconv 1.0.109;makeotfexe 2.5.65596
-    </namerecord>
-    <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      SourceCode_ExtraLight
-    </namerecord>
-    <namerecord nameID="17" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Roman Master 0
-    </namerecord>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      Source Code Variable
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      1.010;ADBO;SourceCode_ExtraLight
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      Source Code Variable
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version 1.010;hotconv 1.0.109;makeotfexe 2.5.65596
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      SourceCode_ExtraLight
-    </namerecord>
-    <namerecord nameID="17" platformID="3" platEncID="1" langID="0x409">
-      Roman Master 0
-    </namerecord>
-  </name>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_4 platformID="0" platEncID="3" language="0">
-      <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x54" name="T"/><!-- LATIN CAPITAL LETTER T -->
-    </cmap_format_4>
-    <cmap_format_6 platformID="1" platEncID="0" language="0">
-      <map code="0x24" name="dollar"/>
-      <map code="0x41" name="A"/>
-      <map code="0x54" name="T"/>
-    </cmap_format_6>
-    <cmap_format_4 platformID="3" platEncID="1" language="0">
-      <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x54" name="T"/><!-- LATIN CAPITAL LETTER T -->
-    </cmap_format_4>
-  </cmap>
-
-  <post>
-    <formatType value="2.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-75"/>
-    <underlineThickness value="50"/>
-    <isFixedPitch value="1"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="0"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="0"/>
-    <psNames>
-      <!-- This file uses unique glyph names based on the information
-           found in the 'post' table. Since these names might not be unique,
-           we have to invent artificial names in case of clashes. In order to
-           be able to retain the original information, we need a name to
-           ps name mapping for those cases where they differ. That's what
-           you see below.
-            -->
-    </psNames>
-    <extraNames>
-      <!-- following are the name that are not taken from the standard Mac glyph order -->
-      <psName name="dollar.a"/>
-    </extraNames>
-  </post>
-
-  <CFF2>
-    <major value="2"/>
-    <minor value="0"/>
-    <CFFFont name="CFF2Font">
-      <FontMatrix value="0.001 0 0 0.001 0 0"/>
-      <FDArray>
-        <FontDict index="0">
-          <Private>
-            <BlueValues value="-12 0 478 490 570 582 640 652 660 672 722 734"/>
-            <OtherBlues value="-234 -222"/>
-            <FamilyBlues value="-12 0 486 498 574 586 638 650 656 668 712 724"/>
-            <FamilyOtherBlues value="-217 -205"/>
-            <BlueScale value="0.0625"/>
-            <BlueShift value="7"/>
-            <BlueFuzz value="0"/>
-            <StdHW value="28"/>
-            <StdVW value="34"/>
-          </Private>
-        </FontDict>
-      </FDArray>
-      <CharStrings>
-        <CharString name=".notdef">
-          84 0 rmoveto
-          432 0 rlineto
-          0 660 rlineto
-          -432 0 rlineto
-          0 -660 rlineto
-          48 32 rmoveto
-          102 176 rlineto
-          64 106 rlineto
-          4 0 rlineto
-          62 -106 rlineto
-          100 -176 rlineto
-          -332 0 rlineto
-          -10 42 rmoveto
-          0 536 rlineto
-          154 -270 rlineto
-          -154 -266 rlineto
-          176 292 rmoveto
-          -56 92 rlineto
-          -94 168 rlineto
-          302 0 rlineto
-          -94 -168 rlineto
-          -54 -92 rlineto
-          -4 0 rlineto
-          26 -26 rmoveto
-          152 270 rlineto
-          0 -536 rlineto
-          -152 266 rlineto
-        </CharString>
-        <CharString name="A">
-          50 0 rmoveto
-          32 0 rlineto
-          140 396 rlineto
-          28 80 24 68 24 82 rrcurveto
-          4 0 rlineto
-          24 -82 24 -68 28 -80 rrcurveto
-          138 -396 rlineto
-          34 0 rlineto
-          -236 660 rlineto
-          -28 0 rlineto
-          -236 -660 rlineto
-          102 236 rmoveto
-          293 0 rlineto
-          0 28 rlineto
-          -293 0 rlineto
-          0 -28 rlineto
-        </CharString>
-        <CharString name="T">
-          284 0 rmoveto
-          32 0 rlineto
-          0 632 rlineto
-          234 0 rlineto
-          0 28 rlineto
-          -500 0 rlineto
-          0 -28 rlineto
-          234 0 rlineto
-          0 -632 rlineto
-        </CharString>
-        <CharString name="dollar">
-          -107 245 7 rmoveto
-          -65 0 -39 15 -46 50 rrcurveto
-          36 -48 rlineto
-          -28 100 rlineto
-          -4 16 -12 4 -11 0 rrcurveto
-          -14 0 -8 -7 -1 -14 rrcurveto
-          24 -85 61 -51 107 0 rrcurveto
-          91 0 90 53 0 111 rrcurveto
-          0 70 -26 66 -134 57 rrcurveto
-          -19 8 rlineto
-          -93 39 -42 49 0 68 rrcurveto
-          0 91 60 48 88 0 rrcurveto
-          56 0 35 -14 44 -50 rrcurveto
-          -38 47 rlineto
-          28 -100 rlineto
-          6 -15 10 -5 11 0 rrcurveto
-          14 0 8 7 1 14 rrcurveto
-          -24 88 -67 48 -84 0 rrcurveto
-          -92 0 -82 -51 0 -108 rrcurveto
-          0 -80 45 -53 92 -42 rrcurveto
-          37 -17 rlineto
-          114 -52 26 -46 0 -65 rrcurveto
-          0 -92 -65 -54 -90 0 rrcurveto
-          18 327 rmoveto
-          0 428 rlineto
-          -22 0 rlineto
-          0 -428 rlineto
-          22 0 rlineto
-          -22 -449 rmoveto
-          22 0 rlineto
-          0 449 rlineto
-          -22 0 rlineto
-          0 -449 rlineto
-        </CharString>
-        <CharString name="dollar.a">
-          311 34 rmoveto
-          103 0 88 56 0 94 rrcurveto
-          0 184 -338 -32 0 142 rrcurveto
-          0 68 57 44 85 0 rrcurveto
-          76 0 34 -24 44 -38 rrcurveto
-          20 20 rlineto
-          -41 38 -45 32 -85 0 rrcurveto
-          -99 0 -78 -54 0 -88 rrcurveto
-          0 -166 338 28 0 -156 rrcurveto
-          0 -70 -56 -50 -103 0 rrcurveto
-          -85 0 -66 38 -40 34 rrcurveto
-          -18 -22 rlineto
-          45 -38 73 -40 91 0 rrcurveto
-          -70 -146 rmoveto
-          158 860 rlineto
-          -30 4 rlineto
-          -158 -860 rlineto
-          30 -4 rlineto
-        </CharString>
-      </CharStrings>
-    </CFFFont>
-
-    <GlobalSubrs>
-      <!-- The 'index' attribute is only for humans; it is ignored when parsed. -->
-    </GlobalSubrs>
-  </CFF2>
-
-  <BASE>
-    <Version value="0x00010000"/>
-    <HorizAxis>
-      <BaseTagList>
-        <!-- BaseTagCount=2 -->
-        <BaselineTag index="0" value="ideo"/>
-        <BaselineTag index="1" value="romn"/>
-      </BaseTagList>
-      <BaseScriptList>
-        <!-- BaseScriptCount=4 -->
-        <BaseScriptRecord index="0">
-          <BaseScriptTag value="DFLT"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="1"/>
-              <!-- BaseCoordCount=2 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-170"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="1">
-          <BaseScriptTag value="cyrl"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="1"/>
-              <!-- BaseCoordCount=2 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-170"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="2">
-          <BaseScriptTag value="grek"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="1"/>
-              <!-- BaseCoordCount=2 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-170"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="3">
-          <BaseScriptTag value="latn"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="1"/>
-              <!-- BaseCoordCount=2 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-170"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-      </BaseScriptList>
-    </HorizAxis>
-  </BASE>
-
-  <GPOS>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=1 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="size"/>
-        <Feature>
-          <FeatureParamsSize>
-            <DesignSize value="10.0"/>
-            <SubfamilyID value="0"/>
-            <SubfamilyNameID value="0"/>
-            <RangeStart value="0.0"/>
-            <RangeEnd value="0.0"/>
-          </FeatureParamsSize>
-          <!-- LookupCount=0 -->
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=0 -->
-    </LookupList>
-  </GPOS>
-
-  <GSUB>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=1 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="test"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="0"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=1 -->
-      <Lookup index="0">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="dollar" out="dollar.a"/>
-        </SingleSubst>
-      </Lookup>
-    </LookupList>
-  </GSUB>
-
-  <hmtx>
-    <mtx name=".notdef" width="600" lsb="84"/>
-    <mtx name="A" width="600" lsb="50"/>
-    <mtx name="T" width="600" lsb="50"/>
-    <mtx name="dollar" width="490" lsb="53"/>
-    <mtx name="dollar.a" width="600" lsb="102"/>
-  </hmtx>
-
-  <DSIG>
-    <!-- note that the Digital Signature will be invalid after recompilation! -->
-    <tableHeader flag="0x0" numSigs="0" version="1"/>
-  </DSIG>
-
-</ttFont>
diff --git a/Tests/varLib/data/master_cff2_input/TestCFF2_Regular.ttx b/Tests/varLib/data/master_cff2_input/TestCFF2_Regular.ttx
deleted file mode 100644
index 757e5b8..0000000
--- a/Tests/varLib/data/master_cff2_input/TestCFF2_Regular.ttx
+++ /dev/null
@@ -1,508 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="OTTO" ttLibVersion="4.2">
-
-  <GlyphOrder>
-    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="A"/>
-    <GlyphID id="2" name="T"/>
-    <GlyphID id="3" name="dollar.a"/>
-    <GlyphID id="4" name="dollar"/>
-  </GlyphOrder>
-
-  <head>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="1.0"/>
-    <fontRevision value="1.01"/>
-    <checkSumAdjustment value="0x60d07155"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00000011"/>
-    <unitsPerEm value="1000"/>
-    <created value="Thu Nov 29 14:52:09 2018"/>
-    <modified value="Thu Nov 29 14:52:09 2018"/>
-    <xMin value="31"/>
-    <yMin value="-115"/>
-    <xMax value="569"/>
-    <yMax value="751"/>
-    <macStyle value="00000000 00000000"/>
-    <lowestRecPPEM value="3"/>
-    <fontDirectionHint value="2"/>
-    <indexToLocFormat value="0"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="984"/>
-    <descent value="-273"/>
-    <lineGap value="0"/>
-    <advanceWidthMax value="600"/>
-    <minLeftSideBearing value="31"/>
-    <minRightSideBearing value="31"/>
-    <xMaxExtent value="569"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfHMetrics value="5"/>
-  </hhea>
-
-  <maxp>
-    <tableVersion value="0x5000"/>
-    <numGlyphs value="5"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="3"/>
-    <xAvgCharWidth value="579"/>
-    <usWeightClass value="400"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00000000"/>
-    <ySubscriptXSize value="650"/>
-    <ySubscriptYSize value="600"/>
-    <ySubscriptXOffset value="0"/>
-    <ySubscriptYOffset value="75"/>
-    <ySuperscriptXSize value="650"/>
-    <ySuperscriptYSize value="600"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="350"/>
-    <yStrikeoutSize value="50"/>
-    <yStrikeoutPosition value="291"/>
-    <sFamilyClass value="0"/>
-    <panose>
-      <bFamilyType value="2"/>
-      <bSerifStyle value="11"/>
-      <bWeight value="5"/>
-      <bProportion value="9"/>
-      <bContrast value="3"/>
-      <bStrokeVariation value="4"/>
-      <bArmStyle value="3"/>
-      <bLetterForm value="2"/>
-      <bMidline value="2"/>
-      <bXHeight value="4"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="ADBO"/>
-    <fsSelection value="00000000 01000000"/>
-    <usFirstCharIndex value="36"/>
-    <usLastCharIndex value="84"/>
-    <sTypoAscender value="750"/>
-    <sTypoDescender value="-250"/>
-    <sTypoLineGap value="0"/>
-    <usWinAscent value="984"/>
-    <usWinDescent value="273"/>
-    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
-    <sxHeight value="486"/>
-    <sCapHeight value="660"/>
-    <usDefaultChar value="0"/>
-    <usBreakChar value="32"/>
-    <usMaxContext value="1"/>
-  </OS_2>
-
-  <name>
-    <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Source Code Variable
-    </namerecord>
-    <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      1.010;ADBO;SourceCodeVariable-Roman
-    </namerecord>
-    <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Source Code Variable
-    </namerecord>
-    <namerecord nameID="5" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Version 1.010;hotconv 1.0.109;makeotfexe 2.5.65596
-    </namerecord>
-    <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      SourceCodeVariable-Roman
-    </namerecord>
-    <namerecord nameID="17" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Roman
-    </namerecord>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      Source Code Variable
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      1.010;ADBO;SourceCodeVariable-Roman
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      Source Code Variable
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version 1.010;hotconv 1.0.109;makeotfexe 2.5.65596
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      SourceCodeVariable-Roman
-    </namerecord>
-    <namerecord nameID="17" platformID="3" platEncID="1" langID="0x409">
-      Roman
-    </namerecord>
-  </name>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_4 platformID="0" platEncID="3" language="0">
-      <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x54" name="T"/><!-- LATIN CAPITAL LETTER T -->
-    </cmap_format_4>
-    <cmap_format_6 platformID="1" platEncID="0" language="0">
-      <map code="0x24" name="dollar"/>
-      <map code="0x41" name="A"/>
-      <map code="0x54" name="T"/>
-    </cmap_format_6>
-    <cmap_format_4 platformID="3" platEncID="1" language="0">
-      <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x54" name="T"/><!-- LATIN CAPITAL LETTER T -->
-    </cmap_format_4>
-  </cmap>
-
-  <post>
-    <formatType value="2.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-75"/>
-    <underlineThickness value="50"/>
-    <isFixedPitch value="1"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="0"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="0"/>
-    <psNames>
-      <!-- This file uses unique glyph names based on the information
-           found in the 'post' table. Since these names might not be unique,
-           we have to invent artificial names in case of clashes. In order to
-           be able to retain the original information, we need a name to
-           ps name mapping for those cases where they differ. That's what
-           you see below.
-            -->
-    </psNames>
-    <extraNames>
-      <!-- following are the name that are not taken from the standard Mac glyph order -->
-      <psName name="dollar.a"/>
-    </extraNames>
-  </post>
-
-  <CFF2>
-    <major value="2"/>
-    <minor value="0"/>
-    <CFFFont name="CFF2Font">
-      <FontMatrix value="0.001 0 0 0.001 0 0"/>
-      <FDArray>
-        <FontDict index="0">
-          <Private>
-            <BlueValues value="-12 0 486 498 574 586 638 650 656 668 712 724"/>
-            <OtherBlues value="-217 -205"/>
-            <BlueScale value="0.0625"/>
-            <BlueShift value="7"/>
-            <BlueFuzz value="0"/>
-            <StdHW value="67"/>
-            <StdVW value="85"/>
-          </Private>
-        </FontDict>
-      </FDArray>
-      <CharStrings>
-        <CharString name=".notdef">
-          62 0 rmoveto
-          476 0 rlineto
-          0 660 rlineto
-          -476 0 rlineto
-          0 -660 rlineto
-          109 59 rmoveto
-          73 131 rlineto
-          54 102 rlineto
-          4 0 rlineto
-          52 -102 rlineto
-          73 -131 rlineto
-          -256 0 rlineto
-          -44 52 rmoveto
-          0 461 rlineto
-          127 -232 rlineto
-          -127 -229 rlineto
-          171 277 rmoveto
-          -50 93 rlineto
-          -66 119 rlineto
-          234 0 rlineto
-          -65 -119 rlineto
-          -49 -93 rlineto
-          -4 0 rlineto
-          48 -48 rmoveto
-          126 232 rlineto
-          0 -461 rlineto
-          -126 229 rlineto
-        </CharString>
-        <CharString name="A">
-          31 0 rmoveto
-          86 0 rlineto
-          115 366 rlineto
-          23 73 21 72 21 76 rrcurveto
-          4 0 rlineto
-          20 -76 22 -72 23 -73 rrcurveto
-          113 -366 rlineto
-          90 0 rlineto
-          -221 656 rlineto
-          -96 0 rlineto
-          -221 -656 rlineto
-          117 199 rmoveto
-          301 0 rlineto
-          0 68 rlineto
-          -301 0 rlineto
-          0 -68 rlineto
-        </CharString>
-        <CharString name="T">
-          258 0 rmoveto
-          84 0 rlineto
-          0 585 rlineto
-          217 0 rlineto
-          0 71 rlineto
-          -518 0 rlineto
-          0 -71 rlineto
-          217 0 rlineto
-          0 -585 rlineto
-        </CharString>
-        <CharString name="dollar">
-          -107 248 35 rmoveto
-          -39 0 -45 5 -46 18 rrcurveto
-          53 -36 rlineto
-          -17 76 rlineto
-          -12 53 -22 13 -24 0 rrcurveto
-          -22 0 -14 -11 -9 -20 rrcurveto
-          4 -87 81 -59 107 0 rrcurveto
-          136 0 82 76 0 107 rrcurveto
-          0 82 -41 65 -135 47 rrcurveto
-          -38 13 rlineto
-          -71 23 -40 35 0 64 rrcurveto
-          0 75 57 37 74 0 rrcurveto
-          30 0 36 -5 42 -17 rrcurveto
-          -52 36 rlineto
-          17 -76 rlineto
-          12 -52 25 -14 22 0 rrcurveto
-          19 0 17 10 8 21 rrcurveto
-          -6 86 -80 60 -101 0 rrcurveto
-          -115 0 -83 -80 0 -102 rrcurveto
-          0 -100 62 -54 105 -37 rrcurveto
-          37 -13 rlineto
-          85 -30 36 -30 0 -63 rrcurveto
-          0 -74 -53 -42 -82 0 rrcurveto
-          31 287 rmoveto
-          0 428 rlineto
-          -40 0 rlineto
-          0 -428 rlineto
-          40 0 rlineto
-          -41 -437 rmoveto
-          40 0 rlineto
-          0 437 rlineto
-          -40 0 rlineto
-          0 -437 rlineto
-        </CharString>
-        <CharString name="dollar.a">
-          304 34 rmoveto
-          125 0 86 65 0 96 rrcurveto
-          0 183 -324 -21 0 110 rrcurveto
-          0 50 42 32 67 0 rrcurveto
-          68 0 36 -21 47 -36 rrcurveto
-          44 49 rlineto
-          -46 44 -54 33 -89 0 rrcurveto
-          -115 0 -81 -59 0 -94 rrcurveto
-          0 -174 324 22 0 -124 rrcurveto
-          0 -51 -42 -35 -78 0 rrcurveto
-          -76 0 -62 31 -52 37 rrcurveto
-          -39 -58 rlineto
-          52 -43 84 -36 83 0 rrcurveto
-          -51 -147 rmoveto
-          159 857 rlineto
-          -56 7 rlineto
-          -159 -858 rlineto
-          56 -6 rlineto
-        </CharString>
-      </CharStrings>
-    </CFFFont>
-
-    <GlobalSubrs>
-      <!-- The 'index' attribute is only for humans; it is ignored when parsed. -->
-    </GlobalSubrs>
-  </CFF2>
-
-  <BASE>
-    <Version value="0x00010000"/>
-    <HorizAxis>
-      <BaseTagList>
-        <!-- BaseTagCount=2 -->
-        <BaselineTag index="0" value="ideo"/>
-        <BaselineTag index="1" value="romn"/>
-      </BaseTagList>
-      <BaseScriptList>
-        <!-- BaseScriptCount=4 -->
-        <BaseScriptRecord index="0">
-          <BaseScriptTag value="DFLT"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="1"/>
-              <!-- BaseCoordCount=2 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-170"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="1">
-          <BaseScriptTag value="cyrl"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="1"/>
-              <!-- BaseCoordCount=2 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-170"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="2">
-          <BaseScriptTag value="grek"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="1"/>
-              <!-- BaseCoordCount=2 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-170"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="3">
-          <BaseScriptTag value="latn"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="1"/>
-              <!-- BaseCoordCount=2 -->
-              <BaseCoord index="0" Format="1">
-                <Coordinate value="-170"/>
-              </BaseCoord>
-              <BaseCoord index="1" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-      </BaseScriptList>
-    </HorizAxis>
-  </BASE>
-
-  <GPOS>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=1 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="size"/>
-        <Feature>
-          <FeatureParamsSize>
-            <DesignSize value="10.0"/>
-            <SubfamilyID value="0"/>
-            <SubfamilyNameID value="0"/>
-            <RangeStart value="0.0"/>
-            <RangeEnd value="0.0"/>
-          </FeatureParamsSize>
-          <!-- LookupCount=0 -->
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=0 -->
-    </LookupList>
-  </GPOS>
-
-  <GSUB>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=1 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="test"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="0"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=1 -->
-      <Lookup index="0">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="dollar" out="dollar.a"/>
-        </SingleSubst>
-      </Lookup>
-    </LookupList>
-  </GSUB>
-
-  <hmtx>
-    <mtx name=".notdef" width="600" lsb="62"/>
-    <mtx name="A" width="600" lsb="31"/>
-    <mtx name="T" width="600" lsb="41"/>
-    <mtx name="dollar" width="497" lsb="51"/>
-    <mtx name="dollar.a" width="600" lsb="85"/>
-  </hmtx>
-
-  <DSIG>
-    <!-- note that the Digital Signature will be invalid after recompilation! -->
-    <tableHeader flag="0x0" numSigs="0" version="1"/>
-  </DSIG>
-
-</ttFont>
diff --git a/Tests/varLib/data/master_incompatible_arrays/IncompatibleArrays-Bold.ttx b/Tests/varLib/data/master_incompatible_arrays/IncompatibleArrays-Bold.ttx
deleted file mode 100644
index c47ecba..0000000
--- a/Tests/varLib/data/master_incompatible_arrays/IncompatibleArrays-Bold.ttx
+++ /dev/null
@@ -1,612 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.20">
-
-  <GlyphOrder>
-    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="A"/>
-    <GlyphID id="2" name="Aacute"/>
-    <GlyphID id="3" name="O"/>
-    <GlyphID id="4" name="V"/>
-    <GlyphID id="5" name="space"/>
-    <GlyphID id="6" name="dollar"/>
-    <GlyphID id="7" name="dollar.bold"/>
-    <GlyphID id="8" name="acutecomb"/>
-    <GlyphID id="9" name="dollar.BRACKET.500"/>
-  </GlyphOrder>
-
-  <head>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="1.0"/>
-    <fontRevision value="1.0"/>
-    <checkSumAdjustment value="0x10cb3f3"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00000011"/>
-    <unitsPerEm value="1000"/>
-    <created value="Fri Jan 15 14:37:13 2021"/>
-    <modified value="Mon Mar 15 12:57:03 2021"/>
-    <xMin value="-141"/>
-    <yMin value="-200"/>
-    <xMax value="906"/>
-    <yMax value="949"/>
-    <macStyle value="00000000 00000001"/>
-    <lowestRecPPEM value="6"/>
-    <fontDirectionHint value="2"/>
-    <indexToLocFormat value="0"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="1000"/>
-    <descent value="-200"/>
-    <lineGap value="0"/>
-    <advanceWidthMax value="911"/>
-    <minLeftSideBearing value="-141"/>
-    <minRightSideBearing value="-125"/>
-    <xMaxExtent value="906"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfHMetrics value="10"/>
-  </hhea>
-
-  <maxp>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="0x10000"/>
-    <numGlyphs value="10"/>
-    <maxPoints value="52"/>
-    <maxContours value="3"/>
-    <maxCompositePoints value="16"/>
-    <maxCompositeContours value="4"/>
-    <maxZones value="1"/>
-    <maxTwilightPoints value="0"/>
-    <maxStorage value="0"/>
-    <maxFunctionDefs value="0"/>
-    <maxInstructionDefs value="0"/>
-    <maxStackElements value="0"/>
-    <maxSizeOfInstructions value="0"/>
-    <maxComponentElements value="2"/>
-    <maxComponentDepth value="1"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="4"/>
-    <xAvgCharWidth value="672"/>
-    <usWeightClass value="400"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00001000"/>
-    <ySubscriptXSize value="650"/>
-    <ySubscriptYSize value="600"/>
-    <ySubscriptXOffset value="0"/>
-    <ySubscriptYOffset value="75"/>
-    <ySuperscriptXSize value="650"/>
-    <ySuperscriptYSize value="600"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="350"/>
-    <yStrikeoutSize value="50"/>
-    <yStrikeoutPosition value="300"/>
-    <sFamilyClass value="0"/>
-    <panose>
-      <bFamilyType value="0"/>
-      <bSerifStyle value="0"/>
-      <bWeight value="0"/>
-      <bProportion value="0"/>
-      <bContrast value="0"/>
-      <bStrokeVariation value="0"/>
-      <bArmStyle value="0"/>
-      <bLetterForm value="0"/>
-      <bMidline value="0"/>
-      <bXHeight value="0"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00000000 01000011"/>
-    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="NONE"/>
-    <fsSelection value="00000000 00100000"/>
-    <usFirstCharIndex value="32"/>
-    <usLastCharIndex value="769"/>
-    <sTypoAscender value="800"/>
-    <sTypoDescender value="-200"/>
-    <sTypoLineGap value="200"/>
-    <usWinAscent value="1000"/>
-    <usWinDescent value="200"/>
-    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
-    <sxHeight value="500"/>
-    <sCapHeight value="700"/>
-    <usDefaultChar value="0"/>
-    <usBreakChar value="32"/>
-    <usMaxContext value="2"/>
-  </OS_2>
-
-  <hmtx>
-    <mtx name=".notdef" width="500" lsb="50"/>
-    <mtx name="A" width="911" lsb="5"/>
-    <mtx name="Aacute" width="911" lsb="5"/>
-    <mtx name="O" width="715" lsb="15"/>
-    <mtx name="V" width="911" lsb="5"/>
-    <mtx name="acutecomb" width="0" lsb="-141"/>
-    <mtx name="dollar" width="600" lsb="1"/>
-    <mtx name="dollar.BRACKET.500" width="600" lsb="1"/>
-    <mtx name="dollar.bold" width="600" lsb="1"/>
-    <mtx name="space" width="300" lsb="0"/>
-  </hmtx>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_4 platformID="0" platEncID="3" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x4f" name="O"/><!-- LATIN CAPITAL LETTER O -->
-      <map code="0x56" name="V"/><!-- LATIN CAPITAL LETTER V -->
-      <map code="0xc1" name="Aacute"/><!-- LATIN CAPITAL LETTER A WITH ACUTE -->
-      <map code="0x301" name="acutecomb"/><!-- COMBINING ACUTE ACCENT -->
-    </cmap_format_4>
-    <cmap_format_4 platformID="3" platEncID="1" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x4f" name="O"/><!-- LATIN CAPITAL LETTER O -->
-      <map code="0x56" name="V"/><!-- LATIN CAPITAL LETTER V -->
-      <map code="0xc1" name="Aacute"/><!-- LATIN CAPITAL LETTER A WITH ACUTE -->
-      <map code="0x301" name="acutecomb"/><!-- COMBINING ACUTE ACCENT -->
-    </cmap_format_4>
-  </cmap>
-
-  <loca>
-    <!-- The 'loca' table will be calculated by the compiler -->
-  </loca>
-
-  <glyf>
-
-    <!-- The xMin, yMin, xMax and yMax values
-         will be recalculated by the compiler. -->
-
-    <TTGlyph name=".notdef" xMin="50" yMin="-200" xMax="450" yMax="800">
-      <contour>
-        <pt x="50" y="-200" on="1"/>
-        <pt x="50" y="800" on="1"/>
-        <pt x="450" y="800" on="1"/>
-        <pt x="450" y="-200" on="1"/>
-      </contour>
-      <contour>
-        <pt x="100" y="-150" on="1"/>
-        <pt x="400" y="-150" on="1"/>
-        <pt x="400" y="750" on="1"/>
-        <pt x="100" y="750" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="A" xMin="5" yMin="0" xMax="906" yMax="700">
-      <contour>
-        <pt x="705" y="0" on="1"/>
-        <pt x="906" y="0" on="1"/>
-        <pt x="556" y="700" on="1"/>
-        <pt x="355" y="700" on="1"/>
-      </contour>
-      <contour>
-        <pt x="5" y="0" on="1"/>
-        <pt x="206" y="0" on="1"/>
-        <pt x="556" y="700" on="1"/>
-        <pt x="355" y="700" on="1"/>
-      </contour>
-      <contour>
-        <pt x="640" y="311" on="1"/>
-        <pt x="190" y="311" on="1"/>
-        <pt x="190" y="191" on="1"/>
-        <pt x="640" y="191" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="Aacute" xMin="5" yMin="0" xMax="906" yMax="949">
-      <component glyphName="A" x="0" y="0" flags="0x204"/>
-      <component glyphName="acutecomb" x="479" y="124" flags="0x4"/>
-    </TTGlyph>
-
-    <TTGlyph name="O" xMin="15" yMin="-10" xMax="670" yMax="710">
-      <contour>
-        <pt x="342" y="-10" on="1"/>
-        <pt x="172" y="-10" on="0"/>
-        <pt x="15" y="163" on="0"/>
-        <pt x="15" y="350" on="1"/>
-        <pt x="15" y="538" on="0"/>
-        <pt x="172" y="710" on="0"/>
-        <pt x="342" y="710" on="1"/>
-        <pt x="513" y="710" on="0"/>
-        <pt x="670" y="538" on="0"/>
-        <pt x="670" y="350" on="1"/>
-        <pt x="670" y="163" on="0"/>
-        <pt x="513" y="-10" on="0"/>
-      </contour>
-      <contour>
-        <pt x="342" y="153" on="1"/>
-        <pt x="419" y="153" on="0"/>
-        <pt x="490" y="247" on="0"/>
-        <pt x="490" y="350" on="1"/>
-        <pt x="490" y="453" on="0"/>
-        <pt x="419" y="547" on="0"/>
-        <pt x="342" y="547" on="1"/>
-        <pt x="266" y="547" on="0"/>
-        <pt x="195" y="453" on="0"/>
-        <pt x="195" y="350" on="1"/>
-        <pt x="195" y="247" on="0"/>
-        <pt x="266" y="153" on="0"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="V" xMin="5" yMin="0" xMax="906" yMax="700">
-      <contour>
-        <pt x="355" y="0" on="1"/>
-        <pt x="705" y="700" on="1"/>
-        <pt x="906" y="700" on="1"/>
-        <pt x="556" y="0" on="1"/>
-      </contour>
-      <contour>
-        <pt x="355" y="0" on="1"/>
-        <pt x="5" y="700" on="1"/>
-        <pt x="206" y="700" on="1"/>
-        <pt x="556" y="0" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="acutecomb" xMin="-141" yMin="630" xMax="125" yMax="825">
-      <contour>
-        <pt x="-118" y="756" on="1"/>
-        <pt x="-141" y="630" on="1"/>
-        <pt x="102" y="699" on="1"/>
-        <pt x="125" y="825" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="dollar" xMin="1" yMin="-98" xMax="595" yMax="789">
-      <contour>
-        <pt x="249" y="789" on="1"/>
-        <pt x="369" y="789" on="1"/>
-        <pt x="369" y="743" on="1"/>
-        <pt x="427" y="735" on="0"/>
-        <pt x="537" y="681" on="0"/>
-        <pt x="590" y="623" on="1"/>
-        <pt x="510" y="515" on="1"/>
-        <pt x="479" y="549" on="0"/>
-        <pt x="411" y="588" on="0"/>
-        <pt x="369" y="595" on="1"/>
-        <pt x="369" y="400" on="1"/>
-        <pt x="476" y="378" on="0"/>
-        <pt x="595" y="278" on="0"/>
-        <pt x="595" y="184" on="1"/>
-        <pt x="595" y="93" on="0"/>
-        <pt x="474" y="-32" on="0"/>
-        <pt x="369" y="-46" on="1"/>
-        <pt x="369" y="-98" on="1"/>
-        <pt x="249" y="-98" on="1"/>
-        <pt x="249" y="-47" on="1"/>
-        <pt x="176" y="-39" on="0"/>
-        <pt x="52" y="17" on="0"/>
-        <pt x="1" y="69" on="1"/>
-        <pt x="80" y="179" on="1"/>
-        <pt x="118" y="144" on="0"/>
-        <pt x="195" y="106" on="0"/>
-        <pt x="249" y="100" on="1"/>
-        <pt x="249" y="273" on="1"/>
-        <pt x="246" y="274" on="1"/>
-        <pt x="144" y="294" on="0"/>
-        <pt x="28" y="405" on="0"/>
-        <pt x="28" y="502" on="1"/>
-        <pt x="28" y="567" on="0"/>
-        <pt x="84" y="667" on="0"/>
-        <pt x="184" y="732" on="0"/>
-        <pt x="249" y="742" on="1"/>
-      </contour>
-      <contour>
-        <pt x="152" y="502" on="1"/>
-        <pt x="152" y="480" on="0"/>
-        <pt x="166" y="453" on="0"/>
-        <pt x="208" y="434" on="0"/>
-        <pt x="249" y="424" on="1"/>
-        <pt x="249" y="595" on="1"/>
-        <pt x="199" y="587" on="0"/>
-        <pt x="152" y="538" on="0"/>
-      </contour>
-      <contour>
-        <pt x="369" y="100" on="1"/>
-        <pt x="426" y="107" on="0"/>
-        <pt x="471" y="150" on="0"/>
-        <pt x="471" y="183" on="1"/>
-        <pt x="471" y="201" on="0"/>
-        <pt x="456" y="225" on="0"/>
-        <pt x="412" y="243" on="0"/>
-        <pt x="369" y="252" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="dollar.BRACKET.500" xMin="1" yMin="-98" xMax="595" yMax="789">
-      <contour>
-        <pt x="249" y="789" on="1"/>
-        <pt x="369" y="789" on="1"/>
-        <pt x="369" y="743" on="1"/>
-        <pt x="427" y="735" on="0"/>
-        <pt x="537" y="681" on="0"/>
-        <pt x="590" y="623" on="1"/>
-        <pt x="510" y="515" on="1"/>
-        <pt x="468" y="560" on="0"/>
-        <pt x="374" y="600" on="0"/>
-        <pt x="308" y="600" on="1"/>
-        <pt x="227" y="600" on="0"/>
-        <pt x="152" y="548" on="0"/>
-        <pt x="152" y="502" on="1"/>
-        <pt x="152" y="479" on="0"/>
-        <pt x="168" y="450" on="0"/>
-        <pt x="217" y="431" on="0"/>
-        <pt x="264" y="421" on="1"/>
-        <pt x="363" y="401" on="1"/>
-        <pt x="473" y="379" on="0"/>
-        <pt x="595" y="279" on="0"/>
-        <pt x="595" y="184" on="1"/>
-        <pt x="595" y="93" on="0"/>
-        <pt x="474" y="-32" on="0"/>
-        <pt x="369" y="-46" on="1"/>
-        <pt x="369" y="-98" on="1"/>
-        <pt x="249" y="-98" on="1"/>
-        <pt x="249" y="-47" on="1"/>
-        <pt x="176" y="-39" on="0"/>
-        <pt x="52" y="17" on="0"/>
-        <pt x="1" y="69" on="1"/>
-        <pt x="80" y="179" on="1"/>
-        <pt x="112" y="150" on="0"/>
-        <pt x="176" y="114" on="0"/>
-        <pt x="256" y="97" on="0"/>
-        <pt x="310" y="97" on="1"/>
-        <pt x="402" y="97" on="0"/>
-        <pt x="471" y="143" on="0"/>
-        <pt x="471" y="183" on="1"/>
-        <pt x="471" y="203" on="0"/>
-        <pt x="453" y="228" on="0"/>
-        <pt x="399" y="247" on="0"/>
-        <pt x="345" y="256" on="1"/>
-        <pt x="246" y="274" on="1"/>
-        <pt x="144" y="293" on="0"/>
-        <pt x="28" y="405" on="0"/>
-        <pt x="28" y="502" on="1"/>
-        <pt x="28" y="567" on="0"/>
-        <pt x="84" y="667" on="0"/>
-        <pt x="184" y="732" on="0"/>
-        <pt x="249" y="742" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="dollar.bold" xMin="1" yMin="-98" xMax="595" yMax="789">
-      <contour>
-        <pt x="249" y="789" on="1"/>
-        <pt x="369" y="789" on="1"/>
-        <pt x="369" y="743" on="1"/>
-        <pt x="427" y="735" on="0"/>
-        <pt x="537" y="681" on="0"/>
-        <pt x="590" y="623" on="1"/>
-        <pt x="510" y="515" on="1"/>
-        <pt x="468" y="560" on="0"/>
-        <pt x="374" y="600" on="0"/>
-        <pt x="308" y="600" on="1"/>
-        <pt x="227" y="600" on="0"/>
-        <pt x="152" y="548" on="0"/>
-        <pt x="152" y="502" on="1"/>
-        <pt x="152" y="479" on="0"/>
-        <pt x="168" y="450" on="0"/>
-        <pt x="217" y="431" on="0"/>
-        <pt x="264" y="421" on="1"/>
-        <pt x="363" y="401" on="1"/>
-        <pt x="473" y="379" on="0"/>
-        <pt x="595" y="279" on="0"/>
-        <pt x="595" y="184" on="1"/>
-        <pt x="595" y="93" on="0"/>
-        <pt x="474" y="-32" on="0"/>
-        <pt x="369" y="-46" on="1"/>
-        <pt x="369" y="-98" on="1"/>
-        <pt x="249" y="-98" on="1"/>
-        <pt x="249" y="-47" on="1"/>
-        <pt x="176" y="-39" on="0"/>
-        <pt x="52" y="17" on="0"/>
-        <pt x="1" y="69" on="1"/>
-        <pt x="80" y="179" on="1"/>
-        <pt x="112" y="150" on="0"/>
-        <pt x="176" y="114" on="0"/>
-        <pt x="256" y="97" on="0"/>
-        <pt x="310" y="97" on="1"/>
-        <pt x="402" y="97" on="0"/>
-        <pt x="471" y="143" on="0"/>
-        <pt x="471" y="183" on="1"/>
-        <pt x="471" y="203" on="0"/>
-        <pt x="453" y="228" on="0"/>
-        <pt x="399" y="247" on="0"/>
-        <pt x="345" y="256" on="1"/>
-        <pt x="246" y="274" on="1"/>
-        <pt x="144" y="293" on="0"/>
-        <pt x="28" y="405" on="0"/>
-        <pt x="28" y="502" on="1"/>
-        <pt x="28" y="567" on="0"/>
-        <pt x="84" y="667" on="0"/>
-        <pt x="184" y="732" on="0"/>
-        <pt x="249" y="742" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="space"/><!-- contains no outline data -->
-
-  </glyf>
-
-  <name>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      Simple Two Axis
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Bold
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      1.000;NONE;SimpleTwoAxis-Bold
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      Simple Two Axis Bold
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version 1.000
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      SimpleTwoAxis-Bold
-    </namerecord>
-  </name>
-
-  <post>
-    <formatType value="2.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-100"/>
-    <underlineThickness value="50"/>
-    <isFixedPitch value="0"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="0"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="0"/>
-    <psNames>
-      <!-- This file uses unique glyph names based on the information
-           found in the 'post' table. Since these names might not be unique,
-           we have to invent artificial names in case of clashes. In order to
-           be able to retain the original information, we need a name to
-           ps name mapping for those cases where they differ. That's what
-           you see below.
-            -->
-    </psNames>
-    <extraNames>
-      <!-- following are the name that are not taken from the standard Mac glyph order -->
-      <psName name="dollar.bold"/>
-      <psName name="acutecomb"/>
-      <psName name="dollar.BRACKET.500"/>
-    </extraNames>
-  </post>
-
-  <GDEF>
-    <Version value="0x00010000"/>
-    <GlyphClassDef>
-      <ClassDef glyph="A" class="1"/>
-      <ClassDef glyph="Aacute" class="1"/>
-      <ClassDef glyph="acutecomb" class="3"/>
-    </GlyphClassDef>
-  </GDEF>
-  <GPOS>
-    <Version value="0x00010000"/>
-    <ScriptList>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=2 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="kern"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="0"/>
-        </Feature>
-      </FeatureRecord>
-      <FeatureRecord index="1">
-        <FeatureTag value="mark"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="1"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=2 -->
-      <Lookup index="0">
-        <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
-        <!-- SubTableCount=1 -->
-        <PairPos index="0" Format="1">
-          <Coverage>
-            <Glyph value="A"/>
-            <Glyph value="Aacute"/>
-            <Glyph value="V"/>
-          </Coverage>
-          <ValueFormat1 value="4"/>
-          <ValueFormat2 value="0"/>
-          <!-- PairSetCount=3 -->
-          <PairSet index="0">
-            <!-- PairValueCount=1 -->
-            <PairValueRecord index="0">
-              <SecondGlyph value="V"/>
-              <Value1 XAdvance="-80"/>
-            </PairValueRecord>
-          </PairSet>
-          <PairSet index="1">
-            <!-- PairValueCount=1 -->
-            <PairValueRecord index="0">
-              <SecondGlyph value="V"/>
-              <Value1 XAdvance="-80"/>
-            </PairValueRecord>
-          </PairSet>
-          <PairSet index="2">
-            <!-- PairValueCount=1 -->
-            <PairValueRecord index="0">
-              <SecondGlyph value="O"/>
-              <Value1 XAdvance="-20"/>
-            </PairValueRecord>
-          </PairSet>
-        </PairPos>
-      </Lookup>
-      <Lookup index="1">
-        <LookupType value="4"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <MarkBasePos index="0" Format="1">
-          <MarkCoverage>
-            <Glyph value="acutecomb"/>
-          </MarkCoverage>
-          <BaseCoverage>
-            <Glyph value="A"/>
-            <Glyph value="Aacute"/>
-          </BaseCoverage>
-          <!-- ClassCount=1 -->
-          <MarkArray>
-            <!-- MarkCount=1 -->
-            <MarkRecord index="0">
-              <Class value="0"/>
-              <MarkAnchor Format="1">
-                <XCoordinate value="4"/>
-                <YCoordinate value="623"/>
-              </MarkAnchor>
-            </MarkRecord>
-          </MarkArray>
-          <BaseArray>
-            <!-- BaseCount=2 -->
-            <BaseRecord index="0">
-              <BaseAnchor index="0" Format="1">
-                <XCoordinate value="406"/>
-                <YCoordinate value="753"/>
-              </BaseAnchor>
-            </BaseRecord>
-            <BaseRecord index="1">
-              <BaseAnchor index="0" Format="1">
-                <XCoordinate value="406"/>
-                <YCoordinate value="753"/>
-              </BaseAnchor>
-            </BaseRecord>
-          </BaseArray>
-        </MarkBasePos>
-      </Lookup>
-    </LookupList>
-  </GPOS>
-
-</ttFont>
diff --git a/Tests/varLib/data/master_incompatible_arrays/IncompatibleArrays-Regular.ttx b/Tests/varLib/data/master_incompatible_arrays/IncompatibleArrays-Regular.ttx
deleted file mode 100644
index cabb69a..0000000
--- a/Tests/varLib/data/master_incompatible_arrays/IncompatibleArrays-Regular.ttx
+++ /dev/null
@@ -1,626 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.20">
-
-  <GlyphOrder>
-    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="A"/>
-    <GlyphID id="2" name="Aacute"/>
-    <GlyphID id="3" name="O"/>
-    <GlyphID id="4" name="V"/>
-    <GlyphID id="5" name="space"/>
-    <GlyphID id="6" name="dollar"/>
-    <GlyphID id="7" name="dollar.bold"/>
-    <GlyphID id="8" name="acutecomb"/>
-    <GlyphID id="9" name="dollar.BRACKET.500"/>
-  </GlyphOrder>
-
-  <head>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="1.0"/>
-    <fontRevision value="1.0"/>
-    <checkSumAdjustment value="0x3c7bc79b"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00000011"/>
-    <unitsPerEm value="1000"/>
-    <created value="Fri Jan 15 14:37:13 2021"/>
-    <modified value="Mon Mar 15 12:57:03 2021"/>
-    <xMin value="-141"/>
-    <yMin value="-200"/>
-    <xMax value="751"/>
-    <yMax value="915"/>
-    <macStyle value="00000000 00000000"/>
-    <lowestRecPPEM value="6"/>
-    <fontDirectionHint value="2"/>
-    <indexToLocFormat value="0"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="1000"/>
-    <descent value="-200"/>
-    <lineGap value="0"/>
-    <advanceWidthMax value="756"/>
-    <minLeftSideBearing value="-141"/>
-    <minRightSideBearing value="-125"/>
-    <xMaxExtent value="751"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfHMetrics value="10"/>
-  </hhea>
-
-  <maxp>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="0x10000"/>
-    <numGlyphs value="10"/>
-    <maxPoints value="52"/>
-    <maxContours value="3"/>
-    <maxCompositePoints value="16"/>
-    <maxCompositeContours value="4"/>
-    <maxZones value="1"/>
-    <maxTwilightPoints value="0"/>
-    <maxStorage value="0"/>
-    <maxFunctionDefs value="0"/>
-    <maxInstructionDefs value="0"/>
-    <maxStackElements value="0"/>
-    <maxSizeOfInstructions value="0"/>
-    <maxComponentElements value="2"/>
-    <maxComponentDepth value="1"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="4"/>
-    <xAvgCharWidth value="604"/>
-    <usWeightClass value="400"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00001000"/>
-    <ySubscriptXSize value="650"/>
-    <ySubscriptYSize value="600"/>
-    <ySubscriptXOffset value="0"/>
-    <ySubscriptYOffset value="75"/>
-    <ySuperscriptXSize value="650"/>
-    <ySuperscriptYSize value="600"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="350"/>
-    <yStrikeoutSize value="50"/>
-    <yStrikeoutPosition value="300"/>
-    <sFamilyClass value="0"/>
-    <panose>
-      <bFamilyType value="0"/>
-      <bSerifStyle value="0"/>
-      <bWeight value="0"/>
-      <bProportion value="0"/>
-      <bContrast value="0"/>
-      <bStrokeVariation value="0"/>
-      <bArmStyle value="0"/>
-      <bLetterForm value="0"/>
-      <bMidline value="0"/>
-      <bXHeight value="0"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00000000 01000011"/>
-    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="NONE"/>
-    <fsSelection value="00000000 01000000"/>
-    <usFirstCharIndex value="32"/>
-    <usLastCharIndex value="769"/>
-    <sTypoAscender value="800"/>
-    <sTypoDescender value="-200"/>
-    <sTypoLineGap value="200"/>
-    <usWinAscent value="1000"/>
-    <usWinDescent value="200"/>
-    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
-    <sxHeight value="500"/>
-    <sCapHeight value="700"/>
-    <usDefaultChar value="0"/>
-    <usBreakChar value="32"/>
-    <usMaxContext value="2"/>
-  </OS_2>
-
-  <hmtx>
-    <mtx name=".notdef" width="500" lsb="50"/>
-    <mtx name="A" width="756" lsb="5"/>
-    <mtx name="Aacute" width="756" lsb="5"/>
-    <mtx name="O" width="664" lsb="30"/>
-    <mtx name="V" width="756" lsb="5"/>
-    <mtx name="acutecomb" width="0" lsb="-141"/>
-    <mtx name="dollar" width="600" lsb="29"/>
-    <mtx name="dollar.BRACKET.500" width="600" lsb="29"/>
-    <mtx name="dollar.bold" width="600" lsb="29"/>
-    <mtx name="space" width="200" lsb="0"/>
-  </hmtx>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_4 platformID="0" platEncID="3" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x4f" name="O"/><!-- LATIN CAPITAL LETTER O -->
-      <map code="0x56" name="V"/><!-- LATIN CAPITAL LETTER V -->
-      <map code="0xc1" name="Aacute"/><!-- LATIN CAPITAL LETTER A WITH ACUTE -->
-      <map code="0x301" name="acutecomb"/><!-- COMBINING ACUTE ACCENT -->
-    </cmap_format_4>
-    <cmap_format_4 platformID="3" platEncID="1" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x4f" name="O"/><!-- LATIN CAPITAL LETTER O -->
-      <map code="0x56" name="V"/><!-- LATIN CAPITAL LETTER V -->
-      <map code="0xc1" name="Aacute"/><!-- LATIN CAPITAL LETTER A WITH ACUTE -->
-      <map code="0x301" name="acutecomb"/><!-- COMBINING ACUTE ACCENT -->
-    </cmap_format_4>
-  </cmap>
-
-  <loca>
-    <!-- The 'loca' table will be calculated by the compiler -->
-  </loca>
-
-  <glyf>
-
-    <!-- The xMin, yMin, xMax and yMax values
-         will be recalculated by the compiler. -->
-
-    <TTGlyph name=".notdef" xMin="50" yMin="-200" xMax="450" yMax="800">
-      <contour>
-        <pt x="50" y="-200" on="1"/>
-        <pt x="50" y="800" on="1"/>
-        <pt x="450" y="800" on="1"/>
-        <pt x="450" y="-200" on="1"/>
-      </contour>
-      <contour>
-        <pt x="100" y="-150" on="1"/>
-        <pt x="400" y="-150" on="1"/>
-        <pt x="400" y="750" on="1"/>
-        <pt x="100" y="750" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="A" xMin="5" yMin="0" xMax="751" yMax="700">
-      <contour>
-        <pt x="641" y="0" on="1"/>
-        <pt x="751" y="0" on="1"/>
-        <pt x="433" y="700" on="1"/>
-        <pt x="323" y="700" on="1"/>
-      </contour>
-      <contour>
-        <pt x="5" y="0" on="1"/>
-        <pt x="115" y="0" on="1"/>
-        <pt x="433" y="700" on="1"/>
-        <pt x="323" y="700" on="1"/>
-      </contour>
-      <contour>
-        <pt x="567" y="284" on="1"/>
-        <pt x="152" y="284" on="1"/>
-        <pt x="152" y="204" on="1"/>
-        <pt x="567" y="204" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="Aacute" xMin="5" yMin="0" xMax="751" yMax="915">
-      <component glyphName="A" x="0" y="0" flags="0x204"/>
-      <component glyphName="acutecomb" x="402" y="130" flags="0x4"/>
-    </TTGlyph>
-
-    <TTGlyph name="O" xMin="30" yMin="-10" xMax="634" yMax="710">
-      <contour>
-        <pt x="332" y="-10" on="1"/>
-        <pt x="181" y="-10" on="0"/>
-        <pt x="30" y="169" on="0"/>
-        <pt x="30" y="350" on="1"/>
-        <pt x="30" y="531" on="0"/>
-        <pt x="181" y="710" on="0"/>
-        <pt x="332" y="710" on="1"/>
-        <pt x="484" y="710" on="0"/>
-        <pt x="634" y="531" on="0"/>
-        <pt x="634" y="350" on="1"/>
-        <pt x="634" y="169" on="0"/>
-        <pt x="484" y="-10" on="0"/>
-      </contour>
-      <contour>
-        <pt x="332" y="74" on="1"/>
-        <pt x="438" y="74" on="0"/>
-        <pt x="544" y="212" on="0"/>
-        <pt x="544" y="350" on="1"/>
-        <pt x="544" y="488" on="0"/>
-        <pt x="438" y="626" on="0"/>
-        <pt x="332" y="626" on="1"/>
-        <pt x="226" y="626" on="0"/>
-        <pt x="120" y="488" on="0"/>
-        <pt x="120" y="350" on="1"/>
-        <pt x="120" y="212" on="0"/>
-        <pt x="226" y="74" on="0"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="V" xMin="5" yMin="0" xMax="751" yMax="700">
-      <contour>
-        <pt x="323" y="0" on="1"/>
-        <pt x="641" y="700" on="1"/>
-        <pt x="751" y="700" on="1"/>
-        <pt x="433" y="0" on="1"/>
-      </contour>
-      <contour>
-        <pt x="323" y="0" on="1"/>
-        <pt x="5" y="700" on="1"/>
-        <pt x="115" y="700" on="1"/>
-        <pt x="433" y="0" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="acutecomb" xMin="-141" yMin="630" xMax="125" yMax="785">
-      <contour>
-        <pt x="-118" y="716" on="1"/>
-        <pt x="-141" y="630" on="1"/>
-        <pt x="102" y="699" on="1"/>
-        <pt x="125" y="785" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="dollar" xMin="29" yMin="-68" xMax="580" yMax="759">
-      <contour>
-        <pt x="264" y="759" on="1"/>
-        <pt x="354" y="759" on="1"/>
-        <pt x="354" y="715" on="1"/>
-        <pt x="415" y="709" on="0"/>
-        <pt x="519" y="662" on="0"/>
-        <pt x="562" y="620" on="1"/>
-        <pt x="509" y="548" on="1"/>
-        <pt x="473" y="584" on="0"/>
-        <pt x="398" y="621" on="0"/>
-        <pt x="354" y="627" on="1"/>
-        <pt x="354" y="373" on="1"/>
-        <pt x="467" y="351" on="0"/>
-        <pt x="580" y="263" on="0"/>
-        <pt x="580" y="184" on="1"/>
-        <pt x="580" y="102" on="0"/>
-        <pt x="459" y="-8" on="0"/>
-        <pt x="354" y="-18" on="1"/>
-        <pt x="354" y="-68" on="1"/>
-        <pt x="264" y="-68" on="1"/>
-        <pt x="264" y="-18" on="1"/>
-        <pt x="192" y="-12" on="0"/>
-        <pt x="72" y="34" on="0"/>
-        <pt x="29" y="74" on="1"/>
-        <pt x="81" y="146" on="1"/>
-        <pt x="123" y="110" on="0"/>
-        <pt x="207" y="73" on="0"/>
-        <pt x="264" y="69" on="1"/>
-        <pt x="264" y="301" on="1"/>
-        <pt x="249" y="304" on="1"/>
-        <pt x="148" y="323" on="0"/>
-        <pt x="43" y="420" on="0"/>
-        <pt x="43" y="502" on="1"/>
-        <pt x="43" y="559" on="0"/>
-        <pt x="99" y="650" on="0"/>
-        <pt x="199" y="707" on="0"/>
-        <pt x="264" y="715" on="1"/>
-      </contour>
-      <contour>
-        <pt x="137" y="502" on="1"/>
-        <pt x="137" y="470" on="0"/>
-        <pt x="160" y="428" on="0"/>
-        <pt x="214" y="402" on="0"/>
-        <pt x="261" y="392" on="1"/>
-        <pt x="264" y="627" on="1"/>
-        <pt x="203" y="618" on="0"/>
-        <pt x="137" y="553" on="0"/>
-      </contour>
-      <contour>
-        <pt x="354" y="69" on="1"/>
-        <pt x="423" y="76" on="0"/>
-        <pt x="486" y="135" on="0"/>
-        <pt x="486" y="183" on="1"/>
-        <pt x="486" y="211" on="0"/>
-        <pt x="462" y="250" on="0"/>
-        <pt x="405" y="275" on="0"/>
-        <pt x="354" y="285" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="dollar.BRACKET.500" xMin="29" yMin="-76" xMax="580" yMax="759">
-      <contour>
-        <pt x="264" y="759" on="1"/>
-        <pt x="354" y="759" on="1"/>
-        <pt x="354" y="715" on="1"/>
-        <pt x="415" y="709" on="0"/>
-        <pt x="519" y="662" on="0"/>
-        <pt x="562" y="620" on="1"/>
-        <pt x="509" y="548" on="1"/>
-        <pt x="464" y="592" on="0"/>
-        <pt x="370" y="630" on="0"/>
-        <pt x="308" y="630" on="1"/>
-        <pt x="226" y="630" on="0"/>
-        <pt x="137" y="562" on="0"/>
-        <pt x="137" y="502" on="1"/>
-        <pt x="137" y="470" on="0"/>
-        <pt x="160" y="428" on="0"/>
-        <pt x="214" y="402" on="0"/>
-        <pt x="261" y="392" on="1"/>
-        <pt x="360" y="372" on="1"/>
-        <pt x="469" y="350" on="0"/>
-        <pt x="580" y="263" on="0"/>
-        <pt x="580" y="184" on="1"/>
-        <pt x="580" y="102" on="0"/>
-        <pt x="459" y="-8" on="0"/>
-        <pt x="354" y="-18" on="1"/>
-        <pt x="354" y="-76" on="1"/>
-        <pt x="264" y="-76" on="1"/>
-        <pt x="264" y="-18" on="1"/>
-        <pt x="192" y="-12" on="0"/>
-        <pt x="72" y="34" on="0"/>
-        <pt x="29" y="74" on="1"/>
-        <pt x="81" y="146" on="1"/>
-        <pt x="115" y="118" on="0"/>
-        <pt x="180" y="83" on="0"/>
-        <pt x="259" y="67" on="0"/>
-        <pt x="310" y="67" on="1"/>
-        <pt x="403" y="67" on="0"/>
-        <pt x="486" y="128" on="0"/>
-        <pt x="486" y="183" on="1"/>
-        <pt x="486" y="212" on="0"/>
-        <pt x="461" y="251" on="0"/>
-        <pt x="401" y="277" on="0"/>
-        <pt x="348" y="286" on="1"/>
-        <pt x="249" y="304" on="1"/>
-        <pt x="148" y="323" on="0"/>
-        <pt x="43" y="420" on="0"/>
-        <pt x="43" y="502" on="1"/>
-        <pt x="43" y="559" on="0"/>
-        <pt x="99" y="650" on="0"/>
-        <pt x="199" y="707" on="0"/>
-        <pt x="264" y="715" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="dollar.bold" xMin="29" yMin="-76" xMax="580" yMax="759">
-      <contour>
-        <pt x="264" y="759" on="1"/>
-        <pt x="354" y="759" on="1"/>
-        <pt x="354" y="715" on="1"/>
-        <pt x="415" y="709" on="0"/>
-        <pt x="519" y="662" on="0"/>
-        <pt x="562" y="620" on="1"/>
-        <pt x="509" y="548" on="1"/>
-        <pt x="464" y="592" on="0"/>
-        <pt x="370" y="630" on="0"/>
-        <pt x="308" y="630" on="1"/>
-        <pt x="226" y="630" on="0"/>
-        <pt x="137" y="562" on="0"/>
-        <pt x="137" y="502" on="1"/>
-        <pt x="137" y="470" on="0"/>
-        <pt x="160" y="428" on="0"/>
-        <pt x="214" y="402" on="0"/>
-        <pt x="261" y="392" on="1"/>
-        <pt x="360" y="372" on="1"/>
-        <pt x="469" y="350" on="0"/>
-        <pt x="580" y="263" on="0"/>
-        <pt x="580" y="184" on="1"/>
-        <pt x="580" y="102" on="0"/>
-        <pt x="459" y="-8" on="0"/>
-        <pt x="354" y="-18" on="1"/>
-        <pt x="354" y="-76" on="1"/>
-        <pt x="264" y="-76" on="1"/>
-        <pt x="264" y="-18" on="1"/>
-        <pt x="192" y="-12" on="0"/>
-        <pt x="72" y="34" on="0"/>
-        <pt x="29" y="74" on="1"/>
-        <pt x="81" y="146" on="1"/>
-        <pt x="115" y="118" on="0"/>
-        <pt x="180" y="83" on="0"/>
-        <pt x="259" y="67" on="0"/>
-        <pt x="310" y="67" on="1"/>
-        <pt x="403" y="67" on="0"/>
-        <pt x="486" y="128" on="0"/>
-        <pt x="486" y="183" on="1"/>
-        <pt x="486" y="212" on="0"/>
-        <pt x="461" y="251" on="0"/>
-        <pt x="401" y="277" on="0"/>
-        <pt x="348" y="286" on="1"/>
-        <pt x="249" y="304" on="1"/>
-        <pt x="148" y="323" on="0"/>
-        <pt x="43" y="420" on="0"/>
-        <pt x="43" y="502" on="1"/>
-        <pt x="43" y="559" on="0"/>
-        <pt x="99" y="650" on="0"/>
-        <pt x="199" y="707" on="0"/>
-        <pt x="264" y="715" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="space"/><!-- contains no outline data -->
-
-  </glyf>
-
-  <name>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      Simple Two Axis
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      1.000;NONE;SimpleTwoAxis-Regular
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      Simple Two Axis Regular
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version 1.000
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      SimpleTwoAxis-Regular
-    </namerecord>
-  </name>
-
-  <post>
-    <formatType value="2.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-100"/>
-    <underlineThickness value="50"/>
-    <isFixedPitch value="0"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="0"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="0"/>
-    <psNames>
-      <!-- This file uses unique glyph names based on the information
-           found in the 'post' table. Since these names might not be unique,
-           we have to invent artificial names in case of clashes. In order to
-           be able to retain the original information, we need a name to
-           ps name mapping for those cases where they differ. That's what
-           you see below.
-            -->
-    </psNames>
-    <extraNames>
-      <!-- following are the name that are not taken from the standard Mac glyph order -->
-      <psName name="dollar.bold"/>
-      <psName name="acutecomb"/>
-      <psName name="dollar.BRACKET.500"/>
-    </extraNames>
-  </post>
-
-  <GDEF>
-    <Version value="0x00010000"/>
-    <GlyphClassDef>
-      <ClassDef glyph="A" class="1"/>
-      <ClassDef glyph="Aacute" class="1"/>
-      <ClassDef glyph="acutecomb" class="3"/>
-    </GlyphClassDef>
-  </GDEF>
-
-  <GPOS>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=2 -->
-            <FeatureIndex index="0" value="0"/>
-            <FeatureIndex index="1" value="1"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=2 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="kern"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="0"/>
-        </Feature>
-      </FeatureRecord>
-      <FeatureRecord index="1">
-        <FeatureTag value="mark"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="1"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=2 -->
-      <Lookup index="0">
-        <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
-        <!-- SubTableCount=1 -->
-        <PairPos index="0" Format="1">
-          <Coverage>
-            <Glyph value="A"/>
-            <Glyph value="Aacute"/>
-            <Glyph value="V"/>
-          </Coverage>
-          <ValueFormat1 value="4"/>
-          <ValueFormat2 value="0"/>
-          <!-- PairSetCount=3 -->
-          <PairSet index="0">
-            <!-- PairValueCount=1 -->
-            <PairValueRecord index="0">
-              <SecondGlyph value="V"/>
-              <Value1 XAdvance="-80"/>
-            </PairValueRecord>
-          </PairSet>
-          <PairSet index="1">
-            <!-- PairValueCount=1 -->
-            <PairValueRecord index="0">
-              <SecondGlyph value="V"/>
-              <Value1 XAdvance="-80"/>
-            </PairValueRecord>
-          </PairSet>
-          <PairSet index="2">
-            <!-- PairValueCount=1 -->
-            <PairValueRecord index="0">
-              <SecondGlyph value="O"/>
-              <Value1 XAdvance="-20"/>
-            </PairValueRecord>
-          </PairSet>
-        </PairPos>
-      </Lookup>
-      <Lookup index="1">
-        <LookupType value="4"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <MarkBasePos index="0" Format="1">
-          <MarkCoverage>
-            <Glyph value="acutecomb"/>
-          </MarkCoverage>
-          <BaseCoverage>
-            <Glyph value="A"/>
-            <Glyph value="Aacute"/>
-          </BaseCoverage>
-          <!-- ClassCount=1 -->
-          <MarkArray>
-            <!-- MarkCount=1 -->
-            <MarkRecord index="0">
-              <Class value="0"/>
-              <MarkAnchor Format="1">
-                <XCoordinate value="4"/>
-                <YCoordinate value="623"/>
-              </MarkAnchor>
-            </MarkRecord>
-          </MarkArray>
-          <BaseArray>
-            <!-- BaseCount=2 -->
-            <BaseRecord index="0">
-              <BaseAnchor index="0" Format="1">
-                <XCoordinate value="406"/>
-                <YCoordinate value="753"/>
-              </BaseAnchor>
-            </BaseRecord>
-            <BaseRecord index="1">
-              <BaseAnchor index="0" Format="1">
-                <XCoordinate value="406"/>
-                <YCoordinate value="753"/>
-              </BaseAnchor>
-            </BaseRecord>
-          </BaseArray>
-        </MarkBasePos>
-      </Lookup>
-    </LookupList>
-  </GPOS>
-
-</ttFont>
diff --git a/Tests/varLib/data/master_incompatible_features/IncompatibleFeatures-Bold.ttx b/Tests/varLib/data/master_incompatible_features/IncompatibleFeatures-Bold.ttx
deleted file mode 100644
index 18aee9f..0000000
--- a/Tests/varLib/data/master_incompatible_features/IncompatibleFeatures-Bold.ttx
+++ /dev/null
@@ -1,578 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.20">
-
-  <GlyphOrder>
-    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="A"/>
-    <GlyphID id="2" name="Aacute"/>
-    <GlyphID id="3" name="O"/>
-    <GlyphID id="4" name="V"/>
-    <GlyphID id="5" name="space"/>
-    <GlyphID id="6" name="dollar"/>
-    <GlyphID id="7" name="dollar.bold"/>
-    <GlyphID id="8" name="acutecomb"/>
-    <GlyphID id="9" name="dollar.BRACKET.500"/>
-  </GlyphOrder>
-
-  <head>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="1.0"/>
-    <fontRevision value="1.0"/>
-    <checkSumAdjustment value="0x10cb3f3"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00000011"/>
-    <unitsPerEm value="1000"/>
-    <created value="Fri Jan 15 14:37:13 2021"/>
-    <modified value="Mon Mar 15 12:57:03 2021"/>
-    <xMin value="-141"/>
-    <yMin value="-200"/>
-    <xMax value="906"/>
-    <yMax value="949"/>
-    <macStyle value="00000000 00000001"/>
-    <lowestRecPPEM value="6"/>
-    <fontDirectionHint value="2"/>
-    <indexToLocFormat value="0"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="1000"/>
-    <descent value="-200"/>
-    <lineGap value="0"/>
-    <advanceWidthMax value="911"/>
-    <minLeftSideBearing value="-141"/>
-    <minRightSideBearing value="-125"/>
-    <xMaxExtent value="906"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfHMetrics value="10"/>
-  </hhea>
-
-  <maxp>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="0x10000"/>
-    <numGlyphs value="10"/>
-    <maxPoints value="52"/>
-    <maxContours value="3"/>
-    <maxCompositePoints value="16"/>
-    <maxCompositeContours value="4"/>
-    <maxZones value="1"/>
-    <maxTwilightPoints value="0"/>
-    <maxStorage value="0"/>
-    <maxFunctionDefs value="0"/>
-    <maxInstructionDefs value="0"/>
-    <maxStackElements value="0"/>
-    <maxSizeOfInstructions value="0"/>
-    <maxComponentElements value="2"/>
-    <maxComponentDepth value="1"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="4"/>
-    <xAvgCharWidth value="672"/>
-    <usWeightClass value="400"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00001000"/>
-    <ySubscriptXSize value="650"/>
-    <ySubscriptYSize value="600"/>
-    <ySubscriptXOffset value="0"/>
-    <ySubscriptYOffset value="75"/>
-    <ySuperscriptXSize value="650"/>
-    <ySuperscriptYSize value="600"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="350"/>
-    <yStrikeoutSize value="50"/>
-    <yStrikeoutPosition value="300"/>
-    <sFamilyClass value="0"/>
-    <panose>
-      <bFamilyType value="0"/>
-      <bSerifStyle value="0"/>
-      <bWeight value="0"/>
-      <bProportion value="0"/>
-      <bContrast value="0"/>
-      <bStrokeVariation value="0"/>
-      <bArmStyle value="0"/>
-      <bLetterForm value="0"/>
-      <bMidline value="0"/>
-      <bXHeight value="0"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00000000 01000011"/>
-    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="NONE"/>
-    <fsSelection value="00000000 00100000"/>
-    <usFirstCharIndex value="32"/>
-    <usLastCharIndex value="769"/>
-    <sTypoAscender value="800"/>
-    <sTypoDescender value="-200"/>
-    <sTypoLineGap value="200"/>
-    <usWinAscent value="1000"/>
-    <usWinDescent value="200"/>
-    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
-    <sxHeight value="500"/>
-    <sCapHeight value="700"/>
-    <usDefaultChar value="0"/>
-    <usBreakChar value="32"/>
-    <usMaxContext value="2"/>
-  </OS_2>
-
-  <hmtx>
-    <mtx name=".notdef" width="500" lsb="50"/>
-    <mtx name="A" width="911" lsb="5"/>
-    <mtx name="Aacute" width="911" lsb="5"/>
-    <mtx name="O" width="715" lsb="15"/>
-    <mtx name="V" width="911" lsb="5"/>
-    <mtx name="acutecomb" width="0" lsb="-141"/>
-    <mtx name="dollar" width="600" lsb="1"/>
-    <mtx name="dollar.BRACKET.500" width="600" lsb="1"/>
-    <mtx name="dollar.bold" width="600" lsb="1"/>
-    <mtx name="space" width="300" lsb="0"/>
-  </hmtx>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_4 platformID="0" platEncID="3" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x4f" name="O"/><!-- LATIN CAPITAL LETTER O -->
-      <map code="0x56" name="V"/><!-- LATIN CAPITAL LETTER V -->
-      <map code="0xc1" name="Aacute"/><!-- LATIN CAPITAL LETTER A WITH ACUTE -->
-      <map code="0x301" name="acutecomb"/><!-- COMBINING ACUTE ACCENT -->
-    </cmap_format_4>
-    <cmap_format_4 platformID="3" platEncID="1" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x4f" name="O"/><!-- LATIN CAPITAL LETTER O -->
-      <map code="0x56" name="V"/><!-- LATIN CAPITAL LETTER V -->
-      <map code="0xc1" name="Aacute"/><!-- LATIN CAPITAL LETTER A WITH ACUTE -->
-      <map code="0x301" name="acutecomb"/><!-- COMBINING ACUTE ACCENT -->
-    </cmap_format_4>
-  </cmap>
-
-  <loca>
-    <!-- The 'loca' table will be calculated by the compiler -->
-  </loca>
-
-  <glyf>
-
-    <!-- The xMin, yMin, xMax and yMax values
-         will be recalculated by the compiler. -->
-
-    <TTGlyph name=".notdef" xMin="50" yMin="-200" xMax="450" yMax="800">
-      <contour>
-        <pt x="50" y="-200" on="1"/>
-        <pt x="50" y="800" on="1"/>
-        <pt x="450" y="800" on="1"/>
-        <pt x="450" y="-200" on="1"/>
-      </contour>
-      <contour>
-        <pt x="100" y="-150" on="1"/>
-        <pt x="400" y="-150" on="1"/>
-        <pt x="400" y="750" on="1"/>
-        <pt x="100" y="750" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="A" xMin="5" yMin="0" xMax="906" yMax="700">
-      <contour>
-        <pt x="705" y="0" on="1"/>
-        <pt x="906" y="0" on="1"/>
-        <pt x="556" y="700" on="1"/>
-        <pt x="355" y="700" on="1"/>
-      </contour>
-      <contour>
-        <pt x="5" y="0" on="1"/>
-        <pt x="206" y="0" on="1"/>
-        <pt x="556" y="700" on="1"/>
-        <pt x="355" y="700" on="1"/>
-      </contour>
-      <contour>
-        <pt x="640" y="311" on="1"/>
-        <pt x="190" y="311" on="1"/>
-        <pt x="190" y="191" on="1"/>
-        <pt x="640" y="191" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="Aacute" xMin="5" yMin="0" xMax="906" yMax="949">
-      <component glyphName="A" x="0" y="0" flags="0x204"/>
-      <component glyphName="acutecomb" x="479" y="124" flags="0x4"/>
-    </TTGlyph>
-
-    <TTGlyph name="O" xMin="15" yMin="-10" xMax="670" yMax="710">
-      <contour>
-        <pt x="342" y="-10" on="1"/>
-        <pt x="172" y="-10" on="0"/>
-        <pt x="15" y="163" on="0"/>
-        <pt x="15" y="350" on="1"/>
-        <pt x="15" y="538" on="0"/>
-        <pt x="172" y="710" on="0"/>
-        <pt x="342" y="710" on="1"/>
-        <pt x="513" y="710" on="0"/>
-        <pt x="670" y="538" on="0"/>
-        <pt x="670" y="350" on="1"/>
-        <pt x="670" y="163" on="0"/>
-        <pt x="513" y="-10" on="0"/>
-      </contour>
-      <contour>
-        <pt x="342" y="153" on="1"/>
-        <pt x="419" y="153" on="0"/>
-        <pt x="490" y="247" on="0"/>
-        <pt x="490" y="350" on="1"/>
-        <pt x="490" y="453" on="0"/>
-        <pt x="419" y="547" on="0"/>
-        <pt x="342" y="547" on="1"/>
-        <pt x="266" y="547" on="0"/>
-        <pt x="195" y="453" on="0"/>
-        <pt x="195" y="350" on="1"/>
-        <pt x="195" y="247" on="0"/>
-        <pt x="266" y="153" on="0"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="V" xMin="5" yMin="0" xMax="906" yMax="700">
-      <contour>
-        <pt x="355" y="0" on="1"/>
-        <pt x="705" y="700" on="1"/>
-        <pt x="906" y="700" on="1"/>
-        <pt x="556" y="0" on="1"/>
-      </contour>
-      <contour>
-        <pt x="355" y="0" on="1"/>
-        <pt x="5" y="700" on="1"/>
-        <pt x="206" y="700" on="1"/>
-        <pt x="556" y="0" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="acutecomb" xMin="-141" yMin="630" xMax="125" yMax="825">
-      <contour>
-        <pt x="-118" y="756" on="1"/>
-        <pt x="-141" y="630" on="1"/>
-        <pt x="102" y="699" on="1"/>
-        <pt x="125" y="825" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="dollar" xMin="1" yMin="-98" xMax="595" yMax="789">
-      <contour>
-        <pt x="249" y="789" on="1"/>
-        <pt x="369" y="789" on="1"/>
-        <pt x="369" y="743" on="1"/>
-        <pt x="427" y="735" on="0"/>
-        <pt x="537" y="681" on="0"/>
-        <pt x="590" y="623" on="1"/>
-        <pt x="510" y="515" on="1"/>
-        <pt x="479" y="549" on="0"/>
-        <pt x="411" y="588" on="0"/>
-        <pt x="369" y="595" on="1"/>
-        <pt x="369" y="400" on="1"/>
-        <pt x="476" y="378" on="0"/>
-        <pt x="595" y="278" on="0"/>
-        <pt x="595" y="184" on="1"/>
-        <pt x="595" y="93" on="0"/>
-        <pt x="474" y="-32" on="0"/>
-        <pt x="369" y="-46" on="1"/>
-        <pt x="369" y="-98" on="1"/>
-        <pt x="249" y="-98" on="1"/>
-        <pt x="249" y="-47" on="1"/>
-        <pt x="176" y="-39" on="0"/>
-        <pt x="52" y="17" on="0"/>
-        <pt x="1" y="69" on="1"/>
-        <pt x="80" y="179" on="1"/>
-        <pt x="118" y="144" on="0"/>
-        <pt x="195" y="106" on="0"/>
-        <pt x="249" y="100" on="1"/>
-        <pt x="249" y="273" on="1"/>
-        <pt x="246" y="274" on="1"/>
-        <pt x="144" y="294" on="0"/>
-        <pt x="28" y="405" on="0"/>
-        <pt x="28" y="502" on="1"/>
-        <pt x="28" y="567" on="0"/>
-        <pt x="84" y="667" on="0"/>
-        <pt x="184" y="732" on="0"/>
-        <pt x="249" y="742" on="1"/>
-      </contour>
-      <contour>
-        <pt x="152" y="502" on="1"/>
-        <pt x="152" y="480" on="0"/>
-        <pt x="166" y="453" on="0"/>
-        <pt x="208" y="434" on="0"/>
-        <pt x="249" y="424" on="1"/>
-        <pt x="249" y="595" on="1"/>
-        <pt x="199" y="587" on="0"/>
-        <pt x="152" y="538" on="0"/>
-      </contour>
-      <contour>
-        <pt x="369" y="100" on="1"/>
-        <pt x="426" y="107" on="0"/>
-        <pt x="471" y="150" on="0"/>
-        <pt x="471" y="183" on="1"/>
-        <pt x="471" y="201" on="0"/>
-        <pt x="456" y="225" on="0"/>
-        <pt x="412" y="243" on="0"/>
-        <pt x="369" y="252" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="dollar.BRACKET.500" xMin="1" yMin="-98" xMax="595" yMax="789">
-      <contour>
-        <pt x="249" y="789" on="1"/>
-        <pt x="369" y="789" on="1"/>
-        <pt x="369" y="743" on="1"/>
-        <pt x="427" y="735" on="0"/>
-        <pt x="537" y="681" on="0"/>
-        <pt x="590" y="623" on="1"/>
-        <pt x="510" y="515" on="1"/>
-        <pt x="468" y="560" on="0"/>
-        <pt x="374" y="600" on="0"/>
-        <pt x="308" y="600" on="1"/>
-        <pt x="227" y="600" on="0"/>
-        <pt x="152" y="548" on="0"/>
-        <pt x="152" y="502" on="1"/>
-        <pt x="152" y="479" on="0"/>
-        <pt x="168" y="450" on="0"/>
-        <pt x="217" y="431" on="0"/>
-        <pt x="264" y="421" on="1"/>
-        <pt x="363" y="401" on="1"/>
-        <pt x="473" y="379" on="0"/>
-        <pt x="595" y="279" on="0"/>
-        <pt x="595" y="184" on="1"/>
-        <pt x="595" y="93" on="0"/>
-        <pt x="474" y="-32" on="0"/>
-        <pt x="369" y="-46" on="1"/>
-        <pt x="369" y="-98" on="1"/>
-        <pt x="249" y="-98" on="1"/>
-        <pt x="249" y="-47" on="1"/>
-        <pt x="176" y="-39" on="0"/>
-        <pt x="52" y="17" on="0"/>
-        <pt x="1" y="69" on="1"/>
-        <pt x="80" y="179" on="1"/>
-        <pt x="112" y="150" on="0"/>
-        <pt x="176" y="114" on="0"/>
-        <pt x="256" y="97" on="0"/>
-        <pt x="310" y="97" on="1"/>
-        <pt x="402" y="97" on="0"/>
-        <pt x="471" y="143" on="0"/>
-        <pt x="471" y="183" on="1"/>
-        <pt x="471" y="203" on="0"/>
-        <pt x="453" y="228" on="0"/>
-        <pt x="399" y="247" on="0"/>
-        <pt x="345" y="256" on="1"/>
-        <pt x="246" y="274" on="1"/>
-        <pt x="144" y="293" on="0"/>
-        <pt x="28" y="405" on="0"/>
-        <pt x="28" y="502" on="1"/>
-        <pt x="28" y="567" on="0"/>
-        <pt x="84" y="667" on="0"/>
-        <pt x="184" y="732" on="0"/>
-        <pt x="249" y="742" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="dollar.bold" xMin="1" yMin="-98" xMax="595" yMax="789">
-      <contour>
-        <pt x="249" y="789" on="1"/>
-        <pt x="369" y="789" on="1"/>
-        <pt x="369" y="743" on="1"/>
-        <pt x="427" y="735" on="0"/>
-        <pt x="537" y="681" on="0"/>
-        <pt x="590" y="623" on="1"/>
-        <pt x="510" y="515" on="1"/>
-        <pt x="468" y="560" on="0"/>
-        <pt x="374" y="600" on="0"/>
-        <pt x="308" y="600" on="1"/>
-        <pt x="227" y="600" on="0"/>
-        <pt x="152" y="548" on="0"/>
-        <pt x="152" y="502" on="1"/>
-        <pt x="152" y="479" on="0"/>
-        <pt x="168" y="450" on="0"/>
-        <pt x="217" y="431" on="0"/>
-        <pt x="264" y="421" on="1"/>
-        <pt x="363" y="401" on="1"/>
-        <pt x="473" y="379" on="0"/>
-        <pt x="595" y="279" on="0"/>
-        <pt x="595" y="184" on="1"/>
-        <pt x="595" y="93" on="0"/>
-        <pt x="474" y="-32" on="0"/>
-        <pt x="369" y="-46" on="1"/>
-        <pt x="369" y="-98" on="1"/>
-        <pt x="249" y="-98" on="1"/>
-        <pt x="249" y="-47" on="1"/>
-        <pt x="176" y="-39" on="0"/>
-        <pt x="52" y="17" on="0"/>
-        <pt x="1" y="69" on="1"/>
-        <pt x="80" y="179" on="1"/>
-        <pt x="112" y="150" on="0"/>
-        <pt x="176" y="114" on="0"/>
-        <pt x="256" y="97" on="0"/>
-        <pt x="310" y="97" on="1"/>
-        <pt x="402" y="97" on="0"/>
-        <pt x="471" y="143" on="0"/>
-        <pt x="471" y="183" on="1"/>
-        <pt x="471" y="203" on="0"/>
-        <pt x="453" y="228" on="0"/>
-        <pt x="399" y="247" on="0"/>
-        <pt x="345" y="256" on="1"/>
-        <pt x="246" y="274" on="1"/>
-        <pt x="144" y="293" on="0"/>
-        <pt x="28" y="405" on="0"/>
-        <pt x="28" y="502" on="1"/>
-        <pt x="28" y="567" on="0"/>
-        <pt x="84" y="667" on="0"/>
-        <pt x="184" y="732" on="0"/>
-        <pt x="249" y="742" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="space"/><!-- contains no outline data -->
-
-  </glyf>
-
-  <name>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      Simple Two Axis
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Bold
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      1.000;NONE;SimpleTwoAxis-Bold
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      Simple Two Axis Bold
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version 1.000
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      SimpleTwoAxis-Bold
-    </namerecord>
-  </name>
-
-  <post>
-    <formatType value="2.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-100"/>
-    <underlineThickness value="50"/>
-    <isFixedPitch value="0"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="0"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="0"/>
-    <psNames>
-      <!-- This file uses unique glyph names based on the information
-           found in the 'post' table. Since these names might not be unique,
-           we have to invent artificial names in case of clashes. In order to
-           be able to retain the original information, we need a name to
-           ps name mapping for those cases where they differ. That's what
-           you see below.
-            -->
-    </psNames>
-    <extraNames>
-      <!-- following are the name that are not taken from the standard Mac glyph order -->
-      <psName name="dollar.bold"/>
-      <psName name="acutecomb"/>
-      <psName name="dollar.BRACKET.500"/>
-    </extraNames>
-  </post>
-
-  <GDEF>
-    <Version value="0x00010000"/>
-    <GlyphClassDef>
-      <ClassDef glyph="A" class="1"/>
-      <ClassDef glyph="Aacute" class="1"/>
-      <ClassDef glyph="acutecomb" class="3"/>
-    </GlyphClassDef>
-  </GDEF>
-
-  <GPOS>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=2 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=2 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="kern"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="0"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=2 -->
-      <Lookup index="0">
-        <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
-        <!-- SubTableCount=1 -->
-        <PairPos index="0" Format="1">
-          <Coverage>
-            <Glyph value="A"/>
-            <Glyph value="Aacute"/>
-            <Glyph value="V"/>
-          </Coverage>
-          <ValueFormat1 value="4"/>
-          <ValueFormat2 value="0"/>
-          <!-- PairSetCount=3 -->
-          <PairSet index="0">
-            <!-- PairValueCount=1 -->
-            <PairValueRecord index="0">
-              <SecondGlyph value="V"/>
-              <Value1 XAdvance="-120"/>
-            </PairValueRecord>
-          </PairSet>
-          <PairSet index="1">
-            <!-- PairValueCount=1 -->
-            <PairValueRecord index="0">
-              <SecondGlyph value="V"/>
-              <Value1 XAdvance="-120"/>
-            </PairValueRecord>
-          </PairSet>
-          <PairSet index="2">
-            <!-- PairValueCount=1 -->
-            <PairValueRecord index="0">
-              <SecondGlyph value="O"/>
-              <Value1 XAdvance="-20"/>
-            </PairValueRecord>
-          </PairSet>
-        </PairPos>
-      </Lookup>
-    </LookupList>
-  </GPOS>
-
-</ttFont>
diff --git a/Tests/varLib/data/master_incompatible_features/IncompatibleFeatures-Regular.ttx b/Tests/varLib/data/master_incompatible_features/IncompatibleFeatures-Regular.ttx
deleted file mode 100644
index cabb69a..0000000
--- a/Tests/varLib/data/master_incompatible_features/IncompatibleFeatures-Regular.ttx
+++ /dev/null
@@ -1,626 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.20">
-
-  <GlyphOrder>
-    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="A"/>
-    <GlyphID id="2" name="Aacute"/>
-    <GlyphID id="3" name="O"/>
-    <GlyphID id="4" name="V"/>
-    <GlyphID id="5" name="space"/>
-    <GlyphID id="6" name="dollar"/>
-    <GlyphID id="7" name="dollar.bold"/>
-    <GlyphID id="8" name="acutecomb"/>
-    <GlyphID id="9" name="dollar.BRACKET.500"/>
-  </GlyphOrder>
-
-  <head>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="1.0"/>
-    <fontRevision value="1.0"/>
-    <checkSumAdjustment value="0x3c7bc79b"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00000011"/>
-    <unitsPerEm value="1000"/>
-    <created value="Fri Jan 15 14:37:13 2021"/>
-    <modified value="Mon Mar 15 12:57:03 2021"/>
-    <xMin value="-141"/>
-    <yMin value="-200"/>
-    <xMax value="751"/>
-    <yMax value="915"/>
-    <macStyle value="00000000 00000000"/>
-    <lowestRecPPEM value="6"/>
-    <fontDirectionHint value="2"/>
-    <indexToLocFormat value="0"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="1000"/>
-    <descent value="-200"/>
-    <lineGap value="0"/>
-    <advanceWidthMax value="756"/>
-    <minLeftSideBearing value="-141"/>
-    <minRightSideBearing value="-125"/>
-    <xMaxExtent value="751"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfHMetrics value="10"/>
-  </hhea>
-
-  <maxp>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="0x10000"/>
-    <numGlyphs value="10"/>
-    <maxPoints value="52"/>
-    <maxContours value="3"/>
-    <maxCompositePoints value="16"/>
-    <maxCompositeContours value="4"/>
-    <maxZones value="1"/>
-    <maxTwilightPoints value="0"/>
-    <maxStorage value="0"/>
-    <maxFunctionDefs value="0"/>
-    <maxInstructionDefs value="0"/>
-    <maxStackElements value="0"/>
-    <maxSizeOfInstructions value="0"/>
-    <maxComponentElements value="2"/>
-    <maxComponentDepth value="1"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="4"/>
-    <xAvgCharWidth value="604"/>
-    <usWeightClass value="400"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00001000"/>
-    <ySubscriptXSize value="650"/>
-    <ySubscriptYSize value="600"/>
-    <ySubscriptXOffset value="0"/>
-    <ySubscriptYOffset value="75"/>
-    <ySuperscriptXSize value="650"/>
-    <ySuperscriptYSize value="600"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="350"/>
-    <yStrikeoutSize value="50"/>
-    <yStrikeoutPosition value="300"/>
-    <sFamilyClass value="0"/>
-    <panose>
-      <bFamilyType value="0"/>
-      <bSerifStyle value="0"/>
-      <bWeight value="0"/>
-      <bProportion value="0"/>
-      <bContrast value="0"/>
-      <bStrokeVariation value="0"/>
-      <bArmStyle value="0"/>
-      <bLetterForm value="0"/>
-      <bMidline value="0"/>
-      <bXHeight value="0"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00000000 01000011"/>
-    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="NONE"/>
-    <fsSelection value="00000000 01000000"/>
-    <usFirstCharIndex value="32"/>
-    <usLastCharIndex value="769"/>
-    <sTypoAscender value="800"/>
-    <sTypoDescender value="-200"/>
-    <sTypoLineGap value="200"/>
-    <usWinAscent value="1000"/>
-    <usWinDescent value="200"/>
-    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
-    <sxHeight value="500"/>
-    <sCapHeight value="700"/>
-    <usDefaultChar value="0"/>
-    <usBreakChar value="32"/>
-    <usMaxContext value="2"/>
-  </OS_2>
-
-  <hmtx>
-    <mtx name=".notdef" width="500" lsb="50"/>
-    <mtx name="A" width="756" lsb="5"/>
-    <mtx name="Aacute" width="756" lsb="5"/>
-    <mtx name="O" width="664" lsb="30"/>
-    <mtx name="V" width="756" lsb="5"/>
-    <mtx name="acutecomb" width="0" lsb="-141"/>
-    <mtx name="dollar" width="600" lsb="29"/>
-    <mtx name="dollar.BRACKET.500" width="600" lsb="29"/>
-    <mtx name="dollar.bold" width="600" lsb="29"/>
-    <mtx name="space" width="200" lsb="0"/>
-  </hmtx>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_4 platformID="0" platEncID="3" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x4f" name="O"/><!-- LATIN CAPITAL LETTER O -->
-      <map code="0x56" name="V"/><!-- LATIN CAPITAL LETTER V -->
-      <map code="0xc1" name="Aacute"/><!-- LATIN CAPITAL LETTER A WITH ACUTE -->
-      <map code="0x301" name="acutecomb"/><!-- COMBINING ACUTE ACCENT -->
-    </cmap_format_4>
-    <cmap_format_4 platformID="3" platEncID="1" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x4f" name="O"/><!-- LATIN CAPITAL LETTER O -->
-      <map code="0x56" name="V"/><!-- LATIN CAPITAL LETTER V -->
-      <map code="0xc1" name="Aacute"/><!-- LATIN CAPITAL LETTER A WITH ACUTE -->
-      <map code="0x301" name="acutecomb"/><!-- COMBINING ACUTE ACCENT -->
-    </cmap_format_4>
-  </cmap>
-
-  <loca>
-    <!-- The 'loca' table will be calculated by the compiler -->
-  </loca>
-
-  <glyf>
-
-    <!-- The xMin, yMin, xMax and yMax values
-         will be recalculated by the compiler. -->
-
-    <TTGlyph name=".notdef" xMin="50" yMin="-200" xMax="450" yMax="800">
-      <contour>
-        <pt x="50" y="-200" on="1"/>
-        <pt x="50" y="800" on="1"/>
-        <pt x="450" y="800" on="1"/>
-        <pt x="450" y="-200" on="1"/>
-      </contour>
-      <contour>
-        <pt x="100" y="-150" on="1"/>
-        <pt x="400" y="-150" on="1"/>
-        <pt x="400" y="750" on="1"/>
-        <pt x="100" y="750" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="A" xMin="5" yMin="0" xMax="751" yMax="700">
-      <contour>
-        <pt x="641" y="0" on="1"/>
-        <pt x="751" y="0" on="1"/>
-        <pt x="433" y="700" on="1"/>
-        <pt x="323" y="700" on="1"/>
-      </contour>
-      <contour>
-        <pt x="5" y="0" on="1"/>
-        <pt x="115" y="0" on="1"/>
-        <pt x="433" y="700" on="1"/>
-        <pt x="323" y="700" on="1"/>
-      </contour>
-      <contour>
-        <pt x="567" y="284" on="1"/>
-        <pt x="152" y="284" on="1"/>
-        <pt x="152" y="204" on="1"/>
-        <pt x="567" y="204" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="Aacute" xMin="5" yMin="0" xMax="751" yMax="915">
-      <component glyphName="A" x="0" y="0" flags="0x204"/>
-      <component glyphName="acutecomb" x="402" y="130" flags="0x4"/>
-    </TTGlyph>
-
-    <TTGlyph name="O" xMin="30" yMin="-10" xMax="634" yMax="710">
-      <contour>
-        <pt x="332" y="-10" on="1"/>
-        <pt x="181" y="-10" on="0"/>
-        <pt x="30" y="169" on="0"/>
-        <pt x="30" y="350" on="1"/>
-        <pt x="30" y="531" on="0"/>
-        <pt x="181" y="710" on="0"/>
-        <pt x="332" y="710" on="1"/>
-        <pt x="484" y="710" on="0"/>
-        <pt x="634" y="531" on="0"/>
-        <pt x="634" y="350" on="1"/>
-        <pt x="634" y="169" on="0"/>
-        <pt x="484" y="-10" on="0"/>
-      </contour>
-      <contour>
-        <pt x="332" y="74" on="1"/>
-        <pt x="438" y="74" on="0"/>
-        <pt x="544" y="212" on="0"/>
-        <pt x="544" y="350" on="1"/>
-        <pt x="544" y="488" on="0"/>
-        <pt x="438" y="626" on="0"/>
-        <pt x="332" y="626" on="1"/>
-        <pt x="226" y="626" on="0"/>
-        <pt x="120" y="488" on="0"/>
-        <pt x="120" y="350" on="1"/>
-        <pt x="120" y="212" on="0"/>
-        <pt x="226" y="74" on="0"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="V" xMin="5" yMin="0" xMax="751" yMax="700">
-      <contour>
-        <pt x="323" y="0" on="1"/>
-        <pt x="641" y="700" on="1"/>
-        <pt x="751" y="700" on="1"/>
-        <pt x="433" y="0" on="1"/>
-      </contour>
-      <contour>
-        <pt x="323" y="0" on="1"/>
-        <pt x="5" y="700" on="1"/>
-        <pt x="115" y="700" on="1"/>
-        <pt x="433" y="0" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="acutecomb" xMin="-141" yMin="630" xMax="125" yMax="785">
-      <contour>
-        <pt x="-118" y="716" on="1"/>
-        <pt x="-141" y="630" on="1"/>
-        <pt x="102" y="699" on="1"/>
-        <pt x="125" y="785" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="dollar" xMin="29" yMin="-68" xMax="580" yMax="759">
-      <contour>
-        <pt x="264" y="759" on="1"/>
-        <pt x="354" y="759" on="1"/>
-        <pt x="354" y="715" on="1"/>
-        <pt x="415" y="709" on="0"/>
-        <pt x="519" y="662" on="0"/>
-        <pt x="562" y="620" on="1"/>
-        <pt x="509" y="548" on="1"/>
-        <pt x="473" y="584" on="0"/>
-        <pt x="398" y="621" on="0"/>
-        <pt x="354" y="627" on="1"/>
-        <pt x="354" y="373" on="1"/>
-        <pt x="467" y="351" on="0"/>
-        <pt x="580" y="263" on="0"/>
-        <pt x="580" y="184" on="1"/>
-        <pt x="580" y="102" on="0"/>
-        <pt x="459" y="-8" on="0"/>
-        <pt x="354" y="-18" on="1"/>
-        <pt x="354" y="-68" on="1"/>
-        <pt x="264" y="-68" on="1"/>
-        <pt x="264" y="-18" on="1"/>
-        <pt x="192" y="-12" on="0"/>
-        <pt x="72" y="34" on="0"/>
-        <pt x="29" y="74" on="1"/>
-        <pt x="81" y="146" on="1"/>
-        <pt x="123" y="110" on="0"/>
-        <pt x="207" y="73" on="0"/>
-        <pt x="264" y="69" on="1"/>
-        <pt x="264" y="301" on="1"/>
-        <pt x="249" y="304" on="1"/>
-        <pt x="148" y="323" on="0"/>
-        <pt x="43" y="420" on="0"/>
-        <pt x="43" y="502" on="1"/>
-        <pt x="43" y="559" on="0"/>
-        <pt x="99" y="650" on="0"/>
-        <pt x="199" y="707" on="0"/>
-        <pt x="264" y="715" on="1"/>
-      </contour>
-      <contour>
-        <pt x="137" y="502" on="1"/>
-        <pt x="137" y="470" on="0"/>
-        <pt x="160" y="428" on="0"/>
-        <pt x="214" y="402" on="0"/>
-        <pt x="261" y="392" on="1"/>
-        <pt x="264" y="627" on="1"/>
-        <pt x="203" y="618" on="0"/>
-        <pt x="137" y="553" on="0"/>
-      </contour>
-      <contour>
-        <pt x="354" y="69" on="1"/>
-        <pt x="423" y="76" on="0"/>
-        <pt x="486" y="135" on="0"/>
-        <pt x="486" y="183" on="1"/>
-        <pt x="486" y="211" on="0"/>
-        <pt x="462" y="250" on="0"/>
-        <pt x="405" y="275" on="0"/>
-        <pt x="354" y="285" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="dollar.BRACKET.500" xMin="29" yMin="-76" xMax="580" yMax="759">
-      <contour>
-        <pt x="264" y="759" on="1"/>
-        <pt x="354" y="759" on="1"/>
-        <pt x="354" y="715" on="1"/>
-        <pt x="415" y="709" on="0"/>
-        <pt x="519" y="662" on="0"/>
-        <pt x="562" y="620" on="1"/>
-        <pt x="509" y="548" on="1"/>
-        <pt x="464" y="592" on="0"/>
-        <pt x="370" y="630" on="0"/>
-        <pt x="308" y="630" on="1"/>
-        <pt x="226" y="630" on="0"/>
-        <pt x="137" y="562" on="0"/>
-        <pt x="137" y="502" on="1"/>
-        <pt x="137" y="470" on="0"/>
-        <pt x="160" y="428" on="0"/>
-        <pt x="214" y="402" on="0"/>
-        <pt x="261" y="392" on="1"/>
-        <pt x="360" y="372" on="1"/>
-        <pt x="469" y="350" on="0"/>
-        <pt x="580" y="263" on="0"/>
-        <pt x="580" y="184" on="1"/>
-        <pt x="580" y="102" on="0"/>
-        <pt x="459" y="-8" on="0"/>
-        <pt x="354" y="-18" on="1"/>
-        <pt x="354" y="-76" on="1"/>
-        <pt x="264" y="-76" on="1"/>
-        <pt x="264" y="-18" on="1"/>
-        <pt x="192" y="-12" on="0"/>
-        <pt x="72" y="34" on="0"/>
-        <pt x="29" y="74" on="1"/>
-        <pt x="81" y="146" on="1"/>
-        <pt x="115" y="118" on="0"/>
-        <pt x="180" y="83" on="0"/>
-        <pt x="259" y="67" on="0"/>
-        <pt x="310" y="67" on="1"/>
-        <pt x="403" y="67" on="0"/>
-        <pt x="486" y="128" on="0"/>
-        <pt x="486" y="183" on="1"/>
-        <pt x="486" y="212" on="0"/>
-        <pt x="461" y="251" on="0"/>
-        <pt x="401" y="277" on="0"/>
-        <pt x="348" y="286" on="1"/>
-        <pt x="249" y="304" on="1"/>
-        <pt x="148" y="323" on="0"/>
-        <pt x="43" y="420" on="0"/>
-        <pt x="43" y="502" on="1"/>
-        <pt x="43" y="559" on="0"/>
-        <pt x="99" y="650" on="0"/>
-        <pt x="199" y="707" on="0"/>
-        <pt x="264" y="715" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="dollar.bold" xMin="29" yMin="-76" xMax="580" yMax="759">
-      <contour>
-        <pt x="264" y="759" on="1"/>
-        <pt x="354" y="759" on="1"/>
-        <pt x="354" y="715" on="1"/>
-        <pt x="415" y="709" on="0"/>
-        <pt x="519" y="662" on="0"/>
-        <pt x="562" y="620" on="1"/>
-        <pt x="509" y="548" on="1"/>
-        <pt x="464" y="592" on="0"/>
-        <pt x="370" y="630" on="0"/>
-        <pt x="308" y="630" on="1"/>
-        <pt x="226" y="630" on="0"/>
-        <pt x="137" y="562" on="0"/>
-        <pt x="137" y="502" on="1"/>
-        <pt x="137" y="470" on="0"/>
-        <pt x="160" y="428" on="0"/>
-        <pt x="214" y="402" on="0"/>
-        <pt x="261" y="392" on="1"/>
-        <pt x="360" y="372" on="1"/>
-        <pt x="469" y="350" on="0"/>
-        <pt x="580" y="263" on="0"/>
-        <pt x="580" y="184" on="1"/>
-        <pt x="580" y="102" on="0"/>
-        <pt x="459" y="-8" on="0"/>
-        <pt x="354" y="-18" on="1"/>
-        <pt x="354" y="-76" on="1"/>
-        <pt x="264" y="-76" on="1"/>
-        <pt x="264" y="-18" on="1"/>
-        <pt x="192" y="-12" on="0"/>
-        <pt x="72" y="34" on="0"/>
-        <pt x="29" y="74" on="1"/>
-        <pt x="81" y="146" on="1"/>
-        <pt x="115" y="118" on="0"/>
-        <pt x="180" y="83" on="0"/>
-        <pt x="259" y="67" on="0"/>
-        <pt x="310" y="67" on="1"/>
-        <pt x="403" y="67" on="0"/>
-        <pt x="486" y="128" on="0"/>
-        <pt x="486" y="183" on="1"/>
-        <pt x="486" y="212" on="0"/>
-        <pt x="461" y="251" on="0"/>
-        <pt x="401" y="277" on="0"/>
-        <pt x="348" y="286" on="1"/>
-        <pt x="249" y="304" on="1"/>
-        <pt x="148" y="323" on="0"/>
-        <pt x="43" y="420" on="0"/>
-        <pt x="43" y="502" on="1"/>
-        <pt x="43" y="559" on="0"/>
-        <pt x="99" y="650" on="0"/>
-        <pt x="199" y="707" on="0"/>
-        <pt x="264" y="715" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="space"/><!-- contains no outline data -->
-
-  </glyf>
-
-  <name>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      Simple Two Axis
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      1.000;NONE;SimpleTwoAxis-Regular
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      Simple Two Axis Regular
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version 1.000
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      SimpleTwoAxis-Regular
-    </namerecord>
-  </name>
-
-  <post>
-    <formatType value="2.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-100"/>
-    <underlineThickness value="50"/>
-    <isFixedPitch value="0"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="0"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="0"/>
-    <psNames>
-      <!-- This file uses unique glyph names based on the information
-           found in the 'post' table. Since these names might not be unique,
-           we have to invent artificial names in case of clashes. In order to
-           be able to retain the original information, we need a name to
-           ps name mapping for those cases where they differ. That's what
-           you see below.
-            -->
-    </psNames>
-    <extraNames>
-      <!-- following are the name that are not taken from the standard Mac glyph order -->
-      <psName name="dollar.bold"/>
-      <psName name="acutecomb"/>
-      <psName name="dollar.BRACKET.500"/>
-    </extraNames>
-  </post>
-
-  <GDEF>
-    <Version value="0x00010000"/>
-    <GlyphClassDef>
-      <ClassDef glyph="A" class="1"/>
-      <ClassDef glyph="Aacute" class="1"/>
-      <ClassDef glyph="acutecomb" class="3"/>
-    </GlyphClassDef>
-  </GDEF>
-
-  <GPOS>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=2 -->
-            <FeatureIndex index="0" value="0"/>
-            <FeatureIndex index="1" value="1"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=2 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="kern"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="0"/>
-        </Feature>
-      </FeatureRecord>
-      <FeatureRecord index="1">
-        <FeatureTag value="mark"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="1"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=2 -->
-      <Lookup index="0">
-        <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
-        <!-- SubTableCount=1 -->
-        <PairPos index="0" Format="1">
-          <Coverage>
-            <Glyph value="A"/>
-            <Glyph value="Aacute"/>
-            <Glyph value="V"/>
-          </Coverage>
-          <ValueFormat1 value="4"/>
-          <ValueFormat2 value="0"/>
-          <!-- PairSetCount=3 -->
-          <PairSet index="0">
-            <!-- PairValueCount=1 -->
-            <PairValueRecord index="0">
-              <SecondGlyph value="V"/>
-              <Value1 XAdvance="-80"/>
-            </PairValueRecord>
-          </PairSet>
-          <PairSet index="1">
-            <!-- PairValueCount=1 -->
-            <PairValueRecord index="0">
-              <SecondGlyph value="V"/>
-              <Value1 XAdvance="-80"/>
-            </PairValueRecord>
-          </PairSet>
-          <PairSet index="2">
-            <!-- PairValueCount=1 -->
-            <PairValueRecord index="0">
-              <SecondGlyph value="O"/>
-              <Value1 XAdvance="-20"/>
-            </PairValueRecord>
-          </PairSet>
-        </PairPos>
-      </Lookup>
-      <Lookup index="1">
-        <LookupType value="4"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <MarkBasePos index="0" Format="1">
-          <MarkCoverage>
-            <Glyph value="acutecomb"/>
-          </MarkCoverage>
-          <BaseCoverage>
-            <Glyph value="A"/>
-            <Glyph value="Aacute"/>
-          </BaseCoverage>
-          <!-- ClassCount=1 -->
-          <MarkArray>
-            <!-- MarkCount=1 -->
-            <MarkRecord index="0">
-              <Class value="0"/>
-              <MarkAnchor Format="1">
-                <XCoordinate value="4"/>
-                <YCoordinate value="623"/>
-              </MarkAnchor>
-            </MarkRecord>
-          </MarkArray>
-          <BaseArray>
-            <!-- BaseCount=2 -->
-            <BaseRecord index="0">
-              <BaseAnchor index="0" Format="1">
-                <XCoordinate value="406"/>
-                <YCoordinate value="753"/>
-              </BaseAnchor>
-            </BaseRecord>
-            <BaseRecord index="1">
-              <BaseAnchor index="0" Format="1">
-                <XCoordinate value="406"/>
-                <YCoordinate value="753"/>
-              </BaseAnchor>
-            </BaseRecord>
-          </BaseArray>
-        </MarkBasePos>
-      </Lookup>
-    </LookupList>
-  </GPOS>
-
-</ttFont>
diff --git a/Tests/varLib/data/master_incompatible_lookup_types/IncompatibleLookupTypes-Bold.ttx b/Tests/varLib/data/master_incompatible_lookup_types/IncompatibleLookupTypes-Bold.ttx
deleted file mode 100644
index 6a28223..0000000
--- a/Tests/varLib/data/master_incompatible_lookup_types/IncompatibleLookupTypes-Bold.ttx
+++ /dev/null
@@ -1,622 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.20">
-
-  <GlyphOrder>
-    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="A"/>
-    <GlyphID id="2" name="Aacute"/>
-    <GlyphID id="3" name="O"/>
-    <GlyphID id="4" name="V"/>
-    <GlyphID id="5" name="space"/>
-    <GlyphID id="6" name="dollar"/>
-    <GlyphID id="7" name="dollar.bold"/>
-    <GlyphID id="8" name="acutecomb"/>
-    <GlyphID id="9" name="dollar.BRACKET.500"/>
-  </GlyphOrder>
-
-  <head>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="1.0"/>
-    <fontRevision value="1.0"/>
-    <checkSumAdjustment value="0x10cb3f3"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00000011"/>
-    <unitsPerEm value="1000"/>
-    <created value="Fri Jan 15 14:37:13 2021"/>
-    <modified value="Mon Mar 15 12:57:03 2021"/>
-    <xMin value="-141"/>
-    <yMin value="-200"/>
-    <xMax value="906"/>
-    <yMax value="949"/>
-    <macStyle value="00000000 00000001"/>
-    <lowestRecPPEM value="6"/>
-    <fontDirectionHint value="2"/>
-    <indexToLocFormat value="0"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="1000"/>
-    <descent value="-200"/>
-    <lineGap value="0"/>
-    <advanceWidthMax value="911"/>
-    <minLeftSideBearing value="-141"/>
-    <minRightSideBearing value="-125"/>
-    <xMaxExtent value="906"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfHMetrics value="10"/>
-  </hhea>
-
-  <maxp>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="0x10000"/>
-    <numGlyphs value="10"/>
-    <maxPoints value="52"/>
-    <maxContours value="3"/>
-    <maxCompositePoints value="16"/>
-    <maxCompositeContours value="4"/>
-    <maxZones value="1"/>
-    <maxTwilightPoints value="0"/>
-    <maxStorage value="0"/>
-    <maxFunctionDefs value="0"/>
-    <maxInstructionDefs value="0"/>
-    <maxStackElements value="0"/>
-    <maxSizeOfInstructions value="0"/>
-    <maxComponentElements value="2"/>
-    <maxComponentDepth value="1"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="4"/>
-    <xAvgCharWidth value="672"/>
-    <usWeightClass value="400"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00001000"/>
-    <ySubscriptXSize value="650"/>
-    <ySubscriptYSize value="600"/>
-    <ySubscriptXOffset value="0"/>
-    <ySubscriptYOffset value="75"/>
-    <ySuperscriptXSize value="650"/>
-    <ySuperscriptYSize value="600"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="350"/>
-    <yStrikeoutSize value="50"/>
-    <yStrikeoutPosition value="300"/>
-    <sFamilyClass value="0"/>
-    <panose>
-      <bFamilyType value="0"/>
-      <bSerifStyle value="0"/>
-      <bWeight value="0"/>
-      <bProportion value="0"/>
-      <bContrast value="0"/>
-      <bStrokeVariation value="0"/>
-      <bArmStyle value="0"/>
-      <bLetterForm value="0"/>
-      <bMidline value="0"/>
-      <bXHeight value="0"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00000000 01000011"/>
-    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="NONE"/>
-    <fsSelection value="00000000 00100000"/>
-    <usFirstCharIndex value="32"/>
-    <usLastCharIndex value="769"/>
-    <sTypoAscender value="800"/>
-    <sTypoDescender value="-200"/>
-    <sTypoLineGap value="200"/>
-    <usWinAscent value="1000"/>
-    <usWinDescent value="200"/>
-    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
-    <sxHeight value="500"/>
-    <sCapHeight value="700"/>
-    <usDefaultChar value="0"/>
-    <usBreakChar value="32"/>
-    <usMaxContext value="2"/>
-  </OS_2>
-
-  <hmtx>
-    <mtx name=".notdef" width="500" lsb="50"/>
-    <mtx name="A" width="911" lsb="5"/>
-    <mtx name="Aacute" width="911" lsb="5"/>
-    <mtx name="O" width="715" lsb="15"/>
-    <mtx name="V" width="911" lsb="5"/>
-    <mtx name="acutecomb" width="0" lsb="-141"/>
-    <mtx name="dollar" width="600" lsb="1"/>
-    <mtx name="dollar.BRACKET.500" width="600" lsb="1"/>
-    <mtx name="dollar.bold" width="600" lsb="1"/>
-    <mtx name="space" width="300" lsb="0"/>
-  </hmtx>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_4 platformID="0" platEncID="3" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x4f" name="O"/><!-- LATIN CAPITAL LETTER O -->
-      <map code="0x56" name="V"/><!-- LATIN CAPITAL LETTER V -->
-      <map code="0xc1" name="Aacute"/><!-- LATIN CAPITAL LETTER A WITH ACUTE -->
-      <map code="0x301" name="acutecomb"/><!-- COMBINING ACUTE ACCENT -->
-    </cmap_format_4>
-    <cmap_format_4 platformID="3" platEncID="1" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x4f" name="O"/><!-- LATIN CAPITAL LETTER O -->
-      <map code="0x56" name="V"/><!-- LATIN CAPITAL LETTER V -->
-      <map code="0xc1" name="Aacute"/><!-- LATIN CAPITAL LETTER A WITH ACUTE -->
-      <map code="0x301" name="acutecomb"/><!-- COMBINING ACUTE ACCENT -->
-    </cmap_format_4>
-  </cmap>
-
-  <loca>
-    <!-- The 'loca' table will be calculated by the compiler -->
-  </loca>
-
-  <glyf>
-
-    <!-- The xMin, yMin, xMax and yMax values
-         will be recalculated by the compiler. -->
-
-    <TTGlyph name=".notdef" xMin="50" yMin="-200" xMax="450" yMax="800">
-      <contour>
-        <pt x="50" y="-200" on="1"/>
-        <pt x="50" y="800" on="1"/>
-        <pt x="450" y="800" on="1"/>
-        <pt x="450" y="-200" on="1"/>
-      </contour>
-      <contour>
-        <pt x="100" y="-150" on="1"/>
-        <pt x="400" y="-150" on="1"/>
-        <pt x="400" y="750" on="1"/>
-        <pt x="100" y="750" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="A" xMin="5" yMin="0" xMax="906" yMax="700">
-      <contour>
-        <pt x="705" y="0" on="1"/>
-        <pt x="906" y="0" on="1"/>
-        <pt x="556" y="700" on="1"/>
-        <pt x="355" y="700" on="1"/>
-      </contour>
-      <contour>
-        <pt x="5" y="0" on="1"/>
-        <pt x="206" y="0" on="1"/>
-        <pt x="556" y="700" on="1"/>
-        <pt x="355" y="700" on="1"/>
-      </contour>
-      <contour>
-        <pt x="640" y="311" on="1"/>
-        <pt x="190" y="311" on="1"/>
-        <pt x="190" y="191" on="1"/>
-        <pt x="640" y="191" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="Aacute" xMin="5" yMin="0" xMax="906" yMax="949">
-      <component glyphName="A" x="0" y="0" flags="0x204"/>
-      <component glyphName="acutecomb" x="479" y="124" flags="0x4"/>
-    </TTGlyph>
-
-    <TTGlyph name="O" xMin="15" yMin="-10" xMax="670" yMax="710">
-      <contour>
-        <pt x="342" y="-10" on="1"/>
-        <pt x="172" y="-10" on="0"/>
-        <pt x="15" y="163" on="0"/>
-        <pt x="15" y="350" on="1"/>
-        <pt x="15" y="538" on="0"/>
-        <pt x="172" y="710" on="0"/>
-        <pt x="342" y="710" on="1"/>
-        <pt x="513" y="710" on="0"/>
-        <pt x="670" y="538" on="0"/>
-        <pt x="670" y="350" on="1"/>
-        <pt x="670" y="163" on="0"/>
-        <pt x="513" y="-10" on="0"/>
-      </contour>
-      <contour>
-        <pt x="342" y="153" on="1"/>
-        <pt x="419" y="153" on="0"/>
-        <pt x="490" y="247" on="0"/>
-        <pt x="490" y="350" on="1"/>
-        <pt x="490" y="453" on="0"/>
-        <pt x="419" y="547" on="0"/>
-        <pt x="342" y="547" on="1"/>
-        <pt x="266" y="547" on="0"/>
-        <pt x="195" y="453" on="0"/>
-        <pt x="195" y="350" on="1"/>
-        <pt x="195" y="247" on="0"/>
-        <pt x="266" y="153" on="0"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="V" xMin="5" yMin="0" xMax="906" yMax="700">
-      <contour>
-        <pt x="355" y="0" on="1"/>
-        <pt x="705" y="700" on="1"/>
-        <pt x="906" y="700" on="1"/>
-        <pt x="556" y="0" on="1"/>
-      </contour>
-      <contour>
-        <pt x="355" y="0" on="1"/>
-        <pt x="5" y="700" on="1"/>
-        <pt x="206" y="700" on="1"/>
-        <pt x="556" y="0" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="acutecomb" xMin="-141" yMin="630" xMax="125" yMax="825">
-      <contour>
-        <pt x="-118" y="756" on="1"/>
-        <pt x="-141" y="630" on="1"/>
-        <pt x="102" y="699" on="1"/>
-        <pt x="125" y="825" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="dollar" xMin="1" yMin="-98" xMax="595" yMax="789">
-      <contour>
-        <pt x="249" y="789" on="1"/>
-        <pt x="369" y="789" on="1"/>
-        <pt x="369" y="743" on="1"/>
-        <pt x="427" y="735" on="0"/>
-        <pt x="537" y="681" on="0"/>
-        <pt x="590" y="623" on="1"/>
-        <pt x="510" y="515" on="1"/>
-        <pt x="479" y="549" on="0"/>
-        <pt x="411" y="588" on="0"/>
-        <pt x="369" y="595" on="1"/>
-        <pt x="369" y="400" on="1"/>
-        <pt x="476" y="378" on="0"/>
-        <pt x="595" y="278" on="0"/>
-        <pt x="595" y="184" on="1"/>
-        <pt x="595" y="93" on="0"/>
-        <pt x="474" y="-32" on="0"/>
-        <pt x="369" y="-46" on="1"/>
-        <pt x="369" y="-98" on="1"/>
-        <pt x="249" y="-98" on="1"/>
-        <pt x="249" y="-47" on="1"/>
-        <pt x="176" y="-39" on="0"/>
-        <pt x="52" y="17" on="0"/>
-        <pt x="1" y="69" on="1"/>
-        <pt x="80" y="179" on="1"/>
-        <pt x="118" y="144" on="0"/>
-        <pt x="195" y="106" on="0"/>
-        <pt x="249" y="100" on="1"/>
-        <pt x="249" y="273" on="1"/>
-        <pt x="246" y="274" on="1"/>
-        <pt x="144" y="294" on="0"/>
-        <pt x="28" y="405" on="0"/>
-        <pt x="28" y="502" on="1"/>
-        <pt x="28" y="567" on="0"/>
-        <pt x="84" y="667" on="0"/>
-        <pt x="184" y="732" on="0"/>
-        <pt x="249" y="742" on="1"/>
-      </contour>
-      <contour>
-        <pt x="152" y="502" on="1"/>
-        <pt x="152" y="480" on="0"/>
-        <pt x="166" y="453" on="0"/>
-        <pt x="208" y="434" on="0"/>
-        <pt x="249" y="424" on="1"/>
-        <pt x="249" y="595" on="1"/>
-        <pt x="199" y="587" on="0"/>
-        <pt x="152" y="538" on="0"/>
-      </contour>
-      <contour>
-        <pt x="369" y="100" on="1"/>
-        <pt x="426" y="107" on="0"/>
-        <pt x="471" y="150" on="0"/>
-        <pt x="471" y="183" on="1"/>
-        <pt x="471" y="201" on="0"/>
-        <pt x="456" y="225" on="0"/>
-        <pt x="412" y="243" on="0"/>
-        <pt x="369" y="252" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="dollar.BRACKET.500" xMin="1" yMin="-98" xMax="595" yMax="789">
-      <contour>
-        <pt x="249" y="789" on="1"/>
-        <pt x="369" y="789" on="1"/>
-        <pt x="369" y="743" on="1"/>
-        <pt x="427" y="735" on="0"/>
-        <pt x="537" y="681" on="0"/>
-        <pt x="590" y="623" on="1"/>
-        <pt x="510" y="515" on="1"/>
-        <pt x="468" y="560" on="0"/>
-        <pt x="374" y="600" on="0"/>
-        <pt x="308" y="600" on="1"/>
-        <pt x="227" y="600" on="0"/>
-        <pt x="152" y="548" on="0"/>
-        <pt x="152" y="502" on="1"/>
-        <pt x="152" y="479" on="0"/>
-        <pt x="168" y="450" on="0"/>
-        <pt x="217" y="431" on="0"/>
-        <pt x="264" y="421" on="1"/>
-        <pt x="363" y="401" on="1"/>
-        <pt x="473" y="379" on="0"/>
-        <pt x="595" y="279" on="0"/>
-        <pt x="595" y="184" on="1"/>
-        <pt x="595" y="93" on="0"/>
-        <pt x="474" y="-32" on="0"/>
-        <pt x="369" y="-46" on="1"/>
-        <pt x="369" y="-98" on="1"/>
-        <pt x="249" y="-98" on="1"/>
-        <pt x="249" y="-47" on="1"/>
-        <pt x="176" y="-39" on="0"/>
-        <pt x="52" y="17" on="0"/>
-        <pt x="1" y="69" on="1"/>
-        <pt x="80" y="179" on="1"/>
-        <pt x="112" y="150" on="0"/>
-        <pt x="176" y="114" on="0"/>
-        <pt x="256" y="97" on="0"/>
-        <pt x="310" y="97" on="1"/>
-        <pt x="402" y="97" on="0"/>
-        <pt x="471" y="143" on="0"/>
-        <pt x="471" y="183" on="1"/>
-        <pt x="471" y="203" on="0"/>
-        <pt x="453" y="228" on="0"/>
-        <pt x="399" y="247" on="0"/>
-        <pt x="345" y="256" on="1"/>
-        <pt x="246" y="274" on="1"/>
-        <pt x="144" y="293" on="0"/>
-        <pt x="28" y="405" on="0"/>
-        <pt x="28" y="502" on="1"/>
-        <pt x="28" y="567" on="0"/>
-        <pt x="84" y="667" on="0"/>
-        <pt x="184" y="732" on="0"/>
-        <pt x="249" y="742" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="dollar.bold" xMin="1" yMin="-98" xMax="595" yMax="789">
-      <contour>
-        <pt x="249" y="789" on="1"/>
-        <pt x="369" y="789" on="1"/>
-        <pt x="369" y="743" on="1"/>
-        <pt x="427" y="735" on="0"/>
-        <pt x="537" y="681" on="0"/>
-        <pt x="590" y="623" on="1"/>
-        <pt x="510" y="515" on="1"/>
-        <pt x="468" y="560" on="0"/>
-        <pt x="374" y="600" on="0"/>
-        <pt x="308" y="600" on="1"/>
-        <pt x="227" y="600" on="0"/>
-        <pt x="152" y="548" on="0"/>
-        <pt x="152" y="502" on="1"/>
-        <pt x="152" y="479" on="0"/>
-        <pt x="168" y="450" on="0"/>
-        <pt x="217" y="431" on="0"/>
-        <pt x="264" y="421" on="1"/>
-        <pt x="363" y="401" on="1"/>
-        <pt x="473" y="379" on="0"/>
-        <pt x="595" y="279" on="0"/>
-        <pt x="595" y="184" on="1"/>
-        <pt x="595" y="93" on="0"/>
-        <pt x="474" y="-32" on="0"/>
-        <pt x="369" y="-46" on="1"/>
-        <pt x="369" y="-98" on="1"/>
-        <pt x="249" y="-98" on="1"/>
-        <pt x="249" y="-47" on="1"/>
-        <pt x="176" y="-39" on="0"/>
-        <pt x="52" y="17" on="0"/>
-        <pt x="1" y="69" on="1"/>
-        <pt x="80" y="179" on="1"/>
-        <pt x="112" y="150" on="0"/>
-        <pt x="176" y="114" on="0"/>
-        <pt x="256" y="97" on="0"/>
-        <pt x="310" y="97" on="1"/>
-        <pt x="402" y="97" on="0"/>
-        <pt x="471" y="143" on="0"/>
-        <pt x="471" y="183" on="1"/>
-        <pt x="471" y="203" on="0"/>
-        <pt x="453" y="228" on="0"/>
-        <pt x="399" y="247" on="0"/>
-        <pt x="345" y="256" on="1"/>
-        <pt x="246" y="274" on="1"/>
-        <pt x="144" y="293" on="0"/>
-        <pt x="28" y="405" on="0"/>
-        <pt x="28" y="502" on="1"/>
-        <pt x="28" y="567" on="0"/>
-        <pt x="84" y="667" on="0"/>
-        <pt x="184" y="732" on="0"/>
-        <pt x="249" y="742" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="space"/><!-- contains no outline data -->
-
-  </glyf>
-
-  <name>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      Simple Two Axis
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Bold
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      1.000;NONE;SimpleTwoAxis-Bold
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      Simple Two Axis Bold
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version 1.000
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      SimpleTwoAxis-Bold
-    </namerecord>
-  </name>
-
-  <post>
-    <formatType value="2.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-100"/>
-    <underlineThickness value="50"/>
-    <isFixedPitch value="0"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="0"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="0"/>
-    <psNames>
-      <!-- This file uses unique glyph names based on the information
-           found in the 'post' table. Since these names might not be unique,
-           we have to invent artificial names in case of clashes. In order to
-           be able to retain the original information, we need a name to
-           ps name mapping for those cases where they differ. That's what
-           you see below.
-            -->
-    </psNames>
-    <extraNames>
-      <!-- following are the name that are not taken from the standard Mac glyph order -->
-      <psName name="dollar.bold"/>
-      <psName name="acutecomb"/>
-      <psName name="dollar.BRACKET.500"/>
-    </extraNames>
-  </post>
-
-  <GDEF>
-    <Version value="0x00010000"/>
-    <GlyphClassDef>
-      <ClassDef glyph="A" class="1"/>
-      <ClassDef glyph="Aacute" class="1"/>
-      <ClassDef glyph="acutecomb" class="3"/>
-    </GlyphClassDef>
-  </GDEF>
-
-  <GPOS>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=2 -->
-            <FeatureIndex index="0" value="0"/>
-            <FeatureIndex index="1" value="1"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=2 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="kern"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="0"/>
-        </Feature>
-      </FeatureRecord>
-      <FeatureRecord index="1">
-        <FeatureTag value="mark"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="1"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=2 -->
-      <Lookup index="0">
-        <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
-        <!-- SubTableCount=1 -->
-        <PairPos index="0" Format="1">
-          <Coverage>
-            <Glyph value="A"/>
-            <Glyph value="Aacute"/>
-            <Glyph value="V"/>
-          </Coverage>
-          <ValueFormat1 value="4"/>
-          <ValueFormat2 value="0"/>
-          <!-- PairSetCount=3 -->
-          <PairSet index="0">
-            <!-- PairValueCount=1 -->
-            <PairValueRecord index="0">
-              <SecondGlyph value="V"/>
-              <Value1 XAdvance="-80"/>
-            </PairValueRecord>
-          </PairSet>
-          <PairSet index="1">
-            <!-- PairValueCount=1 -->
-            <PairValueRecord index="0">
-              <SecondGlyph value="V"/>
-              <Value1 XAdvance="-80"/>
-            </PairValueRecord>
-          </PairSet>
-          <PairSet index="2">
-            <!-- PairValueCount=1 -->
-            <PairValueRecord index="0">
-              <SecondGlyph value="O"/>
-              <Value1 XAdvance="-20"/>
-            </PairValueRecord>
-          </PairSet>
-        </PairPos>
-      </Lookup>
-      <Lookup index="1">
-        <LookupType value="4"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <PairPos index="0" Format="1">
-          <Coverage>
-            <Glyph value="A"/>
-            <Glyph value="Aacute"/>
-            <Glyph value="V"/>
-          </Coverage>
-          <ValueFormat1 value="4"/>
-          <ValueFormat2 value="0"/>
-          <!-- PairSetCount=3 -->
-          <PairSet index="0">
-            <!-- PairValueCount=1 -->
-            <PairValueRecord index="0">
-              <SecondGlyph value="V"/>
-              <Value1 XAdvance="-80"/>
-            </PairValueRecord>
-          </PairSet>
-          <PairSet index="1">
-            <!-- PairValueCount=1 -->
-            <PairValueRecord index="0">
-              <SecondGlyph value="V"/>
-              <Value1 XAdvance="-80"/>
-            </PairValueRecord>
-          </PairSet>
-          <PairSet index="2">
-            <!-- PairValueCount=1 -->
-            <PairValueRecord index="0">
-              <SecondGlyph value="O"/>
-              <Value1 XAdvance="-20"/>
-            </PairValueRecord>
-          </PairSet>
-        </PairPos>
-      </Lookup>
-    </LookupList>
-  </GPOS>
-
-</ttFont>
diff --git a/Tests/varLib/data/master_incompatible_lookup_types/IncompatibleLookupTypes-Regular.ttx b/Tests/varLib/data/master_incompatible_lookup_types/IncompatibleLookupTypes-Regular.ttx
deleted file mode 100644
index dc6eb17..0000000
--- a/Tests/varLib/data/master_incompatible_lookup_types/IncompatibleLookupTypes-Regular.ttx
+++ /dev/null
@@ -1,626 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.20">
-
-  <GlyphOrder>
-    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="A"/>
-    <GlyphID id="2" name="Aacute"/>
-    <GlyphID id="3" name="O"/>
-    <GlyphID id="4" name="V"/>
-    <GlyphID id="5" name="space"/>
-    <GlyphID id="6" name="dollar"/>
-    <GlyphID id="7" name="dollar.bold"/>
-    <GlyphID id="8" name="acutecomb"/>
-    <GlyphID id="9" name="dollar.BRACKET.500"/>
-  </GlyphOrder>
-
-  <head>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="1.0"/>
-    <fontRevision value="1.0"/>
-    <checkSumAdjustment value="0x3c7bc79b"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00000011"/>
-    <unitsPerEm value="1000"/>
-    <created value="Fri Jan 15 14:37:13 2021"/>
-    <modified value="Mon Mar 15 12:57:03 2021"/>
-    <xMin value="-141"/>
-    <yMin value="-200"/>
-    <xMax value="751"/>
-    <yMax value="915"/>
-    <macStyle value="00000000 00000000"/>
-    <lowestRecPPEM value="6"/>
-    <fontDirectionHint value="2"/>
-    <indexToLocFormat value="0"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="1000"/>
-    <descent value="-200"/>
-    <lineGap value="0"/>
-    <advanceWidthMax value="756"/>
-    <minLeftSideBearing value="-141"/>
-    <minRightSideBearing value="-125"/>
-    <xMaxExtent value="751"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfHMetrics value="10"/>
-  </hhea>
-
-  <maxp>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="0x10000"/>
-    <numGlyphs value="10"/>
-    <maxPoints value="52"/>
-    <maxContours value="3"/>
-    <maxCompositePoints value="16"/>
-    <maxCompositeContours value="4"/>
-    <maxZones value="1"/>
-    <maxTwilightPoints value="0"/>
-    <maxStorage value="0"/>
-    <maxFunctionDefs value="0"/>
-    <maxInstructionDefs value="0"/>
-    <maxStackElements value="0"/>
-    <maxSizeOfInstructions value="0"/>
-    <maxComponentElements value="2"/>
-    <maxComponentDepth value="1"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="4"/>
-    <xAvgCharWidth value="604"/>
-    <usWeightClass value="400"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00001000"/>
-    <ySubscriptXSize value="650"/>
-    <ySubscriptYSize value="600"/>
-    <ySubscriptXOffset value="0"/>
-    <ySubscriptYOffset value="75"/>
-    <ySuperscriptXSize value="650"/>
-    <ySuperscriptYSize value="600"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="350"/>
-    <yStrikeoutSize value="50"/>
-    <yStrikeoutPosition value="300"/>
-    <sFamilyClass value="0"/>
-    <panose>
-      <bFamilyType value="0"/>
-      <bSerifStyle value="0"/>
-      <bWeight value="0"/>
-      <bProportion value="0"/>
-      <bContrast value="0"/>
-      <bStrokeVariation value="0"/>
-      <bArmStyle value="0"/>
-      <bLetterForm value="0"/>
-      <bMidline value="0"/>
-      <bXHeight value="0"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00000000 01000011"/>
-    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="NONE"/>
-    <fsSelection value="00000000 01000000"/>
-    <usFirstCharIndex value="32"/>
-    <usLastCharIndex value="769"/>
-    <sTypoAscender value="800"/>
-    <sTypoDescender value="-200"/>
-    <sTypoLineGap value="200"/>
-    <usWinAscent value="1000"/>
-    <usWinDescent value="200"/>
-    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
-    <sxHeight value="500"/>
-    <sCapHeight value="700"/>
-    <usDefaultChar value="0"/>
-    <usBreakChar value="32"/>
-    <usMaxContext value="2"/>
-  </OS_2>
-
-  <hmtx>
-    <mtx name=".notdef" width="500" lsb="50"/>
-    <mtx name="A" width="756" lsb="5"/>
-    <mtx name="Aacute" width="756" lsb="5"/>
-    <mtx name="O" width="664" lsb="30"/>
-    <mtx name="V" width="756" lsb="5"/>
-    <mtx name="acutecomb" width="0" lsb="-141"/>
-    <mtx name="dollar" width="600" lsb="29"/>
-    <mtx name="dollar.BRACKET.500" width="600" lsb="29"/>
-    <mtx name="dollar.bold" width="600" lsb="29"/>
-    <mtx name="space" width="200" lsb="0"/>
-  </hmtx>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_4 platformID="0" platEncID="3" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x4f" name="O"/><!-- LATIN CAPITAL LETTER O -->
-      <map code="0x56" name="V"/><!-- LATIN CAPITAL LETTER V -->
-      <map code="0xc1" name="Aacute"/><!-- LATIN CAPITAL LETTER A WITH ACUTE -->
-      <map code="0x301" name="acutecomb"/><!-- COMBINING ACUTE ACCENT -->
-    </cmap_format_4>
-    <cmap_format_4 platformID="3" platEncID="1" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x4f" name="O"/><!-- LATIN CAPITAL LETTER O -->
-      <map code="0x56" name="V"/><!-- LATIN CAPITAL LETTER V -->
-      <map code="0xc1" name="Aacute"/><!-- LATIN CAPITAL LETTER A WITH ACUTE -->
-      <map code="0x301" name="acutecomb"/><!-- COMBINING ACUTE ACCENT -->
-    </cmap_format_4>
-  </cmap>
-
-  <loca>
-    <!-- The 'loca' table will be calculated by the compiler -->
-  </loca>
-
-  <glyf>
-
-    <!-- The xMin, yMin, xMax and yMax values
-         will be recalculated by the compiler. -->
-
-    <TTGlyph name=".notdef" xMin="50" yMin="-200" xMax="450" yMax="800">
-      <contour>
-        <pt x="50" y="-200" on="1"/>
-        <pt x="50" y="800" on="1"/>
-        <pt x="450" y="800" on="1"/>
-        <pt x="450" y="-200" on="1"/>
-      </contour>
-      <contour>
-        <pt x="100" y="-150" on="1"/>
-        <pt x="400" y="-150" on="1"/>
-        <pt x="400" y="750" on="1"/>
-        <pt x="100" y="750" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="A" xMin="5" yMin="0" xMax="751" yMax="700">
-      <contour>
-        <pt x="641" y="0" on="1"/>
-        <pt x="751" y="0" on="1"/>
-        <pt x="433" y="700" on="1"/>
-        <pt x="323" y="700" on="1"/>
-      </contour>
-      <contour>
-        <pt x="5" y="0" on="1"/>
-        <pt x="115" y="0" on="1"/>
-        <pt x="433" y="700" on="1"/>
-        <pt x="323" y="700" on="1"/>
-      </contour>
-      <contour>
-        <pt x="567" y="284" on="1"/>
-        <pt x="152" y="284" on="1"/>
-        <pt x="152" y="204" on="1"/>
-        <pt x="567" y="204" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="Aacute" xMin="5" yMin="0" xMax="751" yMax="915">
-      <component glyphName="A" x="0" y="0" flags="0x204"/>
-      <component glyphName="acutecomb" x="402" y="130" flags="0x4"/>
-    </TTGlyph>
-
-    <TTGlyph name="O" xMin="30" yMin="-10" xMax="634" yMax="710">
-      <contour>
-        <pt x="332" y="-10" on="1"/>
-        <pt x="181" y="-10" on="0"/>
-        <pt x="30" y="169" on="0"/>
-        <pt x="30" y="350" on="1"/>
-        <pt x="30" y="531" on="0"/>
-        <pt x="181" y="710" on="0"/>
-        <pt x="332" y="710" on="1"/>
-        <pt x="484" y="710" on="0"/>
-        <pt x="634" y="531" on="0"/>
-        <pt x="634" y="350" on="1"/>
-        <pt x="634" y="169" on="0"/>
-        <pt x="484" y="-10" on="0"/>
-      </contour>
-      <contour>
-        <pt x="332" y="74" on="1"/>
-        <pt x="438" y="74" on="0"/>
-        <pt x="544" y="212" on="0"/>
-        <pt x="544" y="350" on="1"/>
-        <pt x="544" y="488" on="0"/>
-        <pt x="438" y="626" on="0"/>
-        <pt x="332" y="626" on="1"/>
-        <pt x="226" y="626" on="0"/>
-        <pt x="120" y="488" on="0"/>
-        <pt x="120" y="350" on="1"/>
-        <pt x="120" y="212" on="0"/>
-        <pt x="226" y="74" on="0"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="V" xMin="5" yMin="0" xMax="751" yMax="700">
-      <contour>
-        <pt x="323" y="0" on="1"/>
-        <pt x="641" y="700" on="1"/>
-        <pt x="751" y="700" on="1"/>
-        <pt x="433" y="0" on="1"/>
-      </contour>
-      <contour>
-        <pt x="323" y="0" on="1"/>
-        <pt x="5" y="700" on="1"/>
-        <pt x="115" y="700" on="1"/>
-        <pt x="433" y="0" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="acutecomb" xMin="-141" yMin="630" xMax="125" yMax="785">
-      <contour>
-        <pt x="-118" y="716" on="1"/>
-        <pt x="-141" y="630" on="1"/>
-        <pt x="102" y="699" on="1"/>
-        <pt x="125" y="785" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="dollar" xMin="29" yMin="-68" xMax="580" yMax="759">
-      <contour>
-        <pt x="264" y="759" on="1"/>
-        <pt x="354" y="759" on="1"/>
-        <pt x="354" y="715" on="1"/>
-        <pt x="415" y="709" on="0"/>
-        <pt x="519" y="662" on="0"/>
-        <pt x="562" y="620" on="1"/>
-        <pt x="509" y="548" on="1"/>
-        <pt x="473" y="584" on="0"/>
-        <pt x="398" y="621" on="0"/>
-        <pt x="354" y="627" on="1"/>
-        <pt x="354" y="373" on="1"/>
-        <pt x="467" y="351" on="0"/>
-        <pt x="580" y="263" on="0"/>
-        <pt x="580" y="184" on="1"/>
-        <pt x="580" y="102" on="0"/>
-        <pt x="459" y="-8" on="0"/>
-        <pt x="354" y="-18" on="1"/>
-        <pt x="354" y="-68" on="1"/>
-        <pt x="264" y="-68" on="1"/>
-        <pt x="264" y="-18" on="1"/>
-        <pt x="192" y="-12" on="0"/>
-        <pt x="72" y="34" on="0"/>
-        <pt x="29" y="74" on="1"/>
-        <pt x="81" y="146" on="1"/>
-        <pt x="123" y="110" on="0"/>
-        <pt x="207" y="73" on="0"/>
-        <pt x="264" y="69" on="1"/>
-        <pt x="264" y="301" on="1"/>
-        <pt x="249" y="304" on="1"/>
-        <pt x="148" y="323" on="0"/>
-        <pt x="43" y="420" on="0"/>
-        <pt x="43" y="502" on="1"/>
-        <pt x="43" y="559" on="0"/>
-        <pt x="99" y="650" on="0"/>
-        <pt x="199" y="707" on="0"/>
-        <pt x="264" y="715" on="1"/>
-      </contour>
-      <contour>
-        <pt x="137" y="502" on="1"/>
-        <pt x="137" y="470" on="0"/>
-        <pt x="160" y="428" on="0"/>
-        <pt x="214" y="402" on="0"/>
-        <pt x="261" y="392" on="1"/>
-        <pt x="264" y="627" on="1"/>
-        <pt x="203" y="618" on="0"/>
-        <pt x="137" y="553" on="0"/>
-      </contour>
-      <contour>
-        <pt x="354" y="69" on="1"/>
-        <pt x="423" y="76" on="0"/>
-        <pt x="486" y="135" on="0"/>
-        <pt x="486" y="183" on="1"/>
-        <pt x="486" y="211" on="0"/>
-        <pt x="462" y="250" on="0"/>
-        <pt x="405" y="275" on="0"/>
-        <pt x="354" y="285" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="dollar.BRACKET.500" xMin="29" yMin="-76" xMax="580" yMax="759">
-      <contour>
-        <pt x="264" y="759" on="1"/>
-        <pt x="354" y="759" on="1"/>
-        <pt x="354" y="715" on="1"/>
-        <pt x="415" y="709" on="0"/>
-        <pt x="519" y="662" on="0"/>
-        <pt x="562" y="620" on="1"/>
-        <pt x="509" y="548" on="1"/>
-        <pt x="464" y="592" on="0"/>
-        <pt x="370" y="630" on="0"/>
-        <pt x="308" y="630" on="1"/>
-        <pt x="226" y="630" on="0"/>
-        <pt x="137" y="562" on="0"/>
-        <pt x="137" y="502" on="1"/>
-        <pt x="137" y="470" on="0"/>
-        <pt x="160" y="428" on="0"/>
-        <pt x="214" y="402" on="0"/>
-        <pt x="261" y="392" on="1"/>
-        <pt x="360" y="372" on="1"/>
-        <pt x="469" y="350" on="0"/>
-        <pt x="580" y="263" on="0"/>
-        <pt x="580" y="184" on="1"/>
-        <pt x="580" y="102" on="0"/>
-        <pt x="459" y="-8" on="0"/>
-        <pt x="354" y="-18" on="1"/>
-        <pt x="354" y="-76" on="1"/>
-        <pt x="264" y="-76" on="1"/>
-        <pt x="264" y="-18" on="1"/>
-        <pt x="192" y="-12" on="0"/>
-        <pt x="72" y="34" on="0"/>
-        <pt x="29" y="74" on="1"/>
-        <pt x="81" y="146" on="1"/>
-        <pt x="115" y="118" on="0"/>
-        <pt x="180" y="83" on="0"/>
-        <pt x="259" y="67" on="0"/>
-        <pt x="310" y="67" on="1"/>
-        <pt x="403" y="67" on="0"/>
-        <pt x="486" y="128" on="0"/>
-        <pt x="486" y="183" on="1"/>
-        <pt x="486" y="212" on="0"/>
-        <pt x="461" y="251" on="0"/>
-        <pt x="401" y="277" on="0"/>
-        <pt x="348" y="286" on="1"/>
-        <pt x="249" y="304" on="1"/>
-        <pt x="148" y="323" on="0"/>
-        <pt x="43" y="420" on="0"/>
-        <pt x="43" y="502" on="1"/>
-        <pt x="43" y="559" on="0"/>
-        <pt x="99" y="650" on="0"/>
-        <pt x="199" y="707" on="0"/>
-        <pt x="264" y="715" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="dollar.bold" xMin="29" yMin="-76" xMax="580" yMax="759">
-      <contour>
-        <pt x="264" y="759" on="1"/>
-        <pt x="354" y="759" on="1"/>
-        <pt x="354" y="715" on="1"/>
-        <pt x="415" y="709" on="0"/>
-        <pt x="519" y="662" on="0"/>
-        <pt x="562" y="620" on="1"/>
-        <pt x="509" y="548" on="1"/>
-        <pt x="464" y="592" on="0"/>
-        <pt x="370" y="630" on="0"/>
-        <pt x="308" y="630" on="1"/>
-        <pt x="226" y="630" on="0"/>
-        <pt x="137" y="562" on="0"/>
-        <pt x="137" y="502" on="1"/>
-        <pt x="137" y="470" on="0"/>
-        <pt x="160" y="428" on="0"/>
-        <pt x="214" y="402" on="0"/>
-        <pt x="261" y="392" on="1"/>
-        <pt x="360" y="372" on="1"/>
-        <pt x="469" y="350" on="0"/>
-        <pt x="580" y="263" on="0"/>
-        <pt x="580" y="184" on="1"/>
-        <pt x="580" y="102" on="0"/>
-        <pt x="459" y="-8" on="0"/>
-        <pt x="354" y="-18" on="1"/>
-        <pt x="354" y="-76" on="1"/>
-        <pt x="264" y="-76" on="1"/>
-        <pt x="264" y="-18" on="1"/>
-        <pt x="192" y="-12" on="0"/>
-        <pt x="72" y="34" on="0"/>
-        <pt x="29" y="74" on="1"/>
-        <pt x="81" y="146" on="1"/>
-        <pt x="115" y="118" on="0"/>
-        <pt x="180" y="83" on="0"/>
-        <pt x="259" y="67" on="0"/>
-        <pt x="310" y="67" on="1"/>
-        <pt x="403" y="67" on="0"/>
-        <pt x="486" y="128" on="0"/>
-        <pt x="486" y="183" on="1"/>
-        <pt x="486" y="212" on="0"/>
-        <pt x="461" y="251" on="0"/>
-        <pt x="401" y="277" on="0"/>
-        <pt x="348" y="286" on="1"/>
-        <pt x="249" y="304" on="1"/>
-        <pt x="148" y="323" on="0"/>
-        <pt x="43" y="420" on="0"/>
-        <pt x="43" y="502" on="1"/>
-        <pt x="43" y="559" on="0"/>
-        <pt x="99" y="650" on="0"/>
-        <pt x="199" y="707" on="0"/>
-        <pt x="264" y="715" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="space"/><!-- contains no outline data -->
-
-  </glyf>
-
-  <name>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      Simple Two Axis
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      1.000;NONE;SimpleTwoAxis-Regular
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      Simple Two Axis Regular
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version 1.000
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      SimpleTwoAxis-Regular
-    </namerecord>
-  </name>
-
-  <post>
-    <formatType value="2.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-100"/>
-    <underlineThickness value="50"/>
-    <isFixedPitch value="0"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="0"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="0"/>
-    <psNames>
-      <!-- This file uses unique glyph names based on the information
-           found in the 'post' table. Since these names might not be unique,
-           we have to invent artificial names in case of clashes. In order to
-           be able to retain the original information, we need a name to
-           ps name mapping for those cases where they differ. That's what
-           you see below.
-            -->
-    </psNames>
-    <extraNames>
-      <!-- following are the name that are not taken from the standard Mac glyph order -->
-      <psName name="dollar.bold"/>
-      <psName name="acutecomb"/>
-      <psName name="dollar.BRACKET.500"/>
-    </extraNames>
-  </post>
-
-  <GDEF>
-    <Version value="0x00010000"/>
-    <GlyphClassDef>
-      <ClassDef glyph="A" class="1"/>
-      <ClassDef glyph="Aacute" class="1"/>
-      <ClassDef glyph="acutecomb" class="3"/>
-    </GlyphClassDef>
-  </GDEF>
-
-  <GPOS>
-    <Version value="0x00010000"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=2 -->
-            <FeatureIndex index="0" value="0"/>
-            <FeatureIndex index="1" value="1"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=2 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="kern"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="0"/>
-        </Feature>
-      </FeatureRecord>
-      <FeatureRecord index="1">
-        <FeatureTag value="mark"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="1"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=2 -->
-      <Lookup index="0">
-        <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
-        <!-- SubTableCount=1 -->
-        <PairPos index="0" Format="1">
-          <Coverage>
-            <Glyph value="A"/>
-            <Glyph value="Aacute"/>
-            <Glyph value="V"/>
-          </Coverage>
-          <ValueFormat1 value="4"/>
-          <ValueFormat2 value="0"/>
-          <!-- PairSetCount=3 -->
-          <PairSet index="0">
-            <!-- PairValueCount=1 -->
-            <PairValueRecord index="0">
-              <SecondGlyph value="V"/>
-              <Value1 XAdvance="-80"/>
-            </PairValueRecord>
-          </PairSet>
-          <PairSet index="1">
-            <!-- PairValueCount=1 -->
-            <PairValueRecord index="0">
-              <SecondGlyph value="V"/>
-              <Value1 XAdvance="-80"/>
-            </PairValueRecord>
-          </PairSet>
-          <PairSet index="2">
-            <!-- PairValueCount=1 -->
-            <PairValueRecord index="0">
-              <SecondGlyph value="O"/>
-              <Value1 XAdvance="-20"/>
-            </PairValueRecord>
-          </PairSet>
-        </PairPos>
-      </Lookup>
-      <Lookup index="1">
-        <LookupType value="4"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <MarkBasePos index="0" Format="1">
-          <MarkCoverage>
-            <Glyph value="acutecomb"/>
-          </MarkCoverage>
-          <BaseCoverage>
-            <Glyph value="A"/>
-            <Glyph value="Aacute"/>
-          </BaseCoverage>
-          <!-- ClassCount=1 -->
-          <MarkArray>
-            <!-- MarkCount=1 -->
-            <MarkRecord index="0">
-              <Class value="0"/>
-              <MarkAnchor Format="1">
-                <XCoordinate value="4"/>
-                <YCoordinate value="623"/>
-              </MarkAnchor>
-            </MarkRecord>
-          </MarkArray>
-          <BaseArray>
-            <!-- BaseCount=2 -->
-            <BaseRecord index="0">
-              <BaseAnchor index="0" Format="3">
-                <XCoordinate value="406"/>
-                <YCoordinate value="753"/>
-              </BaseAnchor>
-            </BaseRecord>
-            <BaseRecord index="1">
-              <BaseAnchor index="0" Format="1">
-                <XCoordinate value="406"/>
-                <YCoordinate value="753"/>
-              </BaseAnchor>
-            </BaseRecord>
-          </BaseArray>
-        </MarkBasePos>
-      </Lookup>
-    </LookupList>
-  </GPOS>
-
-</ttFont>
diff --git a/Tests/varLib/data/master_kerning_merging/0.ttx b/Tests/varLib/data/master_kerning_merging/0.ttx
index 1ca22f6..858f927 100644
--- a/Tests/varLib/data/master_kerning_merging/0.ttx
+++ b/Tests/varLib/data/master_kerning_merging/0.ttx
@@ -263,19 +263,19 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
             <Glyph value="B"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="1">
             <ClassDef glyph="A" class="1"/>
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="1">
             <ClassDef glyph="C" class="1"/>
           </ClassDef2>
           <!-- Class1Count=2 -->
diff --git a/Tests/varLib/data/master_kerning_merging/1.ttx b/Tests/varLib/data/master_kerning_merging/1.ttx
index 9f6756d..d60a708 100644
--- a/Tests/varLib/data/master_kerning_merging/1.ttx
+++ b/Tests/varLib/data/master_kerning_merging/1.ttx
@@ -257,17 +257,17 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="2">
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="1">
             <ClassDef glyph="B" class="2"/>
             <ClassDef glyph="D" class="1"/>
           </ClassDef2>
diff --git a/Tests/varLib/data/master_kerning_merging/2.ttx b/Tests/varLib/data/master_kerning_merging/2.ttx
index b8302e8..e01a7b1 100644
--- a/Tests/varLib/data/master_kerning_merging/2.ttx
+++ b/Tests/varLib/data/master_kerning_merging/2.ttx
@@ -263,19 +263,19 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
             <Glyph value="B"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="1">
             <ClassDef glyph="A" class="1"/>
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="1">
             <ClassDef glyph="D" class="1"/>
           </ClassDef2>
           <!-- Class1Count=2 -->
diff --git a/Tests/varLib/data/master_ttx_interpolatable_otf/TestFamily2-Master0.ttx b/Tests/varLib/data/master_ttx_interpolatable_otf/TestFamily2-Master0.ttx
index 157043f..a6a8e00 100644
--- a/Tests/varLib/data/master_ttx_interpolatable_otf/TestFamily2-Master0.ttx
+++ b/Tests/varLib/data/master_ttx_interpolatable_otf/TestFamily2-Master0.ttx
@@ -766,7 +766,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="A" out="A.sc"/>
         </SingleSubst>
       </Lookup>
@@ -774,7 +774,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="a" out="a.alt"/>
         </SingleSubst>
       </Lookup>
@@ -782,7 +782,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="ampersand" out="a,n,d"/>
         </MultipleSubst>
       </Lookup>
@@ -790,7 +790,7 @@
         <LookupType value="3"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <AlternateSubst index="0">
+        <AlternateSubst index="0" Format="1">
           <AlternateSet glyph="a">
             <Alternate glyph="a.alt"/>
             <Alternate glyph="A.sc"/>
@@ -801,7 +801,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="f">
             <Ligature components="t" glyph="f_t"/>
           </LigatureSet>
@@ -814,11 +814,11 @@
         <ChainContextSubst index="0" Format="3">
           <!-- BacktrackGlyphCount=0 -->
           <!-- InputGlyphCount=1 -->
-          <InputCoverage index="0">
+          <InputCoverage index="0" Format="1">
             <Glyph value="a"/>
           </InputCoverage>
           <!-- LookAheadGlyphCount=1 -->
-          <LookAheadCoverage index="0">
+          <LookAheadCoverage index="0" Format="1">
             <Glyph value="t"/>
           </LookAheadCoverage>
           <!-- SubstCount=1 -->
diff --git a/Tests/varLib/data/master_ttx_interpolatable_ttf/SparseMasters-Bold.ttx b/Tests/varLib/data/master_ttx_interpolatable_ttf/SparseMasters-Bold.ttx
index cf4b5da..55d686e 100644
--- a/Tests/varLib/data/master_ttx_interpolatable_ttf/SparseMasters-Bold.ttx
+++ b/Tests/varLib/data/master_ttx_interpolatable_ttf/SparseMasters-Bold.ttx
@@ -305,7 +305,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="1">
       <ClassDef glyph="dotabovecomb" class="3"/>
       <ClassDef glyph="e" class="1"/>
     </GlyphClassDef>
@@ -344,10 +344,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <MarkBasePos index="0" Format="1">
-          <MarkCoverage>
+          <MarkCoverage Format="1">
             <Glyph value="dotabovecomb"/>
           </MarkCoverage>
-          <BaseCoverage>
+          <BaseCoverage Format="1">
             <Glyph value="e"/>
           </BaseCoverage>
           <!-- ClassCount=1 -->
@@ -407,7 +407,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="a">
             <Ligature components="e,s,s" glyph="s"/>
           </LigatureSet>
diff --git a/Tests/varLib/data/master_ttx_interpolatable_ttf/SparseMasters-Regular.ttx b/Tests/varLib/data/master_ttx_interpolatable_ttf/SparseMasters-Regular.ttx
index c93da2a..e013e0b 100644
--- a/Tests/varLib/data/master_ttx_interpolatable_ttf/SparseMasters-Regular.ttx
+++ b/Tests/varLib/data/master_ttx_interpolatable_ttf/SparseMasters-Regular.ttx
@@ -305,7 +305,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="1">
       <ClassDef glyph="dotabovecomb" class="3"/>
       <ClassDef glyph="e" class="1"/>
     </GlyphClassDef>
@@ -344,10 +344,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <MarkBasePos index="0" Format="1">
-          <MarkCoverage>
+          <MarkCoverage Format="1">
             <Glyph value="dotabovecomb"/>
           </MarkCoverage>
-          <BaseCoverage>
+          <BaseCoverage Format="1">
             <Glyph value="e"/>
           </BaseCoverage>
           <!-- ClassCount=1 -->
@@ -407,7 +407,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="a">
             <Ligature components="e,s,s" glyph="s"/>
           </LigatureSet>
diff --git a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master0.ttx b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master0.ttx
index ca5a2e1..6054e4b 100644
--- a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master0.ttx
+++ b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master0.ttx
@@ -519,7 +519,7 @@
 
   <GDEF>
     <Version value="0x00010003"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="uni0024" class="1"/>
       <ClassDef glyph="uni0024.nostroke" class="1"/>
       <ClassDef glyph="uni0041" class="1"/>
diff --git a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master1.ttx b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master1.ttx
index 9076cf7..afd61de 100644
--- a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master1.ttx
+++ b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master1.ttx
@@ -519,7 +519,7 @@
 
   <GDEF>
     <Version value="0x00010003"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="uni0024" class="1"/>
       <ClassDef glyph="uni0024.nostroke" class="1"/>
       <ClassDef glyph="uni0041" class="1"/>
diff --git a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master2.ttx b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master2.ttx
index 9bec8c0..0ed2f4a 100644
--- a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master2.ttx
+++ b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master2.ttx
@@ -503,7 +503,7 @@
 
   <GDEF>
     <Version value="0x00010003"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="uni0024" class="1"/>
       <ClassDef glyph="uni0024.nostroke" class="1"/>
       <ClassDef glyph="uni0041" class="1"/>
diff --git a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master3.ttx b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master3.ttx
index 1cfdfd9..5666541 100644
--- a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master3.ttx
+++ b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master3.ttx
@@ -503,7 +503,7 @@
 
   <GDEF>
     <Version value="0x00010003"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="uni0024" class="1"/>
       <ClassDef glyph="uni0024.nostroke" class="1"/>
       <ClassDef glyph="uni0041" class="1"/>
diff --git a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master4.ttx b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master4.ttx
index 1ae5d47..8738187 100644
--- a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master4.ttx
+++ b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily-Master4.ttx
@@ -503,7 +503,7 @@
 
   <GDEF>
     <Version value="0x00010003"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="uni0024" class="1"/>
       <ClassDef glyph="uni0024.nostroke" class="1"/>
       <ClassDef glyph="uni0041" class="1"/>
diff --git a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily2-Master0.ttx b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily2-Master0.ttx
index d1a3393..13d48e7 100644
--- a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily2-Master0.ttx
+++ b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily2-Master0.ttx
@@ -1081,7 +1081,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="A" out="A.sc"/>
         </SingleSubst>
       </Lookup>
@@ -1089,7 +1089,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="a" out="a.alt"/>
         </SingleSubst>
       </Lookup>
@@ -1097,7 +1097,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="ampersand" out="a,n,d"/>
         </MultipleSubst>
       </Lookup>
@@ -1105,7 +1105,7 @@
         <LookupType value="3"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <AlternateSubst index="0">
+        <AlternateSubst index="0" Format="1">
           <AlternateSet glyph="a">
             <Alternate glyph="a.alt"/>
             <Alternate glyph="A.sc"/>
@@ -1116,7 +1116,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="f">
             <Ligature components="t" glyph="f_t"/>
           </LigatureSet>
@@ -1129,11 +1129,11 @@
         <ChainContextSubst index="0" Format="3">
           <!-- BacktrackGlyphCount=0 -->
           <!-- InputGlyphCount=1 -->
-          <InputCoverage index="0">
+          <InputCoverage index="0" Format="1">
             <Glyph value="a"/>
           </InputCoverage>
           <!-- LookAheadGlyphCount=1 -->
-          <LookAheadCoverage index="0">
+          <LookAheadCoverage index="0" Format="1">
             <Glyph value="t"/>
           </LookAheadCoverage>
           <!-- SubstCount=1 -->
diff --git a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-Bold.ttx b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-Bold.ttx
index 0f9e97a..a752bc1 100644
--- a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-Bold.ttx
+++ b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-Bold.ttx
@@ -477,17 +477,17 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="T"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="2">
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="1">
             <ClassDef glyph="T" class="4"/>
             <ClassDef glyph="n" class="3"/>
             <ClassDef glyph="o" class="2"/>
diff --git a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-Condensed.ttx b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-Condensed.ttx
index f8ff987..db0372a 100644
--- a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-Condensed.ttx
+++ b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-Condensed.ttx
@@ -483,17 +483,17 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="T"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="2">
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="1">
             <ClassDef glyph="T" class="4"/>
             <ClassDef glyph="n" class="3"/>
             <ClassDef glyph="o" class="2"/>
diff --git a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-CondensedBold.ttx b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-CondensedBold.ttx
index 2b7264d..3313ce6 100644
--- a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-CondensedBold.ttx
+++ b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-CondensedBold.ttx
@@ -483,17 +483,17 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="T"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="2">
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="1">
             <ClassDef glyph="T" class="4"/>
             <ClassDef glyph="n" class="3"/>
             <ClassDef glyph="o" class="2"/>
diff --git a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-CondensedLight.ttx b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-CondensedLight.ttx
index d03abf5..c83912b 100644
--- a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-CondensedLight.ttx
+++ b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-CondensedLight.ttx
@@ -483,17 +483,17 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="T"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="2">
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="1">
             <ClassDef glyph="T" class="4"/>
             <ClassDef glyph="n" class="3"/>
             <ClassDef glyph="o" class="2"/>
diff --git a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-CondensedSemiBold.ttx b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-CondensedSemiBold.ttx
index 1189220..7b0c88f 100644
--- a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-CondensedSemiBold.ttx
+++ b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-CondensedSemiBold.ttx
@@ -483,17 +483,17 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="T"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="2">
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="1">
             <ClassDef glyph="T" class="4"/>
             <ClassDef glyph="n" class="3"/>
             <ClassDef glyph="o" class="2"/>
diff --git a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-Light.ttx b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-Light.ttx
index 3583c0d..0e84719 100644
--- a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-Light.ttx
+++ b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-Light.ttx
@@ -483,17 +483,17 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="T"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="2">
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="1">
             <ClassDef glyph="T" class="4"/>
             <ClassDef glyph="n" class="3"/>
             <ClassDef glyph="o" class="2"/>
diff --git a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-Regular.ttx b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-Regular.ttx
index bf68b16..44848db 100644
--- a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-Regular.ttx
+++ b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-Regular.ttx
@@ -477,17 +477,17 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="T"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="2">
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="1">
             <ClassDef glyph="T" class="4"/>
             <ClassDef glyph="n" class="3"/>
             <ClassDef glyph="o" class="2"/>
diff --git a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-SemiBold.ttx b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-SemiBold.ttx
index 96badb3..7e6a0b3 100644
--- a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-SemiBold.ttx
+++ b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily3-SemiBold.ttx
@@ -483,17 +483,17 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="T"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="2">
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="1">
             <ClassDef glyph="T" class="4"/>
             <ClassDef glyph="n" class="3"/>
             <ClassDef glyph="o" class="2"/>
diff --git a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily4-Italic15.ttx b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily4-Italic15.ttx
index ab5789e..f7aa15f 100644
--- a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily4-Italic15.ttx
+++ b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily4-Italic15.ttx
@@ -455,7 +455,7 @@
 
   <GDEF>
     <Version value="0x00010002"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="N" class="1"/>
       <ClassDef glyph="O" class="1"/>
       <ClassDef glyph="Odieresis" class="1"/>
@@ -467,7 +467,7 @@
     <MarkGlyphSetsDef>
       <MarkSetTableFormat value="1"/>
       <!-- MarkSetCount=1 -->
-      <Coverage index="0">
+      <Coverage index="0" Format="1">
         <Glyph value="uni0308"/>
       </Coverage>
     </MarkGlyphSetsDef>
@@ -545,7 +545,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="N"/>
             <Glyph value="O"/>
             <Glyph value="Odieresis"/>
@@ -559,10 +559,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <MarkBasePos index="0" Format="1">
-          <MarkCoverage>
+          <MarkCoverage Format="1">
             <Glyph value="uni0308"/>
           </MarkCoverage>
-          <BaseCoverage>
+          <BaseCoverage Format="2">
             <Glyph value="N"/>
             <Glyph value="O"/>
             <Glyph value="Odieresis"/>
@@ -624,13 +624,13 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="6"/>
-        <LookupFlag value="16"/><!-- useMarkFilteringSet -->
+        <LookupFlag value="16"/>
         <!-- SubTableCount=1 -->
         <MarkMarkPos index="0" Format="1">
-          <Mark1Coverage>
+          <Mark1Coverage Format="1">
             <Glyph value="uni0308"/>
           </Mark1Coverage>
-          <Mark2Coverage>
+          <Mark2Coverage Format="1">
             <Glyph value="uni0308"/>
           </Mark2Coverage>
           <!-- ClassCount=1 -->
diff --git a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily4-Regular.ttx b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily4-Regular.ttx
index 0b7063f..2e354b0 100644
--- a/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily4-Regular.ttx
+++ b/Tests/varLib/data/master_ttx_interpolatable_ttf/TestFamily4-Regular.ttx
@@ -449,7 +449,7 @@
 
   <GDEF>
     <Version value="0x00010002"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="N" class="1"/>
       <ClassDef glyph="O" class="1"/>
       <ClassDef glyph="Odieresis" class="1"/>
@@ -461,7 +461,7 @@
     <MarkGlyphSetsDef>
       <MarkSetTableFormat value="1"/>
       <!-- MarkSetCount=1 -->
-      <Coverage index="0">
+      <Coverage index="0" Format="1">
         <Glyph value="uni0308"/>
       </Coverage>
     </MarkGlyphSetsDef>
@@ -539,7 +539,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="N"/>
             <Glyph value="O"/>
             <Glyph value="Odieresis"/>
@@ -553,10 +553,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <MarkBasePos index="0" Format="1">
-          <MarkCoverage>
+          <MarkCoverage Format="1">
             <Glyph value="uni0308"/>
           </MarkCoverage>
-          <BaseCoverage>
+          <BaseCoverage Format="2">
             <Glyph value="N"/>
             <Glyph value="O"/>
             <Glyph value="Odieresis"/>
@@ -618,13 +618,13 @@
       </Lookup>
       <Lookup index="2">
         <LookupType value="6"/>
-        <LookupFlag value="16"/><!-- useMarkFilteringSet -->
+        <LookupFlag value="16"/>
         <!-- SubTableCount=1 -->
         <MarkMarkPos index="0" Format="1">
-          <Mark1Coverage>
+          <Mark1Coverage Format="1">
             <Glyph value="uni0308"/>
           </Mark1Coverage>
-          <Mark2Coverage>
+          <Mark2Coverage Format="1">
             <Glyph value="uni0308"/>
           </Mark2Coverage>
           <!-- ClassCount=1 -->
diff --git a/Tests/varLib/data/master_ttx_varfont_otf/TestCFF2VF.ttx b/Tests/varLib/data/master_ttx_varfont_otf/TestCFF2VF.ttx
index 29c5bb3..c2a718e 100644
--- a/Tests/varLib/data/master_ttx_varfont_otf/TestCFF2VF.ttx
+++ b/Tests/varLib/data/master_ttx_varfont_otf/TestCFF2VF.ttx
@@ -623,7 +623,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="dollar" out="glyph00003"/>
         </SingleSubst>
       </Lookup>
@@ -631,7 +631,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="dollar" out="glyph00003"/>
         </SingleSubst>
       </Lookup>
diff --git a/Tests/varLib/data/master_vpal_test/master_vpal_test_0.ttx b/Tests/varLib/data/master_vpal_test/master_vpal_test_0.ttx
index cd454b8..1fbb45d 100644
--- a/Tests/varLib/data/master_vpal_test/master_vpal_test_0.ttx
+++ b/Tests/varLib/data/master_vpal_test/master_vpal_test_0.ttx
@@ -424,7 +424,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=5 -->
         <SinglePos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="uni3001"/>
             <Glyph value="uniFF1A"/>
           </Coverage>
@@ -434,7 +434,7 @@
           <Value index="1" XPlacement="-250" XAdvance="-500"/>
         </SinglePos>
         <SinglePos index="1" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="uni30FB"/>
           </Coverage>
           <ValueFormat value="7"/>
@@ -442,7 +442,7 @@
           <Value index="0" XPlacement="-250" YPlacement="1" XAdvance="-500"/>
         </SinglePos>
         <SinglePos index="2" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="uni3073"/>
             <Glyph value="uni3074"/>
           </Coverage>
@@ -452,7 +452,7 @@
           <Value index="1" XAdvance="-30"/>
         </SinglePos>
         <SinglePos index="3" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="uni307B"/>
           </Coverage>
           <ValueFormat value="1"/>
@@ -460,7 +460,7 @@
           <Value index="0" XPlacement="11"/>
         </SinglePos>
         <SinglePos index="4" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="uniFF2D"/>
           </Coverage>
           <ValueFormat value="5"/>
diff --git a/Tests/varLib/data/master_vpal_test/master_vpal_test_1.ttx b/Tests/varLib/data/master_vpal_test/master_vpal_test_1.ttx
index e1b77c8..bb43958 100644
--- a/Tests/varLib/data/master_vpal_test/master_vpal_test_1.ttx
+++ b/Tests/varLib/data/master_vpal_test/master_vpal_test_1.ttx
@@ -424,7 +424,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=3 -->
         <SinglePos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="uni3001"/>
             <Glyph value="uni30FB"/>
             <Glyph value="uniFF1A"/>
@@ -436,7 +436,7 @@
           <Value index="2" XPlacement="-250" XAdvance="-500"/>
         </SinglePos>
         <SinglePos index="1" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="uni3073"/>
             <Glyph value="uni3074"/>
           </Coverage>
@@ -446,7 +446,7 @@
           <Value index="1" XAdvance="-30"/>
         </SinglePos>
         <SinglePos index="2" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="uniFF2D"/>
             <Glyph value="uni307B"/>
           </Coverage>
diff --git a/Tests/varLib/data/master_vvar_cff2/TestVVAR.0.ttx b/Tests/varLib/data/master_vvar_cff2/TestVVAR.0.ttx
index d956d8c..7383c17 100644
--- a/Tests/varLib/data/master_vvar_cff2/TestVVAR.0.ttx
+++ b/Tests/varLib/data/master_vvar_cff2/TestVVAR.0.ttx
@@ -705,7 +705,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="uni3042" out="c30843"/>
           <Substitution in="uni56FD" out="c32051"/>
           <Substitution in="uni6280" out="c31621"/>
@@ -718,7 +718,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="uni3042" out="c30843"/>
           <Substitution in="uni56FD" out="c32051"/>
           <Substitution in="uni6280" out="c31621"/>
diff --git a/Tests/varLib/data/master_vvar_cff2/TestVVAR.1.ttx b/Tests/varLib/data/master_vvar_cff2/TestVVAR.1.ttx
index 9f67749..f602097 100644
--- a/Tests/varLib/data/master_vvar_cff2/TestVVAR.1.ttx
+++ b/Tests/varLib/data/master_vvar_cff2/TestVVAR.1.ttx
@@ -705,7 +705,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="uni3042" out="c30843"/>
           <Substitution in="uni56FD" out="c32051"/>
           <Substitution in="uni6280" out="c31621"/>
@@ -718,7 +718,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="uni3042" out="c30843"/>
           <Substitution in="uni56FD" out="c32051"/>
           <Substitution in="uni6280" out="c31621"/>
diff --git a/Tests/varLib/data/test_results/Build.ttx b/Tests/varLib/data/test_results/Build.ttx
index c802bf3..6e9c6e3 100644
--- a/Tests/varLib/data/test_results/Build.ttx
+++ b/Tests/varLib/data/test_results/Build.ttx
@@ -3,7 +3,7 @@
 
   <GDEF>
     <Version value="0x00010003"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="uni0024" class="1"/>
       <ClassDef glyph="uni0024.nostroke" class="1"/>
       <ClassDef glyph="uni0041" class="1"/>
@@ -405,6 +405,509 @@
         <delta pt="3" x="0" y="0"/>
       </tuple>
     </glyphVariations>
+    <glyphVariations glyph="uni0041">
+      <tuple>
+        <coord axis="wght" value="-1.0"/>
+        <delta pt="0" x="7" y="0"/>
+        <delta pt="1" x="7" y="-20"/>
+        <delta pt="2" x="-6" y="-29"/>
+        <delta pt="3" x="-12" y="-29"/>
+        <delta pt="4" x="-25" y="-20"/>
+        <delta pt="5" x="-25" y="0"/>
+        <delta pt="6" x="14" y="0"/>
+        <delta pt="7" x="4" y="9"/>
+        <delta pt="8" x="-36" y="9"/>
+        <delta pt="9" x="-37" y="0"/>
+        <delta pt="10" x="24" y="0"/>
+        <delta pt="11" x="9" y="58"/>
+        <delta pt="12" x="3" y="68"/>
+        <delta pt="13" x="-4" y="0"/>
+        <delta pt="14" x="3" y="28"/>
+        <delta pt="15" x="-4" y="2"/>
+        <delta pt="16" x="4" y="2"/>
+        <delta pt="17" x="-4" y="28"/>
+        <delta pt="18" x="20" y="0"/>
+        <delta pt="19" x="20" y="-20"/>
+        <delta pt="20" x="14" y="-29"/>
+        <delta pt="21" x="8" y="-29"/>
+        <delta pt="22" x="-2" y="-20"/>
+        <delta pt="23" x="-2" y="0"/>
+        <delta pt="24" x="0" y="0"/>
+        <delta pt="25" x="-10" y="0"/>
+        <delta pt="26" x="0" y="0"/>
+        <delta pt="27" x="0" y="0"/>
+      </tuple>
+      <tuple>
+        <coord axis="wght" value="1.0"/>
+        <delta pt="0" x="5" y="0"/>
+        <delta pt="1" x="5" y="19"/>
+        <delta pt="2" x="9" y="19"/>
+        <delta pt="3" x="6" y="19"/>
+        <delta pt="4" x="-15" y="19"/>
+        <delta pt="5" x="-15" y="0"/>
+        <delta pt="6" x="-6" y="0"/>
+        <delta pt="7" x="-14" y="-23"/>
+        <delta pt="8" x="46" y="-23"/>
+        <delta pt="9" x="39" y="0"/>
+        <delta pt="10" x="-69" y="0"/>
+        <delta pt="11" x="-27" y="-86"/>
+        <delta pt="12" x="-7" y="-16"/>
+        <delta pt="13" x="11" y="0"/>
+        <delta pt="14" x="-2" y="-39"/>
+        <delta pt="15" x="-1" y="-22"/>
+        <delta pt="16" x="-1" y="-22"/>
+        <delta pt="17" x="8" y="-39"/>
+        <delta pt="18" x="-41" y="0"/>
+        <delta pt="19" x="-41" y="16"/>
+        <delta pt="20" x="-59" y="16"/>
+        <delta pt="21" x="6" y="16"/>
+        <delta pt="22" x="12" y="16"/>
+        <delta pt="23" x="12" y="0"/>
+        <delta pt="24" x="0" y="0"/>
+        <delta pt="25" x="17" y="0"/>
+        <delta pt="26" x="0" y="0"/>
+        <delta pt="27" x="0" y="0"/>
+      </tuple>
+      <tuple>
+        <coord axis="cntr" value="1.0"/>
+        <delta pt="0" x="2" y="0"/>
+        <delta pt="1" x="2" y="-9"/>
+        <delta pt="2" x="-4" y="-9"/>
+        <delta pt="3" x="-4" y="-9"/>
+        <delta pt="4" x="-2" y="-9"/>
+        <delta pt="5" x="-2" y="0"/>
+        <delta pt="6" x="2" y="0"/>
+        <delta pt="7" x="-4" y="0"/>
+        <delta pt="8" x="-4" y="0"/>
+        <delta pt="9" x="-4" y="0"/>
+        <delta pt="10" x="-4" y="0"/>
+        <delta pt="11" x="-6" y="8"/>
+        <delta pt="12" x="-10" y="0"/>
+        <delta pt="13" x="-2" y="0"/>
+        <delta pt="14" x="0" y="5"/>
+        <delta pt="15" x="-3" y="-5"/>
+        <delta pt="16" x="5" y="-5"/>
+        <delta pt="17" x="-1" y="5"/>
+        <delta pt="18" x="0" y="0"/>
+        <delta pt="19" x="0" y="-8"/>
+        <delta pt="20" x="4" y="-8"/>
+        <delta pt="21" x="0" y="-8"/>
+        <delta pt="22" x="0" y="-8"/>
+        <delta pt="23" x="0" y="0"/>
+        <delta pt="24" x="0" y="0"/>
+        <delta pt="25" x="0" y="0"/>
+        <delta pt="26" x="0" y="0"/>
+        <delta pt="27" x="0" y="0"/>
+      </tuple>
+      <tuple>
+        <coord axis="wght" value="-1.0"/>
+        <coord axis="cntr" value="1.0"/>
+        <delta pt="0" x="-2" y="0"/>
+        <delta pt="1" x="-2" y="9"/>
+        <delta pt="2" x="4" y="9"/>
+        <delta pt="3" x="4" y="9"/>
+        <delta pt="4" x="2" y="9"/>
+        <delta pt="5" x="2" y="0"/>
+        <delta pt="6" x="-2" y="0"/>
+        <delta pt="7" x="4" y="0"/>
+        <delta pt="8" x="4" y="0"/>
+        <delta pt="9" x="4" y="0"/>
+        <delta pt="10" x="4" y="0"/>
+        <delta pt="11" x="6" y="-8"/>
+        <delta pt="12" x="10" y="0"/>
+        <delta pt="13" x="2" y="0"/>
+        <delta pt="14" x="0" y="-5"/>
+        <delta pt="15" x="3" y="5"/>
+        <delta pt="16" x="-5" y="5"/>
+        <delta pt="17" x="1" y="-5"/>
+        <delta pt="18" x="0" y="0"/>
+        <delta pt="19" x="0" y="8"/>
+        <delta pt="20" x="-4" y="8"/>
+        <delta pt="21" x="0" y="8"/>
+        <delta pt="22" x="0" y="8"/>
+        <delta pt="23" x="0" y="0"/>
+        <delta pt="24" x="0" y="0"/>
+        <delta pt="25" x="0" y="0"/>
+        <delta pt="26" x="0" y="0"/>
+        <delta pt="27" x="0" y="0"/>
+      </tuple>
+      <tuple>
+        <coord axis="wght" value="1.0"/>
+        <coord axis="cntr" value="1.0"/>
+        <delta pt="0" x="3" y="0"/>
+        <delta pt="1" x="3" y="-15"/>
+        <delta pt="2" x="-6" y="-15"/>
+        <delta pt="3" x="-6" y="-15"/>
+        <delta pt="4" x="-3" y="-15"/>
+        <delta pt="5" x="-3" y="0"/>
+        <delta pt="6" x="3" y="0"/>
+        <delta pt="7" x="-6" y="0"/>
+        <delta pt="8" x="-6" y="0"/>
+        <delta pt="9" x="-6" y="0"/>
+        <delta pt="10" x="-6" y="0"/>
+        <delta pt="11" x="-11" y="13"/>
+        <delta pt="12" x="-17" y="0"/>
+        <delta pt="13" x="-3" y="0"/>
+        <delta pt="14" x="-1" y="8"/>
+        <delta pt="15" x="-5" y="-9"/>
+        <delta pt="16" x="8" y="-9"/>
+        <delta pt="17" x="-1" y="8"/>
+        <delta pt="18" x="0" y="0"/>
+        <delta pt="19" x="0" y="-13"/>
+        <delta pt="20" x="6" y="-13"/>
+        <delta pt="21" x="0" y="-13"/>
+        <delta pt="22" x="0" y="-13"/>
+        <delta pt="23" x="0" y="0"/>
+        <delta pt="24" x="0" y="0"/>
+        <delta pt="25" x="0" y="0"/>
+        <delta pt="26" x="0" y="0"/>
+        <delta pt="27" x="0" y="0"/>
+      </tuple>
+    </glyphVariations>
+    <glyphVariations glyph="uni0061">
+      <tuple>
+        <coord axis="wght" value="-1.0"/>
+        <delta pt="0" x="11" y="-8"/>
+        <delta pt="1" x="11" y="4"/>
+        <delta pt="2" x="22" y="5"/>
+        <delta pt="3" x="-4" y="-8"/>
+        <delta pt="4" x="6" y="-5"/>
+        <delta pt="5" x="3" y="-11"/>
+        <delta pt="6" x="4" y="-9"/>
+        <delta pt="7" x="4" y="9"/>
+        <delta pt="8" x="0" y="7"/>
+        <delta pt="9" x="-9" y="8"/>
+        <delta pt="10" x="-24" y="3"/>
+        <delta pt="11" x="-18" y="6"/>
+        <delta pt="12" x="-44" y="1"/>
+        <delta pt="13" x="-44" y="-16"/>
+        <delta pt="14" x="-44" y="-22"/>
+        <delta pt="15" x="-36" y="-39"/>
+        <delta pt="16" x="-24" y="-39"/>
+        <delta pt="17" x="-7" y="-39"/>
+        <delta pt="18" x="26" y="-15"/>
+        <delta pt="19" x="26" y="3"/>
+        <delta pt="20" x="17" y="0"/>
+        <delta pt="21" x="3" y="-4"/>
+        <delta pt="22" x="23" y="15"/>
+        <delta pt="23" x="22" y="8"/>
+        <delta pt="24" x="6" y="0"/>
+        <delta pt="25" x="0" y="0"/>
+        <delta pt="26" x="2" y="0"/>
+        <delta pt="27" x="11" y="-2"/>
+        <delta pt="28" x="30" y="7"/>
+        <delta pt="29" x="30" y="4"/>
+        <delta pt="30" x="30" y="13"/>
+        <delta pt="31" x="14" y="21"/>
+        <delta pt="32" x="3" y="21"/>
+        <delta pt="33" x="-15" y="21"/>
+        <delta pt="34" x="-32" y="5"/>
+        <delta pt="35" x="-34" y="-9"/>
+        <delta pt="36" x="-48" y="-14"/>
+        <delta pt="37" x="-40" y="4"/>
+        <delta pt="38" x="-36" y="14"/>
+        <delta pt="39" x="-24" y="27"/>
+        <delta pt="40" x="-13" y="27"/>
+        <delta pt="41" x="12" y="27"/>
+        <delta pt="42" x="10" y="6"/>
+        <delta pt="43" x="12" y="5"/>
+        <delta pt="44" x="-4" y="-4"/>
+        <delta pt="45" x="-16" y="-4"/>
+        <delta pt="46" x="-20" y="-4"/>
+        <delta pt="47" x="-22" y="7"/>
+        <delta pt="48" x="-22" y="25"/>
+        <delta pt="49" x="-22" y="10"/>
+        <delta pt="50" x="-22" y="-15"/>
+        <delta pt="51" x="-16" y="-30"/>
+        <delta pt="52" x="-9" y="-30"/>
+        <delta pt="53" x="-12" y="-30"/>
+        <delta pt="54" x="-11" y="-35"/>
+        <delta pt="55" x="-5" y="-35"/>
+        <delta pt="56" x="-15" y="-27"/>
+        <delta pt="57" x="-10" y="-3"/>
+        <delta pt="58" x="9" y="-3"/>
+        <delta pt="59" x="14" y="-3"/>
+        <delta pt="60" x="33" y="-1"/>
+        <delta pt="61" x="0" y="0"/>
+        <delta pt="62" x="-3" y="0"/>
+        <delta pt="63" x="0" y="0"/>
+        <delta pt="64" x="0" y="0"/>
+      </tuple>
+      <tuple>
+        <coord axis="wght" value="1.0"/>
+        <delta pt="0" x="-21" y="1"/>
+        <delta pt="1" x="-21" y="17"/>
+        <delta pt="2" x="-2" y="28"/>
+        <delta pt="3" x="20" y="23"/>
+        <delta pt="4" x="19" y="20"/>
+        <delta pt="5" x="28" y="21"/>
+        <delta pt="6" x="26" y="23"/>
+        <delta pt="7" x="26" y="15"/>
+        <delta pt="8" x="24" y="12"/>
+        <delta pt="9" x="30" y="17"/>
+        <delta pt="10" x="31" y="15"/>
+        <delta pt="11" x="77" y="31"/>
+        <delta pt="12" x="66" y="36"/>
+        <delta pt="13" x="66" y="18"/>
+        <delta pt="14" x="66" y="21"/>
+        <delta pt="15" x="49" y="19"/>
+        <delta pt="16" x="37" y="19"/>
+        <delta pt="17" x="21" y="19"/>
+        <delta pt="18" x="-2" y="5"/>
+        <delta pt="19" x="-34" y="-18"/>
+        <delta pt="20" x="-6" y="3"/>
+        <delta pt="21" x="-11" y="12"/>
+        <delta pt="22" x="-29" y="-11"/>
+        <delta pt="23" x="-17" y="-2"/>
+        <delta pt="24" x="-13" y="-3"/>
+        <delta pt="25" x="-25" y="-3"/>
+        <delta pt="26" x="-29" y="-3"/>
+        <delta pt="27" x="-21" y="2"/>
+        <delta pt="28" x="-34" y="-14"/>
+        <delta pt="29" x="-34" y="17"/>
+        <delta pt="30" x="-34" y="7"/>
+        <delta pt="31" x="-18" y="7"/>
+        <delta pt="32" x="-16" y="7"/>
+        <delta pt="33" x="-18" y="7"/>
+        <delta pt="34" x="-15" y="9"/>
+        <delta pt="35" x="-21" y="12"/>
+        <delta pt="36" x="19" y="23"/>
+        <delta pt="37" x="45" y="46"/>
+        <delta pt="38" x="52" y="7"/>
+        <delta pt="39" x="26" y="-21"/>
+        <delta pt="40" x="14" y="-21"/>
+        <delta pt="41" x="-5" y="-21"/>
+        <delta pt="42" x="-17" y="-7"/>
+        <delta pt="43" x="-31" y="1"/>
+        <delta pt="44" x="-12" y="16"/>
+        <delta pt="45" x="34" y="16"/>
+        <delta pt="46" x="61" y="16"/>
+        <delta pt="47" x="70" y="4"/>
+        <delta pt="48" x="70" y="-5"/>
+        <delta pt="49" x="70" y="-22"/>
+        <delta pt="50" x="70" y="4"/>
+        <delta pt="51" x="59" y="22"/>
+        <delta pt="52" x="50" y="22"/>
+        <delta pt="53" x="43" y="22"/>
+        <delta pt="54" x="37" y="19"/>
+        <delta pt="55" x="38" y="22"/>
+        <delta pt="56" x="47" y="28"/>
+        <delta pt="57" x="46" y="-6"/>
+        <delta pt="58" x="-2" y="-6"/>
+        <delta pt="59" x="-16" y="-6"/>
+        <delta pt="60" x="-25" y="-13"/>
+        <delta pt="61" x="0" y="0"/>
+        <delta pt="62" x="32" y="0"/>
+        <delta pt="63" x="0" y="0"/>
+        <delta pt="64" x="0" y="0"/>
+      </tuple>
+      <tuple>
+        <coord axis="cntr" value="1.0"/>
+        <delta pt="0" x="0" y="-3"/>
+        <delta pt="1" x="0" y="-1"/>
+        <delta pt="2" x="0" y="-3"/>
+        <delta pt="3" x="0" y="-3"/>
+        <delta pt="4" x="0" y="-3"/>
+        <delta pt="5" x="0" y="-3"/>
+        <delta pt="6" x="0" y="-3"/>
+        <delta pt="7" x="0" y="4"/>
+        <delta pt="8" x="0" y="4"/>
+        <delta pt="9" x="2" y="5"/>
+        <delta pt="10" x="6" y="7"/>
+        <delta pt="11" x="1" y="5"/>
+        <delta pt="12" x="0" y="-1"/>
+        <delta pt="13" x="0" y="-6"/>
+        <delta pt="14" x="0" y="-6"/>
+        <delta pt="15" x="-1" y="-6"/>
+        <delta pt="16" x="0" y="-6"/>
+        <delta pt="17" x="0" y="-6"/>
+        <delta pt="18" x="0" y="-5"/>
+        <delta pt="19" x="0" y="-4"/>
+        <delta pt="20" x="0" y="-1"/>
+        <delta pt="21" x="0" y="0"/>
+        <delta pt="22" x="0" y="0"/>
+        <delta pt="23" x="0" y="0"/>
+        <delta pt="24" x="0" y="0"/>
+        <delta pt="25" x="0" y="0"/>
+        <delta pt="26" x="0" y="0"/>
+        <delta pt="27" x="0" y="-1"/>
+        <delta pt="28" x="0" y="-2"/>
+        <delta pt="29" x="0" y="7"/>
+        <delta pt="30" x="0" y="6"/>
+        <delta pt="31" x="0" y="7"/>
+        <delta pt="32" x="0" y="7"/>
+        <delta pt="33" x="0" y="7"/>
+        <delta pt="34" x="0" y="7"/>
+        <delta pt="35" x="0" y="7"/>
+        <delta pt="36" x="0" y="0"/>
+        <delta pt="37" x="0" y="0"/>
+        <delta pt="38" x="0" y="0"/>
+        <delta pt="39" x="0" y="0"/>
+        <delta pt="40" x="0" y="0"/>
+        <delta pt="41" x="0" y="0"/>
+        <delta pt="42" x="0" y="0"/>
+        <delta pt="43" x="0" y="0"/>
+        <delta pt="44" x="0" y="0"/>
+        <delta pt="45" x="0" y="0"/>
+        <delta pt="46" x="0" y="0"/>
+        <delta pt="47" x="0" y="0"/>
+        <delta pt="48" x="0" y="0"/>
+        <delta pt="49" x="0" y="-6"/>
+        <delta pt="50" x="0" y="-7"/>
+        <delta pt="51" x="0" y="-8"/>
+        <delta pt="52" x="0" y="-8"/>
+        <delta pt="53" x="1" y="-8"/>
+        <delta pt="54" x="2" y="-5"/>
+        <delta pt="55" x="4" y="-2"/>
+        <delta pt="56" x="0" y="0"/>
+        <delta pt="57" x="0" y="0"/>
+        <delta pt="58" x="0" y="0"/>
+        <delta pt="59" x="0" y="0"/>
+        <delta pt="60" x="0" y="-1"/>
+        <delta pt="61" x="0" y="0"/>
+        <delta pt="62" x="0" y="0"/>
+        <delta pt="63" x="0" y="0"/>
+        <delta pt="64" x="0" y="0"/>
+      </tuple>
+      <tuple>
+        <coord axis="wght" value="-1.0"/>
+        <coord axis="cntr" value="1.0"/>
+        <delta pt="0" x="0" y="3"/>
+        <delta pt="1" x="0" y="1"/>
+        <delta pt="2" x="0" y="3"/>
+        <delta pt="3" x="0" y="3"/>
+        <delta pt="4" x="0" y="3"/>
+        <delta pt="5" x="0" y="3"/>
+        <delta pt="6" x="0" y="3"/>
+        <delta pt="7" x="0" y="-4"/>
+        <delta pt="8" x="0" y="-4"/>
+        <delta pt="9" x="-2" y="-5"/>
+        <delta pt="10" x="-6" y="-7"/>
+        <delta pt="11" x="-1" y="-5"/>
+        <delta pt="12" x="0" y="1"/>
+        <delta pt="13" x="0" y="6"/>
+        <delta pt="14" x="0" y="6"/>
+        <delta pt="15" x="1" y="6"/>
+        <delta pt="16" x="0" y="6"/>
+        <delta pt="17" x="0" y="6"/>
+        <delta pt="18" x="0" y="5"/>
+        <delta pt="19" x="0" y="4"/>
+        <delta pt="20" x="0" y="1"/>
+        <delta pt="21" x="0" y="0"/>
+        <delta pt="22" x="0" y="0"/>
+        <delta pt="23" x="0" y="0"/>
+        <delta pt="24" x="0" y="0"/>
+        <delta pt="25" x="0" y="0"/>
+        <delta pt="26" x="0" y="0"/>
+        <delta pt="27" x="0" y="1"/>
+        <delta pt="28" x="0" y="2"/>
+        <delta pt="29" x="0" y="-7"/>
+        <delta pt="30" x="0" y="-6"/>
+        <delta pt="31" x="0" y="-7"/>
+        <delta pt="32" x="0" y="-7"/>
+        <delta pt="33" x="0" y="-7"/>
+        <delta pt="34" x="0" y="-7"/>
+        <delta pt="35" x="0" y="-7"/>
+        <delta pt="36" x="0" y="0"/>
+        <delta pt="37" x="0" y="0"/>
+        <delta pt="38" x="0" y="0"/>
+        <delta pt="39" x="0" y="0"/>
+        <delta pt="40" x="0" y="0"/>
+        <delta pt="41" x="0" y="0"/>
+        <delta pt="42" x="0" y="0"/>
+        <delta pt="43" x="0" y="0"/>
+        <delta pt="44" x="0" y="0"/>
+        <delta pt="45" x="0" y="0"/>
+        <delta pt="46" x="0" y="0"/>
+        <delta pt="47" x="0" y="0"/>
+        <delta pt="48" x="0" y="0"/>
+        <delta pt="49" x="0" y="6"/>
+        <delta pt="50" x="0" y="7"/>
+        <delta pt="51" x="0" y="8"/>
+        <delta pt="52" x="0" y="8"/>
+        <delta pt="53" x="-1" y="8"/>
+        <delta pt="54" x="-2" y="5"/>
+        <delta pt="55" x="-4" y="2"/>
+        <delta pt="56" x="0" y="0"/>
+        <delta pt="57" x="0" y="0"/>
+        <delta pt="58" x="0" y="0"/>
+        <delta pt="59" x="0" y="0"/>
+        <delta pt="60" x="0" y="1"/>
+        <delta pt="61" x="0" y="0"/>
+        <delta pt="62" x="0" y="0"/>
+        <delta pt="63" x="0" y="0"/>
+        <delta pt="64" x="0" y="0"/>
+      </tuple>
+      <tuple>
+        <coord axis="wght" value="1.0"/>
+        <coord axis="cntr" value="1.0"/>
+        <delta pt="0" x="0" y="-5"/>
+        <delta pt="1" x="0" y="0"/>
+        <delta pt="2" x="3" y="-4"/>
+        <delta pt="3" x="0" y="-4"/>
+        <delta pt="4" x="0" y="-4"/>
+        <delta pt="5" x="0" y="-4"/>
+        <delta pt="6" x="0" y="-4"/>
+        <delta pt="7" x="0" y="8"/>
+        <delta pt="8" x="0" y="8"/>
+        <delta pt="9" x="5" y="9"/>
+        <delta pt="10" x="11" y="13"/>
+        <delta pt="11" x="2" y="10"/>
+        <delta pt="12" x="0" y="0"/>
+        <delta pt="13" x="0" y="-9"/>
+        <delta pt="14" x="0" y="-9"/>
+        <delta pt="15" x="-1" y="-9"/>
+        <delta pt="16" x="0" y="-9"/>
+        <delta pt="17" x="0" y="-9"/>
+        <delta pt="18" x="0" y="-10"/>
+        <delta pt="19" x="0" y="-8"/>
+        <delta pt="20" x="0" y="-2"/>
+        <delta pt="21" x="0" y="1"/>
+        <delta pt="22" x="0" y="0"/>
+        <delta pt="23" x="1" y="-1"/>
+        <delta pt="24" x="0" y="0"/>
+        <delta pt="25" x="0" y="0"/>
+        <delta pt="26" x="0" y="0"/>
+        <delta pt="27" x="0" y="-1"/>
+        <delta pt="28" x="0" y="-4"/>
+        <delta pt="29" x="0" y="12"/>
+        <delta pt="30" x="0" y="13"/>
+        <delta pt="31" x="0" y="13"/>
+        <delta pt="32" x="0" y="13"/>
+        <delta pt="33" x="0" y="13"/>
+        <delta pt="34" x="0" y="13"/>
+        <delta pt="35" x="0" y="13"/>
+        <delta pt="36" x="0" y="0"/>
+        <delta pt="37" x="0" y="0"/>
+        <delta pt="38" x="0" y="0"/>
+        <delta pt="39" x="0" y="1"/>
+        <delta pt="40" x="0" y="1"/>
+        <delta pt="41" x="0" y="1"/>
+        <delta pt="42" x="0" y="1"/>
+        <delta pt="43" x="0" y="0"/>
+        <delta pt="44" x="0" y="0"/>
+        <delta pt="45" x="0" y="0"/>
+        <delta pt="46" x="0" y="0"/>
+        <delta pt="47" x="0" y="-1"/>
+        <delta pt="48" x="0" y="-1"/>
+        <delta pt="49" x="0" y="-9"/>
+        <delta pt="50" x="0" y="-13"/>
+        <delta pt="51" x="1" y="-14"/>
+        <delta pt="52" x="1" y="-14"/>
+        <delta pt="53" x="2" y="-14"/>
+        <delta pt="54" x="5" y="-11"/>
+        <delta pt="55" x="7" y="-4"/>
+        <delta pt="56" x="0" y="0"/>
+        <delta pt="57" x="0" y="0"/>
+        <delta pt="58" x="0" y="0"/>
+        <delta pt="59" x="0" y="0"/>
+        <delta pt="60" x="1" y="0"/>
+        <delta pt="61" x="0" y="0"/>
+        <delta pt="62" x="0" y="0"/>
+        <delta pt="63" x="0" y="0"/>
+        <delta pt="64" x="0" y="0"/>
+      </tuple>
+    </glyphVariations>
     <glyphVariations glyph="uni0024">
       <tuple>
         <coord axis="wght" value="-1.0"/>
@@ -1103,509 +1606,6 @@
         <delta pt="65" x="0" y="0"/>
       </tuple>
     </glyphVariations>
-    <glyphVariations glyph="uni0041">
-      <tuple>
-        <coord axis="wght" value="-1.0"/>
-        <delta pt="0" x="7" y="0"/>
-        <delta pt="1" x="7" y="-20"/>
-        <delta pt="2" x="-6" y="-29"/>
-        <delta pt="3" x="-12" y="-29"/>
-        <delta pt="4" x="-25" y="-20"/>
-        <delta pt="5" x="-25" y="0"/>
-        <delta pt="6" x="14" y="0"/>
-        <delta pt="7" x="4" y="9"/>
-        <delta pt="8" x="-36" y="9"/>
-        <delta pt="9" x="-37" y="0"/>
-        <delta pt="10" x="24" y="0"/>
-        <delta pt="11" x="9" y="58"/>
-        <delta pt="12" x="3" y="68"/>
-        <delta pt="13" x="-4" y="0"/>
-        <delta pt="14" x="3" y="28"/>
-        <delta pt="15" x="-4" y="2"/>
-        <delta pt="16" x="4" y="2"/>
-        <delta pt="17" x="-4" y="28"/>
-        <delta pt="18" x="20" y="0"/>
-        <delta pt="19" x="20" y="-20"/>
-        <delta pt="20" x="14" y="-29"/>
-        <delta pt="21" x="8" y="-29"/>
-        <delta pt="22" x="-2" y="-20"/>
-        <delta pt="23" x="-2" y="0"/>
-        <delta pt="24" x="0" y="0"/>
-        <delta pt="25" x="-10" y="0"/>
-        <delta pt="26" x="0" y="0"/>
-        <delta pt="27" x="0" y="0"/>
-      </tuple>
-      <tuple>
-        <coord axis="wght" value="1.0"/>
-        <delta pt="0" x="5" y="0"/>
-        <delta pt="1" x="5" y="19"/>
-        <delta pt="2" x="9" y="19"/>
-        <delta pt="3" x="6" y="19"/>
-        <delta pt="4" x="-15" y="19"/>
-        <delta pt="5" x="-15" y="0"/>
-        <delta pt="6" x="-6" y="0"/>
-        <delta pt="7" x="-14" y="-23"/>
-        <delta pt="8" x="46" y="-23"/>
-        <delta pt="9" x="39" y="0"/>
-        <delta pt="10" x="-69" y="0"/>
-        <delta pt="11" x="-27" y="-86"/>
-        <delta pt="12" x="-7" y="-16"/>
-        <delta pt="13" x="11" y="0"/>
-        <delta pt="14" x="-2" y="-39"/>
-        <delta pt="15" x="-1" y="-22"/>
-        <delta pt="16" x="-1" y="-22"/>
-        <delta pt="17" x="8" y="-39"/>
-        <delta pt="18" x="-41" y="0"/>
-        <delta pt="19" x="-41" y="16"/>
-        <delta pt="20" x="-59" y="16"/>
-        <delta pt="21" x="6" y="16"/>
-        <delta pt="22" x="12" y="16"/>
-        <delta pt="23" x="12" y="0"/>
-        <delta pt="24" x="0" y="0"/>
-        <delta pt="25" x="17" y="0"/>
-        <delta pt="26" x="0" y="0"/>
-        <delta pt="27" x="0" y="0"/>
-      </tuple>
-      <tuple>
-        <coord axis="cntr" value="1.0"/>
-        <delta pt="0" x="2" y="0"/>
-        <delta pt="1" x="2" y="-9"/>
-        <delta pt="2" x="-4" y="-9"/>
-        <delta pt="3" x="-4" y="-9"/>
-        <delta pt="4" x="-2" y="-9"/>
-        <delta pt="5" x="-2" y="0"/>
-        <delta pt="6" x="2" y="0"/>
-        <delta pt="7" x="-4" y="0"/>
-        <delta pt="8" x="-4" y="0"/>
-        <delta pt="9" x="-4" y="0"/>
-        <delta pt="10" x="-4" y="0"/>
-        <delta pt="11" x="-6" y="8"/>
-        <delta pt="12" x="-10" y="0"/>
-        <delta pt="13" x="-2" y="0"/>
-        <delta pt="14" x="0" y="5"/>
-        <delta pt="15" x="-3" y="-5"/>
-        <delta pt="16" x="5" y="-5"/>
-        <delta pt="17" x="-1" y="5"/>
-        <delta pt="18" x="0" y="0"/>
-        <delta pt="19" x="0" y="-8"/>
-        <delta pt="20" x="4" y="-8"/>
-        <delta pt="21" x="0" y="-8"/>
-        <delta pt="22" x="0" y="-8"/>
-        <delta pt="23" x="0" y="0"/>
-        <delta pt="24" x="0" y="0"/>
-        <delta pt="25" x="0" y="0"/>
-        <delta pt="26" x="0" y="0"/>
-        <delta pt="27" x="0" y="0"/>
-      </tuple>
-      <tuple>
-        <coord axis="wght" value="-1.0"/>
-        <coord axis="cntr" value="1.0"/>
-        <delta pt="0" x="-2" y="0"/>
-        <delta pt="1" x="-2" y="9"/>
-        <delta pt="2" x="4" y="9"/>
-        <delta pt="3" x="4" y="9"/>
-        <delta pt="4" x="2" y="9"/>
-        <delta pt="5" x="2" y="0"/>
-        <delta pt="6" x="-2" y="0"/>
-        <delta pt="7" x="4" y="0"/>
-        <delta pt="8" x="4" y="0"/>
-        <delta pt="9" x="4" y="0"/>
-        <delta pt="10" x="4" y="0"/>
-        <delta pt="11" x="6" y="-8"/>
-        <delta pt="12" x="10" y="0"/>
-        <delta pt="13" x="2" y="0"/>
-        <delta pt="14" x="0" y="-5"/>
-        <delta pt="15" x="3" y="5"/>
-        <delta pt="16" x="-5" y="5"/>
-        <delta pt="17" x="1" y="-5"/>
-        <delta pt="18" x="0" y="0"/>
-        <delta pt="19" x="0" y="8"/>
-        <delta pt="20" x="-4" y="8"/>
-        <delta pt="21" x="0" y="8"/>
-        <delta pt="22" x="0" y="8"/>
-        <delta pt="23" x="0" y="0"/>
-        <delta pt="24" x="0" y="0"/>
-        <delta pt="25" x="0" y="0"/>
-        <delta pt="26" x="0" y="0"/>
-        <delta pt="27" x="0" y="0"/>
-      </tuple>
-      <tuple>
-        <coord axis="wght" value="1.0"/>
-        <coord axis="cntr" value="1.0"/>
-        <delta pt="0" x="3" y="0"/>
-        <delta pt="1" x="3" y="-15"/>
-        <delta pt="2" x="-6" y="-15"/>
-        <delta pt="3" x="-6" y="-15"/>
-        <delta pt="4" x="-3" y="-15"/>
-        <delta pt="5" x="-3" y="0"/>
-        <delta pt="6" x="3" y="0"/>
-        <delta pt="7" x="-6" y="0"/>
-        <delta pt="8" x="-6" y="0"/>
-        <delta pt="9" x="-6" y="0"/>
-        <delta pt="10" x="-6" y="0"/>
-        <delta pt="11" x="-11" y="13"/>
-        <delta pt="12" x="-17" y="0"/>
-        <delta pt="13" x="-3" y="0"/>
-        <delta pt="14" x="-1" y="8"/>
-        <delta pt="15" x="-5" y="-9"/>
-        <delta pt="16" x="8" y="-9"/>
-        <delta pt="17" x="-1" y="8"/>
-        <delta pt="18" x="0" y="0"/>
-        <delta pt="19" x="0" y="-13"/>
-        <delta pt="20" x="6" y="-13"/>
-        <delta pt="21" x="0" y="-13"/>
-        <delta pt="22" x="0" y="-13"/>
-        <delta pt="23" x="0" y="0"/>
-        <delta pt="24" x="0" y="0"/>
-        <delta pt="25" x="0" y="0"/>
-        <delta pt="26" x="0" y="0"/>
-        <delta pt="27" x="0" y="0"/>
-      </tuple>
-    </glyphVariations>
-    <glyphVariations glyph="uni0061">
-      <tuple>
-        <coord axis="wght" value="-1.0"/>
-        <delta pt="0" x="11" y="-8"/>
-        <delta pt="1" x="11" y="4"/>
-        <delta pt="2" x="22" y="5"/>
-        <delta pt="3" x="-4" y="-8"/>
-        <delta pt="4" x="6" y="-5"/>
-        <delta pt="5" x="3" y="-11"/>
-        <delta pt="6" x="4" y="-9"/>
-        <delta pt="7" x="4" y="9"/>
-        <delta pt="8" x="0" y="7"/>
-        <delta pt="9" x="-9" y="8"/>
-        <delta pt="10" x="-24" y="3"/>
-        <delta pt="11" x="-18" y="6"/>
-        <delta pt="12" x="-44" y="1"/>
-        <delta pt="13" x="-44" y="-16"/>
-        <delta pt="14" x="-44" y="-22"/>
-        <delta pt="15" x="-36" y="-39"/>
-        <delta pt="16" x="-24" y="-39"/>
-        <delta pt="17" x="-7" y="-39"/>
-        <delta pt="18" x="26" y="-15"/>
-        <delta pt="19" x="26" y="3"/>
-        <delta pt="20" x="17" y="0"/>
-        <delta pt="21" x="3" y="-4"/>
-        <delta pt="22" x="23" y="15"/>
-        <delta pt="23" x="22" y="8"/>
-        <delta pt="24" x="6" y="0"/>
-        <delta pt="25" x="0" y="0"/>
-        <delta pt="26" x="2" y="0"/>
-        <delta pt="27" x="11" y="-2"/>
-        <delta pt="28" x="30" y="7"/>
-        <delta pt="29" x="30" y="4"/>
-        <delta pt="30" x="30" y="13"/>
-        <delta pt="31" x="14" y="21"/>
-        <delta pt="32" x="3" y="21"/>
-        <delta pt="33" x="-15" y="21"/>
-        <delta pt="34" x="-32" y="5"/>
-        <delta pt="35" x="-34" y="-9"/>
-        <delta pt="36" x="-48" y="-14"/>
-        <delta pt="37" x="-40" y="4"/>
-        <delta pt="38" x="-36" y="14"/>
-        <delta pt="39" x="-24" y="27"/>
-        <delta pt="40" x="-13" y="27"/>
-        <delta pt="41" x="12" y="27"/>
-        <delta pt="42" x="10" y="6"/>
-        <delta pt="43" x="12" y="5"/>
-        <delta pt="44" x="-4" y="-4"/>
-        <delta pt="45" x="-16" y="-4"/>
-        <delta pt="46" x="-20" y="-4"/>
-        <delta pt="47" x="-22" y="7"/>
-        <delta pt="48" x="-22" y="25"/>
-        <delta pt="49" x="-22" y="10"/>
-        <delta pt="50" x="-22" y="-15"/>
-        <delta pt="51" x="-16" y="-30"/>
-        <delta pt="52" x="-9" y="-30"/>
-        <delta pt="53" x="-12" y="-30"/>
-        <delta pt="54" x="-11" y="-35"/>
-        <delta pt="55" x="-5" y="-35"/>
-        <delta pt="56" x="-15" y="-27"/>
-        <delta pt="57" x="-10" y="-3"/>
-        <delta pt="58" x="9" y="-3"/>
-        <delta pt="59" x="14" y="-3"/>
-        <delta pt="60" x="33" y="-1"/>
-        <delta pt="61" x="0" y="0"/>
-        <delta pt="62" x="-3" y="0"/>
-        <delta pt="63" x="0" y="0"/>
-        <delta pt="64" x="0" y="0"/>
-      </tuple>
-      <tuple>
-        <coord axis="wght" value="1.0"/>
-        <delta pt="0" x="-21" y="1"/>
-        <delta pt="1" x="-21" y="17"/>
-        <delta pt="2" x="-2" y="28"/>
-        <delta pt="3" x="20" y="23"/>
-        <delta pt="4" x="19" y="20"/>
-        <delta pt="5" x="28" y="21"/>
-        <delta pt="6" x="26" y="23"/>
-        <delta pt="7" x="26" y="15"/>
-        <delta pt="8" x="24" y="12"/>
-        <delta pt="9" x="30" y="17"/>
-        <delta pt="10" x="31" y="15"/>
-        <delta pt="11" x="77" y="31"/>
-        <delta pt="12" x="66" y="36"/>
-        <delta pt="13" x="66" y="18"/>
-        <delta pt="14" x="66" y="21"/>
-        <delta pt="15" x="49" y="19"/>
-        <delta pt="16" x="37" y="19"/>
-        <delta pt="17" x="21" y="19"/>
-        <delta pt="18" x="-2" y="5"/>
-        <delta pt="19" x="-34" y="-18"/>
-        <delta pt="20" x="-6" y="3"/>
-        <delta pt="21" x="-11" y="12"/>
-        <delta pt="22" x="-29" y="-11"/>
-        <delta pt="23" x="-17" y="-2"/>
-        <delta pt="24" x="-13" y="-3"/>
-        <delta pt="25" x="-25" y="-3"/>
-        <delta pt="26" x="-29" y="-3"/>
-        <delta pt="27" x="-21" y="2"/>
-        <delta pt="28" x="-34" y="-14"/>
-        <delta pt="29" x="-34" y="17"/>
-        <delta pt="30" x="-34" y="7"/>
-        <delta pt="31" x="-18" y="7"/>
-        <delta pt="32" x="-16" y="7"/>
-        <delta pt="33" x="-18" y="7"/>
-        <delta pt="34" x="-15" y="9"/>
-        <delta pt="35" x="-21" y="12"/>
-        <delta pt="36" x="19" y="23"/>
-        <delta pt="37" x="45" y="46"/>
-        <delta pt="38" x="52" y="7"/>
-        <delta pt="39" x="26" y="-21"/>
-        <delta pt="40" x="14" y="-21"/>
-        <delta pt="41" x="-5" y="-21"/>
-        <delta pt="42" x="-17" y="-7"/>
-        <delta pt="43" x="-31" y="1"/>
-        <delta pt="44" x="-12" y="16"/>
-        <delta pt="45" x="34" y="16"/>
-        <delta pt="46" x="61" y="16"/>
-        <delta pt="47" x="70" y="4"/>
-        <delta pt="48" x="70" y="-5"/>
-        <delta pt="49" x="70" y="-22"/>
-        <delta pt="50" x="70" y="4"/>
-        <delta pt="51" x="59" y="22"/>
-        <delta pt="52" x="50" y="22"/>
-        <delta pt="53" x="43" y="22"/>
-        <delta pt="54" x="37" y="19"/>
-        <delta pt="55" x="38" y="22"/>
-        <delta pt="56" x="47" y="28"/>
-        <delta pt="57" x="46" y="-6"/>
-        <delta pt="58" x="-2" y="-6"/>
-        <delta pt="59" x="-16" y="-6"/>
-        <delta pt="60" x="-25" y="-13"/>
-        <delta pt="61" x="0" y="0"/>
-        <delta pt="62" x="32" y="0"/>
-        <delta pt="63" x="0" y="0"/>
-        <delta pt="64" x="0" y="0"/>
-      </tuple>
-      <tuple>
-        <coord axis="cntr" value="1.0"/>
-        <delta pt="0" x="0" y="-3"/>
-        <delta pt="1" x="0" y="-1"/>
-        <delta pt="2" x="0" y="-3"/>
-        <delta pt="3" x="0" y="-3"/>
-        <delta pt="4" x="0" y="-3"/>
-        <delta pt="5" x="0" y="-3"/>
-        <delta pt="6" x="0" y="-3"/>
-        <delta pt="7" x="0" y="4"/>
-        <delta pt="8" x="0" y="4"/>
-        <delta pt="9" x="2" y="5"/>
-        <delta pt="10" x="6" y="7"/>
-        <delta pt="11" x="1" y="5"/>
-        <delta pt="12" x="0" y="-1"/>
-        <delta pt="13" x="0" y="-6"/>
-        <delta pt="14" x="0" y="-6"/>
-        <delta pt="15" x="-1" y="-6"/>
-        <delta pt="16" x="0" y="-6"/>
-        <delta pt="17" x="0" y="-6"/>
-        <delta pt="18" x="0" y="-5"/>
-        <delta pt="19" x="0" y="-4"/>
-        <delta pt="20" x="0" y="-1"/>
-        <delta pt="21" x="0" y="0"/>
-        <delta pt="22" x="0" y="0"/>
-        <delta pt="23" x="0" y="0"/>
-        <delta pt="24" x="0" y="0"/>
-        <delta pt="25" x="0" y="0"/>
-        <delta pt="26" x="0" y="0"/>
-        <delta pt="27" x="0" y="-1"/>
-        <delta pt="28" x="0" y="-2"/>
-        <delta pt="29" x="0" y="7"/>
-        <delta pt="30" x="0" y="6"/>
-        <delta pt="31" x="0" y="7"/>
-        <delta pt="32" x="0" y="7"/>
-        <delta pt="33" x="0" y="7"/>
-        <delta pt="34" x="0" y="7"/>
-        <delta pt="35" x="0" y="7"/>
-        <delta pt="36" x="0" y="0"/>
-        <delta pt="37" x="0" y="0"/>
-        <delta pt="38" x="0" y="0"/>
-        <delta pt="39" x="0" y="0"/>
-        <delta pt="40" x="0" y="0"/>
-        <delta pt="41" x="0" y="0"/>
-        <delta pt="42" x="0" y="0"/>
-        <delta pt="43" x="0" y="0"/>
-        <delta pt="44" x="0" y="0"/>
-        <delta pt="45" x="0" y="0"/>
-        <delta pt="46" x="0" y="0"/>
-        <delta pt="47" x="0" y="0"/>
-        <delta pt="48" x="0" y="0"/>
-        <delta pt="49" x="0" y="-6"/>
-        <delta pt="50" x="0" y="-7"/>
-        <delta pt="51" x="0" y="-8"/>
-        <delta pt="52" x="0" y="-8"/>
-        <delta pt="53" x="1" y="-8"/>
-        <delta pt="54" x="2" y="-5"/>
-        <delta pt="55" x="4" y="-2"/>
-        <delta pt="56" x="0" y="0"/>
-        <delta pt="57" x="0" y="0"/>
-        <delta pt="58" x="0" y="0"/>
-        <delta pt="59" x="0" y="0"/>
-        <delta pt="60" x="0" y="-1"/>
-        <delta pt="61" x="0" y="0"/>
-        <delta pt="62" x="0" y="0"/>
-        <delta pt="63" x="0" y="0"/>
-        <delta pt="64" x="0" y="0"/>
-      </tuple>
-      <tuple>
-        <coord axis="wght" value="-1.0"/>
-        <coord axis="cntr" value="1.0"/>
-        <delta pt="0" x="0" y="3"/>
-        <delta pt="1" x="0" y="1"/>
-        <delta pt="2" x="0" y="3"/>
-        <delta pt="3" x="0" y="3"/>
-        <delta pt="4" x="0" y="3"/>
-        <delta pt="5" x="0" y="3"/>
-        <delta pt="6" x="0" y="3"/>
-        <delta pt="7" x="0" y="-4"/>
-        <delta pt="8" x="0" y="-4"/>
-        <delta pt="9" x="-2" y="-5"/>
-        <delta pt="10" x="-6" y="-7"/>
-        <delta pt="11" x="-1" y="-5"/>
-        <delta pt="12" x="0" y="1"/>
-        <delta pt="13" x="0" y="6"/>
-        <delta pt="14" x="0" y="6"/>
-        <delta pt="15" x="1" y="6"/>
-        <delta pt="16" x="0" y="6"/>
-        <delta pt="17" x="0" y="6"/>
-        <delta pt="18" x="0" y="5"/>
-        <delta pt="19" x="0" y="4"/>
-        <delta pt="20" x="0" y="1"/>
-        <delta pt="21" x="0" y="0"/>
-        <delta pt="22" x="0" y="0"/>
-        <delta pt="23" x="0" y="0"/>
-        <delta pt="24" x="0" y="0"/>
-        <delta pt="25" x="0" y="0"/>
-        <delta pt="26" x="0" y="0"/>
-        <delta pt="27" x="0" y="1"/>
-        <delta pt="28" x="0" y="2"/>
-        <delta pt="29" x="0" y="-7"/>
-        <delta pt="30" x="0" y="-6"/>
-        <delta pt="31" x="0" y="-7"/>
-        <delta pt="32" x="0" y="-7"/>
-        <delta pt="33" x="0" y="-7"/>
-        <delta pt="34" x="0" y="-7"/>
-        <delta pt="35" x="0" y="-7"/>
-        <delta pt="36" x="0" y="0"/>
-        <delta pt="37" x="0" y="0"/>
-        <delta pt="38" x="0" y="0"/>
-        <delta pt="39" x="0" y="0"/>
-        <delta pt="40" x="0" y="0"/>
-        <delta pt="41" x="0" y="0"/>
-        <delta pt="42" x="0" y="0"/>
-        <delta pt="43" x="0" y="0"/>
-        <delta pt="44" x="0" y="0"/>
-        <delta pt="45" x="0" y="0"/>
-        <delta pt="46" x="0" y="0"/>
-        <delta pt="47" x="0" y="0"/>
-        <delta pt="48" x="0" y="0"/>
-        <delta pt="49" x="0" y="6"/>
-        <delta pt="50" x="0" y="7"/>
-        <delta pt="51" x="0" y="8"/>
-        <delta pt="52" x="0" y="8"/>
-        <delta pt="53" x="-1" y="8"/>
-        <delta pt="54" x="-2" y="5"/>
-        <delta pt="55" x="-4" y="2"/>
-        <delta pt="56" x="0" y="0"/>
-        <delta pt="57" x="0" y="0"/>
-        <delta pt="58" x="0" y="0"/>
-        <delta pt="59" x="0" y="0"/>
-        <delta pt="60" x="0" y="1"/>
-        <delta pt="61" x="0" y="0"/>
-        <delta pt="62" x="0" y="0"/>
-        <delta pt="63" x="0" y="0"/>
-        <delta pt="64" x="0" y="0"/>
-      </tuple>
-      <tuple>
-        <coord axis="wght" value="1.0"/>
-        <coord axis="cntr" value="1.0"/>
-        <delta pt="0" x="0" y="-5"/>
-        <delta pt="1" x="0" y="0"/>
-        <delta pt="2" x="3" y="-4"/>
-        <delta pt="3" x="0" y="-4"/>
-        <delta pt="4" x="0" y="-4"/>
-        <delta pt="5" x="0" y="-4"/>
-        <delta pt="6" x="0" y="-4"/>
-        <delta pt="7" x="0" y="8"/>
-        <delta pt="8" x="0" y="8"/>
-        <delta pt="9" x="5" y="9"/>
-        <delta pt="10" x="11" y="13"/>
-        <delta pt="11" x="2" y="10"/>
-        <delta pt="12" x="0" y="0"/>
-        <delta pt="13" x="0" y="-9"/>
-        <delta pt="14" x="0" y="-9"/>
-        <delta pt="15" x="-1" y="-9"/>
-        <delta pt="16" x="0" y="-9"/>
-        <delta pt="17" x="0" y="-9"/>
-        <delta pt="18" x="0" y="-10"/>
-        <delta pt="19" x="0" y="-8"/>
-        <delta pt="20" x="0" y="-2"/>
-        <delta pt="21" x="0" y="1"/>
-        <delta pt="22" x="0" y="0"/>
-        <delta pt="23" x="1" y="-1"/>
-        <delta pt="24" x="0" y="0"/>
-        <delta pt="25" x="0" y="0"/>
-        <delta pt="26" x="0" y="0"/>
-        <delta pt="27" x="0" y="-1"/>
-        <delta pt="28" x="0" y="-4"/>
-        <delta pt="29" x="0" y="12"/>
-        <delta pt="30" x="0" y="13"/>
-        <delta pt="31" x="0" y="13"/>
-        <delta pt="32" x="0" y="13"/>
-        <delta pt="33" x="0" y="13"/>
-        <delta pt="34" x="0" y="13"/>
-        <delta pt="35" x="0" y="13"/>
-        <delta pt="36" x="0" y="0"/>
-        <delta pt="37" x="0" y="0"/>
-        <delta pt="38" x="0" y="0"/>
-        <delta pt="39" x="0" y="1"/>
-        <delta pt="40" x="0" y="1"/>
-        <delta pt="41" x="0" y="1"/>
-        <delta pt="42" x="0" y="1"/>
-        <delta pt="43" x="0" y="0"/>
-        <delta pt="44" x="0" y="0"/>
-        <delta pt="45" x="0" y="0"/>
-        <delta pt="46" x="0" y="0"/>
-        <delta pt="47" x="0" y="-1"/>
-        <delta pt="48" x="0" y="-1"/>
-        <delta pt="49" x="0" y="-9"/>
-        <delta pt="50" x="0" y="-13"/>
-        <delta pt="51" x="1" y="-14"/>
-        <delta pt="52" x="1" y="-14"/>
-        <delta pt="53" x="2" y="-14"/>
-        <delta pt="54" x="5" y="-11"/>
-        <delta pt="55" x="7" y="-4"/>
-        <delta pt="56" x="0" y="0"/>
-        <delta pt="57" x="0" y="0"/>
-        <delta pt="58" x="0" y="0"/>
-        <delta pt="59" x="0" y="0"/>
-        <delta pt="60" x="1" y="0"/>
-        <delta pt="61" x="0" y="0"/>
-        <delta pt="62" x="0" y="0"/>
-        <delta pt="63" x="0" y="0"/>
-        <delta pt="64" x="0" y="0"/>
-      </tuple>
-    </glyphVariations>
   </gvar>
 
 </ttFont>
diff --git a/Tests/varLib/data/test_results/BuildMain.ttx b/Tests/varLib/data/test_results/BuildMain.ttx
index 27d02d1..7e5d956 100644
--- a/Tests/varLib/data/test_results/BuildMain.ttx
+++ b/Tests/varLib/data/test_results/BuildMain.ttx
@@ -615,7 +615,7 @@
 
   <GDEF>
     <Version value="0x00010003"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="uni0024" class="1"/>
       <ClassDef glyph="uni0024.nostroke" class="1"/>
       <ClassDef glyph="uni0041" class="1"/>
@@ -1051,6 +1051,509 @@
         <delta pt="3" x="0" y="0"/>
       </tuple>
     </glyphVariations>
+    <glyphVariations glyph="uni0041">
+      <tuple>
+        <coord axis="wght" value="-1.0"/>
+        <delta pt="0" x="7" y="0"/>
+        <delta pt="1" x="7" y="-20"/>
+        <delta pt="2" x="-6" y="-29"/>
+        <delta pt="3" x="-12" y="-29"/>
+        <delta pt="4" x="-25" y="-20"/>
+        <delta pt="5" x="-25" y="0"/>
+        <delta pt="6" x="14" y="0"/>
+        <delta pt="7" x="4" y="9"/>
+        <delta pt="8" x="-36" y="9"/>
+        <delta pt="9" x="-37" y="0"/>
+        <delta pt="10" x="24" y="0"/>
+        <delta pt="11" x="9" y="58"/>
+        <delta pt="12" x="3" y="68"/>
+        <delta pt="13" x="-4" y="0"/>
+        <delta pt="14" x="3" y="28"/>
+        <delta pt="15" x="-4" y="2"/>
+        <delta pt="16" x="4" y="2"/>
+        <delta pt="17" x="-4" y="28"/>
+        <delta pt="18" x="20" y="0"/>
+        <delta pt="19" x="20" y="-20"/>
+        <delta pt="20" x="14" y="-29"/>
+        <delta pt="21" x="8" y="-29"/>
+        <delta pt="22" x="-2" y="-20"/>
+        <delta pt="23" x="-2" y="0"/>
+        <delta pt="24" x="0" y="0"/>
+        <delta pt="25" x="-10" y="0"/>
+        <delta pt="26" x="0" y="0"/>
+        <delta pt="27" x="0" y="0"/>
+      </tuple>
+      <tuple>
+        <coord axis="wght" value="1.0"/>
+        <delta pt="0" x="5" y="0"/>
+        <delta pt="1" x="5" y="19"/>
+        <delta pt="2" x="9" y="19"/>
+        <delta pt="3" x="6" y="19"/>
+        <delta pt="4" x="-15" y="19"/>
+        <delta pt="5" x="-15" y="0"/>
+        <delta pt="6" x="-6" y="0"/>
+        <delta pt="7" x="-14" y="-23"/>
+        <delta pt="8" x="46" y="-23"/>
+        <delta pt="9" x="39" y="0"/>
+        <delta pt="10" x="-69" y="0"/>
+        <delta pt="11" x="-27" y="-86"/>
+        <delta pt="12" x="-7" y="-16"/>
+        <delta pt="13" x="11" y="0"/>
+        <delta pt="14" x="-2" y="-39"/>
+        <delta pt="15" x="-1" y="-22"/>
+        <delta pt="16" x="-1" y="-22"/>
+        <delta pt="17" x="8" y="-39"/>
+        <delta pt="18" x="-41" y="0"/>
+        <delta pt="19" x="-41" y="16"/>
+        <delta pt="20" x="-59" y="16"/>
+        <delta pt="21" x="6" y="16"/>
+        <delta pt="22" x="12" y="16"/>
+        <delta pt="23" x="12" y="0"/>
+        <delta pt="24" x="0" y="0"/>
+        <delta pt="25" x="17" y="0"/>
+        <delta pt="26" x="0" y="0"/>
+        <delta pt="27" x="0" y="0"/>
+      </tuple>
+      <tuple>
+        <coord axis="cntr" value="1.0"/>
+        <delta pt="0" x="2" y="0"/>
+        <delta pt="1" x="2" y="-9"/>
+        <delta pt="2" x="-4" y="-9"/>
+        <delta pt="3" x="-4" y="-9"/>
+        <delta pt="4" x="-2" y="-9"/>
+        <delta pt="5" x="-2" y="0"/>
+        <delta pt="6" x="2" y="0"/>
+        <delta pt="7" x="-4" y="0"/>
+        <delta pt="8" x="-4" y="0"/>
+        <delta pt="9" x="-4" y="0"/>
+        <delta pt="10" x="-4" y="0"/>
+        <delta pt="11" x="-6" y="8"/>
+        <delta pt="12" x="-10" y="0"/>
+        <delta pt="13" x="-2" y="0"/>
+        <delta pt="14" x="0" y="5"/>
+        <delta pt="15" x="-3" y="-5"/>
+        <delta pt="16" x="5" y="-5"/>
+        <delta pt="17" x="-1" y="5"/>
+        <delta pt="18" x="0" y="0"/>
+        <delta pt="19" x="0" y="-8"/>
+        <delta pt="20" x="4" y="-8"/>
+        <delta pt="21" x="0" y="-8"/>
+        <delta pt="22" x="0" y="-8"/>
+        <delta pt="23" x="0" y="0"/>
+        <delta pt="24" x="0" y="0"/>
+        <delta pt="25" x="0" y="0"/>
+        <delta pt="26" x="0" y="0"/>
+        <delta pt="27" x="0" y="0"/>
+      </tuple>
+      <tuple>
+        <coord axis="wght" value="-1.0"/>
+        <coord axis="cntr" value="1.0"/>
+        <delta pt="0" x="-2" y="0"/>
+        <delta pt="1" x="-2" y="9"/>
+        <delta pt="2" x="4" y="9"/>
+        <delta pt="3" x="4" y="9"/>
+        <delta pt="4" x="2" y="9"/>
+        <delta pt="5" x="2" y="0"/>
+        <delta pt="6" x="-2" y="0"/>
+        <delta pt="7" x="4" y="0"/>
+        <delta pt="8" x="4" y="0"/>
+        <delta pt="9" x="4" y="0"/>
+        <delta pt="10" x="4" y="0"/>
+        <delta pt="11" x="6" y="-8"/>
+        <delta pt="12" x="10" y="0"/>
+        <delta pt="13" x="2" y="0"/>
+        <delta pt="14" x="0" y="-5"/>
+        <delta pt="15" x="3" y="5"/>
+        <delta pt="16" x="-5" y="5"/>
+        <delta pt="17" x="1" y="-5"/>
+        <delta pt="18" x="0" y="0"/>
+        <delta pt="19" x="0" y="8"/>
+        <delta pt="20" x="-4" y="8"/>
+        <delta pt="21" x="0" y="8"/>
+        <delta pt="22" x="0" y="8"/>
+        <delta pt="23" x="0" y="0"/>
+        <delta pt="24" x="0" y="0"/>
+        <delta pt="25" x="0" y="0"/>
+        <delta pt="26" x="0" y="0"/>
+        <delta pt="27" x="0" y="0"/>
+      </tuple>
+      <tuple>
+        <coord axis="wght" value="1.0"/>
+        <coord axis="cntr" value="1.0"/>
+        <delta pt="0" x="3" y="0"/>
+        <delta pt="1" x="3" y="-15"/>
+        <delta pt="2" x="-6" y="-15"/>
+        <delta pt="3" x="-6" y="-15"/>
+        <delta pt="4" x="-3" y="-15"/>
+        <delta pt="5" x="-3" y="0"/>
+        <delta pt="6" x="3" y="0"/>
+        <delta pt="7" x="-6" y="0"/>
+        <delta pt="8" x="-6" y="0"/>
+        <delta pt="9" x="-6" y="0"/>
+        <delta pt="10" x="-6" y="0"/>
+        <delta pt="11" x="-11" y="13"/>
+        <delta pt="12" x="-17" y="0"/>
+        <delta pt="13" x="-3" y="0"/>
+        <delta pt="14" x="-1" y="8"/>
+        <delta pt="15" x="-5" y="-9"/>
+        <delta pt="16" x="8" y="-9"/>
+        <delta pt="17" x="-1" y="8"/>
+        <delta pt="18" x="0" y="0"/>
+        <delta pt="19" x="0" y="-13"/>
+        <delta pt="20" x="6" y="-13"/>
+        <delta pt="21" x="0" y="-13"/>
+        <delta pt="22" x="0" y="-13"/>
+        <delta pt="23" x="0" y="0"/>
+        <delta pt="24" x="0" y="0"/>
+        <delta pt="25" x="0" y="0"/>
+        <delta pt="26" x="0" y="0"/>
+        <delta pt="27" x="0" y="0"/>
+      </tuple>
+    </glyphVariations>
+    <glyphVariations glyph="uni0061">
+      <tuple>
+        <coord axis="wght" value="-1.0"/>
+        <delta pt="0" x="11" y="-8"/>
+        <delta pt="1" x="11" y="4"/>
+        <delta pt="2" x="22" y="5"/>
+        <delta pt="3" x="-4" y="-8"/>
+        <delta pt="4" x="6" y="-5"/>
+        <delta pt="5" x="3" y="-11"/>
+        <delta pt="6" x="4" y="-9"/>
+        <delta pt="7" x="4" y="9"/>
+        <delta pt="8" x="0" y="7"/>
+        <delta pt="9" x="-9" y="8"/>
+        <delta pt="10" x="-24" y="3"/>
+        <delta pt="11" x="-18" y="6"/>
+        <delta pt="12" x="-44" y="1"/>
+        <delta pt="13" x="-44" y="-16"/>
+        <delta pt="14" x="-44" y="-22"/>
+        <delta pt="15" x="-36" y="-39"/>
+        <delta pt="16" x="-24" y="-39"/>
+        <delta pt="17" x="-7" y="-39"/>
+        <delta pt="18" x="26" y="-15"/>
+        <delta pt="19" x="26" y="3"/>
+        <delta pt="20" x="17" y="0"/>
+        <delta pt="21" x="3" y="-4"/>
+        <delta pt="22" x="23" y="15"/>
+        <delta pt="23" x="22" y="8"/>
+        <delta pt="24" x="6" y="0"/>
+        <delta pt="25" x="0" y="0"/>
+        <delta pt="26" x="2" y="0"/>
+        <delta pt="27" x="11" y="-2"/>
+        <delta pt="28" x="30" y="7"/>
+        <delta pt="29" x="30" y="4"/>
+        <delta pt="30" x="30" y="13"/>
+        <delta pt="31" x="14" y="21"/>
+        <delta pt="32" x="3" y="21"/>
+        <delta pt="33" x="-15" y="21"/>
+        <delta pt="34" x="-32" y="5"/>
+        <delta pt="35" x="-34" y="-9"/>
+        <delta pt="36" x="-48" y="-14"/>
+        <delta pt="37" x="-40" y="4"/>
+        <delta pt="38" x="-36" y="14"/>
+        <delta pt="39" x="-24" y="27"/>
+        <delta pt="40" x="-13" y="27"/>
+        <delta pt="41" x="12" y="27"/>
+        <delta pt="42" x="10" y="6"/>
+        <delta pt="43" x="12" y="5"/>
+        <delta pt="44" x="-4" y="-4"/>
+        <delta pt="45" x="-16" y="-4"/>
+        <delta pt="46" x="-20" y="-4"/>
+        <delta pt="47" x="-22" y="7"/>
+        <delta pt="48" x="-22" y="25"/>
+        <delta pt="49" x="-22" y="10"/>
+        <delta pt="50" x="-22" y="-15"/>
+        <delta pt="51" x="-16" y="-30"/>
+        <delta pt="52" x="-9" y="-30"/>
+        <delta pt="53" x="-12" y="-30"/>
+        <delta pt="54" x="-11" y="-35"/>
+        <delta pt="55" x="-5" y="-35"/>
+        <delta pt="56" x="-15" y="-27"/>
+        <delta pt="57" x="-10" y="-3"/>
+        <delta pt="58" x="9" y="-3"/>
+        <delta pt="59" x="14" y="-3"/>
+        <delta pt="60" x="33" y="-1"/>
+        <delta pt="61" x="0" y="0"/>
+        <delta pt="62" x="-3" y="0"/>
+        <delta pt="63" x="0" y="0"/>
+        <delta pt="64" x="0" y="0"/>
+      </tuple>
+      <tuple>
+        <coord axis="wght" value="1.0"/>
+        <delta pt="0" x="-21" y="1"/>
+        <delta pt="1" x="-21" y="17"/>
+        <delta pt="2" x="-2" y="28"/>
+        <delta pt="3" x="20" y="23"/>
+        <delta pt="4" x="19" y="20"/>
+        <delta pt="5" x="28" y="21"/>
+        <delta pt="6" x="26" y="23"/>
+        <delta pt="7" x="26" y="15"/>
+        <delta pt="8" x="24" y="12"/>
+        <delta pt="9" x="30" y="17"/>
+        <delta pt="10" x="31" y="15"/>
+        <delta pt="11" x="77" y="31"/>
+        <delta pt="12" x="66" y="36"/>
+        <delta pt="13" x="66" y="18"/>
+        <delta pt="14" x="66" y="21"/>
+        <delta pt="15" x="49" y="19"/>
+        <delta pt="16" x="37" y="19"/>
+        <delta pt="17" x="21" y="19"/>
+        <delta pt="18" x="-2" y="5"/>
+        <delta pt="19" x="-34" y="-18"/>
+        <delta pt="20" x="-6" y="3"/>
+        <delta pt="21" x="-11" y="12"/>
+        <delta pt="22" x="-29" y="-11"/>
+        <delta pt="23" x="-17" y="-2"/>
+        <delta pt="24" x="-13" y="-3"/>
+        <delta pt="25" x="-25" y="-3"/>
+        <delta pt="26" x="-29" y="-3"/>
+        <delta pt="27" x="-21" y="2"/>
+        <delta pt="28" x="-34" y="-14"/>
+        <delta pt="29" x="-34" y="17"/>
+        <delta pt="30" x="-34" y="7"/>
+        <delta pt="31" x="-18" y="7"/>
+        <delta pt="32" x="-16" y="7"/>
+        <delta pt="33" x="-18" y="7"/>
+        <delta pt="34" x="-15" y="9"/>
+        <delta pt="35" x="-21" y="12"/>
+        <delta pt="36" x="19" y="23"/>
+        <delta pt="37" x="45" y="46"/>
+        <delta pt="38" x="52" y="7"/>
+        <delta pt="39" x="26" y="-21"/>
+        <delta pt="40" x="14" y="-21"/>
+        <delta pt="41" x="-5" y="-21"/>
+        <delta pt="42" x="-17" y="-7"/>
+        <delta pt="43" x="-31" y="1"/>
+        <delta pt="44" x="-12" y="16"/>
+        <delta pt="45" x="34" y="16"/>
+        <delta pt="46" x="61" y="16"/>
+        <delta pt="47" x="70" y="4"/>
+        <delta pt="48" x="70" y="-5"/>
+        <delta pt="49" x="70" y="-22"/>
+        <delta pt="50" x="70" y="4"/>
+        <delta pt="51" x="59" y="22"/>
+        <delta pt="52" x="50" y="22"/>
+        <delta pt="53" x="43" y="22"/>
+        <delta pt="54" x="37" y="19"/>
+        <delta pt="55" x="38" y="22"/>
+        <delta pt="56" x="47" y="28"/>
+        <delta pt="57" x="46" y="-6"/>
+        <delta pt="58" x="-2" y="-6"/>
+        <delta pt="59" x="-16" y="-6"/>
+        <delta pt="60" x="-25" y="-13"/>
+        <delta pt="61" x="0" y="0"/>
+        <delta pt="62" x="32" y="0"/>
+        <delta pt="63" x="0" y="0"/>
+        <delta pt="64" x="0" y="0"/>
+      </tuple>
+      <tuple>
+        <coord axis="cntr" value="1.0"/>
+        <delta pt="0" x="0" y="-3"/>
+        <delta pt="1" x="0" y="-1"/>
+        <delta pt="2" x="0" y="-3"/>
+        <delta pt="3" x="0" y="-3"/>
+        <delta pt="4" x="0" y="-3"/>
+        <delta pt="5" x="0" y="-3"/>
+        <delta pt="6" x="0" y="-3"/>
+        <delta pt="7" x="0" y="4"/>
+        <delta pt="8" x="0" y="4"/>
+        <delta pt="9" x="2" y="5"/>
+        <delta pt="10" x="6" y="7"/>
+        <delta pt="11" x="1" y="5"/>
+        <delta pt="12" x="0" y="-1"/>
+        <delta pt="13" x="0" y="-6"/>
+        <delta pt="14" x="0" y="-6"/>
+        <delta pt="15" x="-1" y="-6"/>
+        <delta pt="16" x="0" y="-6"/>
+        <delta pt="17" x="0" y="-6"/>
+        <delta pt="18" x="0" y="-5"/>
+        <delta pt="19" x="0" y="-4"/>
+        <delta pt="20" x="0" y="-1"/>
+        <delta pt="21" x="0" y="0"/>
+        <delta pt="22" x="0" y="0"/>
+        <delta pt="23" x="0" y="0"/>
+        <delta pt="24" x="0" y="0"/>
+        <delta pt="25" x="0" y="0"/>
+        <delta pt="26" x="0" y="0"/>
+        <delta pt="27" x="0" y="-1"/>
+        <delta pt="28" x="0" y="-2"/>
+        <delta pt="29" x="0" y="7"/>
+        <delta pt="30" x="0" y="6"/>
+        <delta pt="31" x="0" y="7"/>
+        <delta pt="32" x="0" y="7"/>
+        <delta pt="33" x="0" y="7"/>
+        <delta pt="34" x="0" y="7"/>
+        <delta pt="35" x="0" y="7"/>
+        <delta pt="36" x="0" y="0"/>
+        <delta pt="37" x="0" y="0"/>
+        <delta pt="38" x="0" y="0"/>
+        <delta pt="39" x="0" y="0"/>
+        <delta pt="40" x="0" y="0"/>
+        <delta pt="41" x="0" y="0"/>
+        <delta pt="42" x="0" y="0"/>
+        <delta pt="43" x="0" y="0"/>
+        <delta pt="44" x="0" y="0"/>
+        <delta pt="45" x="0" y="0"/>
+        <delta pt="46" x="0" y="0"/>
+        <delta pt="47" x="0" y="0"/>
+        <delta pt="48" x="0" y="0"/>
+        <delta pt="49" x="0" y="-6"/>
+        <delta pt="50" x="0" y="-7"/>
+        <delta pt="51" x="0" y="-8"/>
+        <delta pt="52" x="0" y="-8"/>
+        <delta pt="53" x="1" y="-8"/>
+        <delta pt="54" x="2" y="-5"/>
+        <delta pt="55" x="4" y="-2"/>
+        <delta pt="56" x="0" y="0"/>
+        <delta pt="57" x="0" y="0"/>
+        <delta pt="58" x="0" y="0"/>
+        <delta pt="59" x="0" y="0"/>
+        <delta pt="60" x="0" y="-1"/>
+        <delta pt="61" x="0" y="0"/>
+        <delta pt="62" x="0" y="0"/>
+        <delta pt="63" x="0" y="0"/>
+        <delta pt="64" x="0" y="0"/>
+      </tuple>
+      <tuple>
+        <coord axis="wght" value="-1.0"/>
+        <coord axis="cntr" value="1.0"/>
+        <delta pt="0" x="0" y="3"/>
+        <delta pt="1" x="0" y="1"/>
+        <delta pt="2" x="0" y="3"/>
+        <delta pt="3" x="0" y="3"/>
+        <delta pt="4" x="0" y="3"/>
+        <delta pt="5" x="0" y="3"/>
+        <delta pt="6" x="0" y="3"/>
+        <delta pt="7" x="0" y="-4"/>
+        <delta pt="8" x="0" y="-4"/>
+        <delta pt="9" x="-2" y="-5"/>
+        <delta pt="10" x="-6" y="-7"/>
+        <delta pt="11" x="-1" y="-5"/>
+        <delta pt="12" x="0" y="1"/>
+        <delta pt="13" x="0" y="6"/>
+        <delta pt="14" x="0" y="6"/>
+        <delta pt="15" x="1" y="6"/>
+        <delta pt="16" x="0" y="6"/>
+        <delta pt="17" x="0" y="6"/>
+        <delta pt="18" x="0" y="5"/>
+        <delta pt="19" x="0" y="4"/>
+        <delta pt="20" x="0" y="1"/>
+        <delta pt="21" x="0" y="0"/>
+        <delta pt="22" x="0" y="0"/>
+        <delta pt="23" x="0" y="0"/>
+        <delta pt="24" x="0" y="0"/>
+        <delta pt="25" x="0" y="0"/>
+        <delta pt="26" x="0" y="0"/>
+        <delta pt="27" x="0" y="1"/>
+        <delta pt="28" x="0" y="2"/>
+        <delta pt="29" x="0" y="-7"/>
+        <delta pt="30" x="0" y="-6"/>
+        <delta pt="31" x="0" y="-7"/>
+        <delta pt="32" x="0" y="-7"/>
+        <delta pt="33" x="0" y="-7"/>
+        <delta pt="34" x="0" y="-7"/>
+        <delta pt="35" x="0" y="-7"/>
+        <delta pt="36" x="0" y="0"/>
+        <delta pt="37" x="0" y="0"/>
+        <delta pt="38" x="0" y="0"/>
+        <delta pt="39" x="0" y="0"/>
+        <delta pt="40" x="0" y="0"/>
+        <delta pt="41" x="0" y="0"/>
+        <delta pt="42" x="0" y="0"/>
+        <delta pt="43" x="0" y="0"/>
+        <delta pt="44" x="0" y="0"/>
+        <delta pt="45" x="0" y="0"/>
+        <delta pt="46" x="0" y="0"/>
+        <delta pt="47" x="0" y="0"/>
+        <delta pt="48" x="0" y="0"/>
+        <delta pt="49" x="0" y="6"/>
+        <delta pt="50" x="0" y="7"/>
+        <delta pt="51" x="0" y="8"/>
+        <delta pt="52" x="0" y="8"/>
+        <delta pt="53" x="-1" y="8"/>
+        <delta pt="54" x="-2" y="5"/>
+        <delta pt="55" x="-4" y="2"/>
+        <delta pt="56" x="0" y="0"/>
+        <delta pt="57" x="0" y="0"/>
+        <delta pt="58" x="0" y="0"/>
+        <delta pt="59" x="0" y="0"/>
+        <delta pt="60" x="0" y="1"/>
+        <delta pt="61" x="0" y="0"/>
+        <delta pt="62" x="0" y="0"/>
+        <delta pt="63" x="0" y="0"/>
+        <delta pt="64" x="0" y="0"/>
+      </tuple>
+      <tuple>
+        <coord axis="wght" value="1.0"/>
+        <coord axis="cntr" value="1.0"/>
+        <delta pt="0" x="0" y="-5"/>
+        <delta pt="1" x="0" y="0"/>
+        <delta pt="2" x="3" y="-4"/>
+        <delta pt="3" x="0" y="-4"/>
+        <delta pt="4" x="0" y="-4"/>
+        <delta pt="5" x="0" y="-4"/>
+        <delta pt="6" x="0" y="-4"/>
+        <delta pt="7" x="0" y="8"/>
+        <delta pt="8" x="0" y="8"/>
+        <delta pt="9" x="5" y="9"/>
+        <delta pt="10" x="11" y="13"/>
+        <delta pt="11" x="2" y="10"/>
+        <delta pt="12" x="0" y="0"/>
+        <delta pt="13" x="0" y="-9"/>
+        <delta pt="14" x="0" y="-9"/>
+        <delta pt="15" x="-1" y="-9"/>
+        <delta pt="16" x="0" y="-9"/>
+        <delta pt="17" x="0" y="-9"/>
+        <delta pt="18" x="0" y="-10"/>
+        <delta pt="19" x="0" y="-8"/>
+        <delta pt="20" x="0" y="-2"/>
+        <delta pt="21" x="0" y="1"/>
+        <delta pt="22" x="0" y="0"/>
+        <delta pt="23" x="1" y="-1"/>
+        <delta pt="24" x="0" y="0"/>
+        <delta pt="25" x="0" y="0"/>
+        <delta pt="26" x="0" y="0"/>
+        <delta pt="27" x="0" y="-1"/>
+        <delta pt="28" x="0" y="-4"/>
+        <delta pt="29" x="0" y="12"/>
+        <delta pt="30" x="0" y="13"/>
+        <delta pt="31" x="0" y="13"/>
+        <delta pt="32" x="0" y="13"/>
+        <delta pt="33" x="0" y="13"/>
+        <delta pt="34" x="0" y="13"/>
+        <delta pt="35" x="0" y="13"/>
+        <delta pt="36" x="0" y="0"/>
+        <delta pt="37" x="0" y="0"/>
+        <delta pt="38" x="0" y="0"/>
+        <delta pt="39" x="0" y="1"/>
+        <delta pt="40" x="0" y="1"/>
+        <delta pt="41" x="0" y="1"/>
+        <delta pt="42" x="0" y="1"/>
+        <delta pt="43" x="0" y="0"/>
+        <delta pt="44" x="0" y="0"/>
+        <delta pt="45" x="0" y="0"/>
+        <delta pt="46" x="0" y="0"/>
+        <delta pt="47" x="0" y="-1"/>
+        <delta pt="48" x="0" y="-1"/>
+        <delta pt="49" x="0" y="-9"/>
+        <delta pt="50" x="0" y="-13"/>
+        <delta pt="51" x="1" y="-14"/>
+        <delta pt="52" x="1" y="-14"/>
+        <delta pt="53" x="2" y="-14"/>
+        <delta pt="54" x="5" y="-11"/>
+        <delta pt="55" x="7" y="-4"/>
+        <delta pt="56" x="0" y="0"/>
+        <delta pt="57" x="0" y="0"/>
+        <delta pt="58" x="0" y="0"/>
+        <delta pt="59" x="0" y="0"/>
+        <delta pt="60" x="1" y="0"/>
+        <delta pt="61" x="0" y="0"/>
+        <delta pt="62" x="0" y="0"/>
+        <delta pt="63" x="0" y="0"/>
+        <delta pt="64" x="0" y="0"/>
+      </tuple>
+    </glyphVariations>
     <glyphVariations glyph="uni0024">
       <tuple>
         <coord axis="wght" value="-1.0"/>
@@ -1749,509 +2252,6 @@
         <delta pt="65" x="0" y="0"/>
       </tuple>
     </glyphVariations>
-    <glyphVariations glyph="uni0041">
-      <tuple>
-        <coord axis="wght" value="-1.0"/>
-        <delta pt="0" x="7" y="0"/>
-        <delta pt="1" x="7" y="-20"/>
-        <delta pt="2" x="-6" y="-29"/>
-        <delta pt="3" x="-12" y="-29"/>
-        <delta pt="4" x="-25" y="-20"/>
-        <delta pt="5" x="-25" y="0"/>
-        <delta pt="6" x="14" y="0"/>
-        <delta pt="7" x="4" y="9"/>
-        <delta pt="8" x="-36" y="9"/>
-        <delta pt="9" x="-37" y="0"/>
-        <delta pt="10" x="24" y="0"/>
-        <delta pt="11" x="9" y="58"/>
-        <delta pt="12" x="3" y="68"/>
-        <delta pt="13" x="-4" y="0"/>
-        <delta pt="14" x="3" y="28"/>
-        <delta pt="15" x="-4" y="2"/>
-        <delta pt="16" x="4" y="2"/>
-        <delta pt="17" x="-4" y="28"/>
-        <delta pt="18" x="20" y="0"/>
-        <delta pt="19" x="20" y="-20"/>
-        <delta pt="20" x="14" y="-29"/>
-        <delta pt="21" x="8" y="-29"/>
-        <delta pt="22" x="-2" y="-20"/>
-        <delta pt="23" x="-2" y="0"/>
-        <delta pt="24" x="0" y="0"/>
-        <delta pt="25" x="-10" y="0"/>
-        <delta pt="26" x="0" y="0"/>
-        <delta pt="27" x="0" y="0"/>
-      </tuple>
-      <tuple>
-        <coord axis="wght" value="1.0"/>
-        <delta pt="0" x="5" y="0"/>
-        <delta pt="1" x="5" y="19"/>
-        <delta pt="2" x="9" y="19"/>
-        <delta pt="3" x="6" y="19"/>
-        <delta pt="4" x="-15" y="19"/>
-        <delta pt="5" x="-15" y="0"/>
-        <delta pt="6" x="-6" y="0"/>
-        <delta pt="7" x="-14" y="-23"/>
-        <delta pt="8" x="46" y="-23"/>
-        <delta pt="9" x="39" y="0"/>
-        <delta pt="10" x="-69" y="0"/>
-        <delta pt="11" x="-27" y="-86"/>
-        <delta pt="12" x="-7" y="-16"/>
-        <delta pt="13" x="11" y="0"/>
-        <delta pt="14" x="-2" y="-39"/>
-        <delta pt="15" x="-1" y="-22"/>
-        <delta pt="16" x="-1" y="-22"/>
-        <delta pt="17" x="8" y="-39"/>
-        <delta pt="18" x="-41" y="0"/>
-        <delta pt="19" x="-41" y="16"/>
-        <delta pt="20" x="-59" y="16"/>
-        <delta pt="21" x="6" y="16"/>
-        <delta pt="22" x="12" y="16"/>
-        <delta pt="23" x="12" y="0"/>
-        <delta pt="24" x="0" y="0"/>
-        <delta pt="25" x="17" y="0"/>
-        <delta pt="26" x="0" y="0"/>
-        <delta pt="27" x="0" y="0"/>
-      </tuple>
-      <tuple>
-        <coord axis="cntr" value="1.0"/>
-        <delta pt="0" x="2" y="0"/>
-        <delta pt="1" x="2" y="-9"/>
-        <delta pt="2" x="-4" y="-9"/>
-        <delta pt="3" x="-4" y="-9"/>
-        <delta pt="4" x="-2" y="-9"/>
-        <delta pt="5" x="-2" y="0"/>
-        <delta pt="6" x="2" y="0"/>
-        <delta pt="7" x="-4" y="0"/>
-        <delta pt="8" x="-4" y="0"/>
-        <delta pt="9" x="-4" y="0"/>
-        <delta pt="10" x="-4" y="0"/>
-        <delta pt="11" x="-6" y="8"/>
-        <delta pt="12" x="-10" y="0"/>
-        <delta pt="13" x="-2" y="0"/>
-        <delta pt="14" x="0" y="5"/>
-        <delta pt="15" x="-3" y="-5"/>
-        <delta pt="16" x="5" y="-5"/>
-        <delta pt="17" x="-1" y="5"/>
-        <delta pt="18" x="0" y="0"/>
-        <delta pt="19" x="0" y="-8"/>
-        <delta pt="20" x="4" y="-8"/>
-        <delta pt="21" x="0" y="-8"/>
-        <delta pt="22" x="0" y="-8"/>
-        <delta pt="23" x="0" y="0"/>
-        <delta pt="24" x="0" y="0"/>
-        <delta pt="25" x="0" y="0"/>
-        <delta pt="26" x="0" y="0"/>
-        <delta pt="27" x="0" y="0"/>
-      </tuple>
-      <tuple>
-        <coord axis="wght" value="-1.0"/>
-        <coord axis="cntr" value="1.0"/>
-        <delta pt="0" x="-2" y="0"/>
-        <delta pt="1" x="-2" y="9"/>
-        <delta pt="2" x="4" y="9"/>
-        <delta pt="3" x="4" y="9"/>
-        <delta pt="4" x="2" y="9"/>
-        <delta pt="5" x="2" y="0"/>
-        <delta pt="6" x="-2" y="0"/>
-        <delta pt="7" x="4" y="0"/>
-        <delta pt="8" x="4" y="0"/>
-        <delta pt="9" x="4" y="0"/>
-        <delta pt="10" x="4" y="0"/>
-        <delta pt="11" x="6" y="-8"/>
-        <delta pt="12" x="10" y="0"/>
-        <delta pt="13" x="2" y="0"/>
-        <delta pt="14" x="0" y="-5"/>
-        <delta pt="15" x="3" y="5"/>
-        <delta pt="16" x="-5" y="5"/>
-        <delta pt="17" x="1" y="-5"/>
-        <delta pt="18" x="0" y="0"/>
-        <delta pt="19" x="0" y="8"/>
-        <delta pt="20" x="-4" y="8"/>
-        <delta pt="21" x="0" y="8"/>
-        <delta pt="22" x="0" y="8"/>
-        <delta pt="23" x="0" y="0"/>
-        <delta pt="24" x="0" y="0"/>
-        <delta pt="25" x="0" y="0"/>
-        <delta pt="26" x="0" y="0"/>
-        <delta pt="27" x="0" y="0"/>
-      </tuple>
-      <tuple>
-        <coord axis="wght" value="1.0"/>
-        <coord axis="cntr" value="1.0"/>
-        <delta pt="0" x="3" y="0"/>
-        <delta pt="1" x="3" y="-15"/>
-        <delta pt="2" x="-6" y="-15"/>
-        <delta pt="3" x="-6" y="-15"/>
-        <delta pt="4" x="-3" y="-15"/>
-        <delta pt="5" x="-3" y="0"/>
-        <delta pt="6" x="3" y="0"/>
-        <delta pt="7" x="-6" y="0"/>
-        <delta pt="8" x="-6" y="0"/>
-        <delta pt="9" x="-6" y="0"/>
-        <delta pt="10" x="-6" y="0"/>
-        <delta pt="11" x="-11" y="13"/>
-        <delta pt="12" x="-17" y="0"/>
-        <delta pt="13" x="-3" y="0"/>
-        <delta pt="14" x="-1" y="8"/>
-        <delta pt="15" x="-5" y="-9"/>
-        <delta pt="16" x="8" y="-9"/>
-        <delta pt="17" x="-1" y="8"/>
-        <delta pt="18" x="0" y="0"/>
-        <delta pt="19" x="0" y="-13"/>
-        <delta pt="20" x="6" y="-13"/>
-        <delta pt="21" x="0" y="-13"/>
-        <delta pt="22" x="0" y="-13"/>
-        <delta pt="23" x="0" y="0"/>
-        <delta pt="24" x="0" y="0"/>
-        <delta pt="25" x="0" y="0"/>
-        <delta pt="26" x="0" y="0"/>
-        <delta pt="27" x="0" y="0"/>
-      </tuple>
-    </glyphVariations>
-    <glyphVariations glyph="uni0061">
-      <tuple>
-        <coord axis="wght" value="-1.0"/>
-        <delta pt="0" x="11" y="-8"/>
-        <delta pt="1" x="11" y="4"/>
-        <delta pt="2" x="22" y="5"/>
-        <delta pt="3" x="-4" y="-8"/>
-        <delta pt="4" x="6" y="-5"/>
-        <delta pt="5" x="3" y="-11"/>
-        <delta pt="6" x="4" y="-9"/>
-        <delta pt="7" x="4" y="9"/>
-        <delta pt="8" x="0" y="7"/>
-        <delta pt="9" x="-9" y="8"/>
-        <delta pt="10" x="-24" y="3"/>
-        <delta pt="11" x="-18" y="6"/>
-        <delta pt="12" x="-44" y="1"/>
-        <delta pt="13" x="-44" y="-16"/>
-        <delta pt="14" x="-44" y="-22"/>
-        <delta pt="15" x="-36" y="-39"/>
-        <delta pt="16" x="-24" y="-39"/>
-        <delta pt="17" x="-7" y="-39"/>
-        <delta pt="18" x="26" y="-15"/>
-        <delta pt="19" x="26" y="3"/>
-        <delta pt="20" x="17" y="0"/>
-        <delta pt="21" x="3" y="-4"/>
-        <delta pt="22" x="23" y="15"/>
-        <delta pt="23" x="22" y="8"/>
-        <delta pt="24" x="6" y="0"/>
-        <delta pt="25" x="0" y="0"/>
-        <delta pt="26" x="2" y="0"/>
-        <delta pt="27" x="11" y="-2"/>
-        <delta pt="28" x="30" y="7"/>
-        <delta pt="29" x="30" y="4"/>
-        <delta pt="30" x="30" y="13"/>
-        <delta pt="31" x="14" y="21"/>
-        <delta pt="32" x="3" y="21"/>
-        <delta pt="33" x="-15" y="21"/>
-        <delta pt="34" x="-32" y="5"/>
-        <delta pt="35" x="-34" y="-9"/>
-        <delta pt="36" x="-48" y="-14"/>
-        <delta pt="37" x="-40" y="4"/>
-        <delta pt="38" x="-36" y="14"/>
-        <delta pt="39" x="-24" y="27"/>
-        <delta pt="40" x="-13" y="27"/>
-        <delta pt="41" x="12" y="27"/>
-        <delta pt="42" x="10" y="6"/>
-        <delta pt="43" x="12" y="5"/>
-        <delta pt="44" x="-4" y="-4"/>
-        <delta pt="45" x="-16" y="-4"/>
-        <delta pt="46" x="-20" y="-4"/>
-        <delta pt="47" x="-22" y="7"/>
-        <delta pt="48" x="-22" y="25"/>
-        <delta pt="49" x="-22" y="10"/>
-        <delta pt="50" x="-22" y="-15"/>
-        <delta pt="51" x="-16" y="-30"/>
-        <delta pt="52" x="-9" y="-30"/>
-        <delta pt="53" x="-12" y="-30"/>
-        <delta pt="54" x="-11" y="-35"/>
-        <delta pt="55" x="-5" y="-35"/>
-        <delta pt="56" x="-15" y="-27"/>
-        <delta pt="57" x="-10" y="-3"/>
-        <delta pt="58" x="9" y="-3"/>
-        <delta pt="59" x="14" y="-3"/>
-        <delta pt="60" x="33" y="-1"/>
-        <delta pt="61" x="0" y="0"/>
-        <delta pt="62" x="-3" y="0"/>
-        <delta pt="63" x="0" y="0"/>
-        <delta pt="64" x="0" y="0"/>
-      </tuple>
-      <tuple>
-        <coord axis="wght" value="1.0"/>
-        <delta pt="0" x="-21" y="1"/>
-        <delta pt="1" x="-21" y="17"/>
-        <delta pt="2" x="-2" y="28"/>
-        <delta pt="3" x="20" y="23"/>
-        <delta pt="4" x="19" y="20"/>
-        <delta pt="5" x="28" y="21"/>
-        <delta pt="6" x="26" y="23"/>
-        <delta pt="7" x="26" y="15"/>
-        <delta pt="8" x="24" y="12"/>
-        <delta pt="9" x="30" y="17"/>
-        <delta pt="10" x="31" y="15"/>
-        <delta pt="11" x="77" y="31"/>
-        <delta pt="12" x="66" y="36"/>
-        <delta pt="13" x="66" y="18"/>
-        <delta pt="14" x="66" y="21"/>
-        <delta pt="15" x="49" y="19"/>
-        <delta pt="16" x="37" y="19"/>
-        <delta pt="17" x="21" y="19"/>
-        <delta pt="18" x="-2" y="5"/>
-        <delta pt="19" x="-34" y="-18"/>
-        <delta pt="20" x="-6" y="3"/>
-        <delta pt="21" x="-11" y="12"/>
-        <delta pt="22" x="-29" y="-11"/>
-        <delta pt="23" x="-17" y="-2"/>
-        <delta pt="24" x="-13" y="-3"/>
-        <delta pt="25" x="-25" y="-3"/>
-        <delta pt="26" x="-29" y="-3"/>
-        <delta pt="27" x="-21" y="2"/>
-        <delta pt="28" x="-34" y="-14"/>
-        <delta pt="29" x="-34" y="17"/>
-        <delta pt="30" x="-34" y="7"/>
-        <delta pt="31" x="-18" y="7"/>
-        <delta pt="32" x="-16" y="7"/>
-        <delta pt="33" x="-18" y="7"/>
-        <delta pt="34" x="-15" y="9"/>
-        <delta pt="35" x="-21" y="12"/>
-        <delta pt="36" x="19" y="23"/>
-        <delta pt="37" x="45" y="46"/>
-        <delta pt="38" x="52" y="7"/>
-        <delta pt="39" x="26" y="-21"/>
-        <delta pt="40" x="14" y="-21"/>
-        <delta pt="41" x="-5" y="-21"/>
-        <delta pt="42" x="-17" y="-7"/>
-        <delta pt="43" x="-31" y="1"/>
-        <delta pt="44" x="-12" y="16"/>
-        <delta pt="45" x="34" y="16"/>
-        <delta pt="46" x="61" y="16"/>
-        <delta pt="47" x="70" y="4"/>
-        <delta pt="48" x="70" y="-5"/>
-        <delta pt="49" x="70" y="-22"/>
-        <delta pt="50" x="70" y="4"/>
-        <delta pt="51" x="59" y="22"/>
-        <delta pt="52" x="50" y="22"/>
-        <delta pt="53" x="43" y="22"/>
-        <delta pt="54" x="37" y="19"/>
-        <delta pt="55" x="38" y="22"/>
-        <delta pt="56" x="47" y="28"/>
-        <delta pt="57" x="46" y="-6"/>
-        <delta pt="58" x="-2" y="-6"/>
-        <delta pt="59" x="-16" y="-6"/>
-        <delta pt="60" x="-25" y="-13"/>
-        <delta pt="61" x="0" y="0"/>
-        <delta pt="62" x="32" y="0"/>
-        <delta pt="63" x="0" y="0"/>
-        <delta pt="64" x="0" y="0"/>
-      </tuple>
-      <tuple>
-        <coord axis="cntr" value="1.0"/>
-        <delta pt="0" x="0" y="-3"/>
-        <delta pt="1" x="0" y="-1"/>
-        <delta pt="2" x="0" y="-3"/>
-        <delta pt="3" x="0" y="-3"/>
-        <delta pt="4" x="0" y="-3"/>
-        <delta pt="5" x="0" y="-3"/>
-        <delta pt="6" x="0" y="-3"/>
-        <delta pt="7" x="0" y="4"/>
-        <delta pt="8" x="0" y="4"/>
-        <delta pt="9" x="2" y="5"/>
-        <delta pt="10" x="6" y="7"/>
-        <delta pt="11" x="1" y="5"/>
-        <delta pt="12" x="0" y="-1"/>
-        <delta pt="13" x="0" y="-6"/>
-        <delta pt="14" x="0" y="-6"/>
-        <delta pt="15" x="-1" y="-6"/>
-        <delta pt="16" x="0" y="-6"/>
-        <delta pt="17" x="0" y="-6"/>
-        <delta pt="18" x="0" y="-5"/>
-        <delta pt="19" x="0" y="-4"/>
-        <delta pt="20" x="0" y="-1"/>
-        <delta pt="21" x="0" y="0"/>
-        <delta pt="22" x="0" y="0"/>
-        <delta pt="23" x="0" y="0"/>
-        <delta pt="24" x="0" y="0"/>
-        <delta pt="25" x="0" y="0"/>
-        <delta pt="26" x="0" y="0"/>
-        <delta pt="27" x="0" y="-1"/>
-        <delta pt="28" x="0" y="-2"/>
-        <delta pt="29" x="0" y="7"/>
-        <delta pt="30" x="0" y="6"/>
-        <delta pt="31" x="0" y="7"/>
-        <delta pt="32" x="0" y="7"/>
-        <delta pt="33" x="0" y="7"/>
-        <delta pt="34" x="0" y="7"/>
-        <delta pt="35" x="0" y="7"/>
-        <delta pt="36" x="0" y="0"/>
-        <delta pt="37" x="0" y="0"/>
-        <delta pt="38" x="0" y="0"/>
-        <delta pt="39" x="0" y="0"/>
-        <delta pt="40" x="0" y="0"/>
-        <delta pt="41" x="0" y="0"/>
-        <delta pt="42" x="0" y="0"/>
-        <delta pt="43" x="0" y="0"/>
-        <delta pt="44" x="0" y="0"/>
-        <delta pt="45" x="0" y="0"/>
-        <delta pt="46" x="0" y="0"/>
-        <delta pt="47" x="0" y="0"/>
-        <delta pt="48" x="0" y="0"/>
-        <delta pt="49" x="0" y="-6"/>
-        <delta pt="50" x="0" y="-7"/>
-        <delta pt="51" x="0" y="-8"/>
-        <delta pt="52" x="0" y="-8"/>
-        <delta pt="53" x="1" y="-8"/>
-        <delta pt="54" x="2" y="-5"/>
-        <delta pt="55" x="4" y="-2"/>
-        <delta pt="56" x="0" y="0"/>
-        <delta pt="57" x="0" y="0"/>
-        <delta pt="58" x="0" y="0"/>
-        <delta pt="59" x="0" y="0"/>
-        <delta pt="60" x="0" y="-1"/>
-        <delta pt="61" x="0" y="0"/>
-        <delta pt="62" x="0" y="0"/>
-        <delta pt="63" x="0" y="0"/>
-        <delta pt="64" x="0" y="0"/>
-      </tuple>
-      <tuple>
-        <coord axis="wght" value="-1.0"/>
-        <coord axis="cntr" value="1.0"/>
-        <delta pt="0" x="0" y="3"/>
-        <delta pt="1" x="0" y="1"/>
-        <delta pt="2" x="0" y="3"/>
-        <delta pt="3" x="0" y="3"/>
-        <delta pt="4" x="0" y="3"/>
-        <delta pt="5" x="0" y="3"/>
-        <delta pt="6" x="0" y="3"/>
-        <delta pt="7" x="0" y="-4"/>
-        <delta pt="8" x="0" y="-4"/>
-        <delta pt="9" x="-2" y="-5"/>
-        <delta pt="10" x="-6" y="-7"/>
-        <delta pt="11" x="-1" y="-5"/>
-        <delta pt="12" x="0" y="1"/>
-        <delta pt="13" x="0" y="6"/>
-        <delta pt="14" x="0" y="6"/>
-        <delta pt="15" x="1" y="6"/>
-        <delta pt="16" x="0" y="6"/>
-        <delta pt="17" x="0" y="6"/>
-        <delta pt="18" x="0" y="5"/>
-        <delta pt="19" x="0" y="4"/>
-        <delta pt="20" x="0" y="1"/>
-        <delta pt="21" x="0" y="0"/>
-        <delta pt="22" x="0" y="0"/>
-        <delta pt="23" x="0" y="0"/>
-        <delta pt="24" x="0" y="0"/>
-        <delta pt="25" x="0" y="0"/>
-        <delta pt="26" x="0" y="0"/>
-        <delta pt="27" x="0" y="1"/>
-        <delta pt="28" x="0" y="2"/>
-        <delta pt="29" x="0" y="-7"/>
-        <delta pt="30" x="0" y="-6"/>
-        <delta pt="31" x="0" y="-7"/>
-        <delta pt="32" x="0" y="-7"/>
-        <delta pt="33" x="0" y="-7"/>
-        <delta pt="34" x="0" y="-7"/>
-        <delta pt="35" x="0" y="-7"/>
-        <delta pt="36" x="0" y="0"/>
-        <delta pt="37" x="0" y="0"/>
-        <delta pt="38" x="0" y="0"/>
-        <delta pt="39" x="0" y="0"/>
-        <delta pt="40" x="0" y="0"/>
-        <delta pt="41" x="0" y="0"/>
-        <delta pt="42" x="0" y="0"/>
-        <delta pt="43" x="0" y="0"/>
-        <delta pt="44" x="0" y="0"/>
-        <delta pt="45" x="0" y="0"/>
-        <delta pt="46" x="0" y="0"/>
-        <delta pt="47" x="0" y="0"/>
-        <delta pt="48" x="0" y="0"/>
-        <delta pt="49" x="0" y="6"/>
-        <delta pt="50" x="0" y="7"/>
-        <delta pt="51" x="0" y="8"/>
-        <delta pt="52" x="0" y="8"/>
-        <delta pt="53" x="-1" y="8"/>
-        <delta pt="54" x="-2" y="5"/>
-        <delta pt="55" x="-4" y="2"/>
-        <delta pt="56" x="0" y="0"/>
-        <delta pt="57" x="0" y="0"/>
-        <delta pt="58" x="0" y="0"/>
-        <delta pt="59" x="0" y="0"/>
-        <delta pt="60" x="0" y="1"/>
-        <delta pt="61" x="0" y="0"/>
-        <delta pt="62" x="0" y="0"/>
-        <delta pt="63" x="0" y="0"/>
-        <delta pt="64" x="0" y="0"/>
-      </tuple>
-      <tuple>
-        <coord axis="wght" value="1.0"/>
-        <coord axis="cntr" value="1.0"/>
-        <delta pt="0" x="0" y="-5"/>
-        <delta pt="1" x="0" y="0"/>
-        <delta pt="2" x="3" y="-4"/>
-        <delta pt="3" x="0" y="-4"/>
-        <delta pt="4" x="0" y="-4"/>
-        <delta pt="5" x="0" y="-4"/>
-        <delta pt="6" x="0" y="-4"/>
-        <delta pt="7" x="0" y="8"/>
-        <delta pt="8" x="0" y="8"/>
-        <delta pt="9" x="5" y="9"/>
-        <delta pt="10" x="11" y="13"/>
-        <delta pt="11" x="2" y="10"/>
-        <delta pt="12" x="0" y="0"/>
-        <delta pt="13" x="0" y="-9"/>
-        <delta pt="14" x="0" y="-9"/>
-        <delta pt="15" x="-1" y="-9"/>
-        <delta pt="16" x="0" y="-9"/>
-        <delta pt="17" x="0" y="-9"/>
-        <delta pt="18" x="0" y="-10"/>
-        <delta pt="19" x="0" y="-8"/>
-        <delta pt="20" x="0" y="-2"/>
-        <delta pt="21" x="0" y="1"/>
-        <delta pt="22" x="0" y="0"/>
-        <delta pt="23" x="1" y="-1"/>
-        <delta pt="24" x="0" y="0"/>
-        <delta pt="25" x="0" y="0"/>
-        <delta pt="26" x="0" y="0"/>
-        <delta pt="27" x="0" y="-1"/>
-        <delta pt="28" x="0" y="-4"/>
-        <delta pt="29" x="0" y="12"/>
-        <delta pt="30" x="0" y="13"/>
-        <delta pt="31" x="0" y="13"/>
-        <delta pt="32" x="0" y="13"/>
-        <delta pt="33" x="0" y="13"/>
-        <delta pt="34" x="0" y="13"/>
-        <delta pt="35" x="0" y="13"/>
-        <delta pt="36" x="0" y="0"/>
-        <delta pt="37" x="0" y="0"/>
-        <delta pt="38" x="0" y="0"/>
-        <delta pt="39" x="0" y="1"/>
-        <delta pt="40" x="0" y="1"/>
-        <delta pt="41" x="0" y="1"/>
-        <delta pt="42" x="0" y="1"/>
-        <delta pt="43" x="0" y="0"/>
-        <delta pt="44" x="0" y="0"/>
-        <delta pt="45" x="0" y="0"/>
-        <delta pt="46" x="0" y="0"/>
-        <delta pt="47" x="0" y="-1"/>
-        <delta pt="48" x="0" y="-1"/>
-        <delta pt="49" x="0" y="-9"/>
-        <delta pt="50" x="0" y="-13"/>
-        <delta pt="51" x="1" y="-14"/>
-        <delta pt="52" x="1" y="-14"/>
-        <delta pt="53" x="2" y="-14"/>
-        <delta pt="54" x="5" y="-11"/>
-        <delta pt="55" x="7" y="-4"/>
-        <delta pt="56" x="0" y="0"/>
-        <delta pt="57" x="0" y="0"/>
-        <delta pt="58" x="0" y="0"/>
-        <delta pt="59" x="0" y="0"/>
-        <delta pt="60" x="1" y="0"/>
-        <delta pt="61" x="0" y="0"/>
-        <delta pt="62" x="0" y="0"/>
-        <delta pt="63" x="0" y="0"/>
-        <delta pt="64" x="0" y="0"/>
-      </tuple>
-    </glyphVariations>
   </gvar>
 
   <ltag>
diff --git a/Tests/varLib/data/test_results/BuildTestCFF2.ttx b/Tests/varLib/data/test_results/BuildTestCFF2.ttx
index c4b9377..2904452 100644
--- a/Tests/varLib/data/test_results/BuildTestCFF2.ttx
+++ b/Tests/varLib/data/test_results/BuildTestCFF2.ttx
@@ -27,31 +27,31 @@
 
     <!-- Regular -->
     <!-- PostScript: TestCFF2Roman-Regular -->
-    <NamedInstance flags="0x0" postscriptNameID="261" subfamilyNameID="2">
+    <NamedInstance flags="0x0" postscriptNameID="262" subfamilyNameID="261">
       <coord axis="wght" value="400.0"/>
     </NamedInstance>
 
     <!-- Medium -->
     <!-- PostScript: TestCFF2Roman-Medium -->
-    <NamedInstance flags="0x0" postscriptNameID="263" subfamilyNameID="262">
+    <NamedInstance flags="0x0" postscriptNameID="264" subfamilyNameID="263">
       <coord axis="wght" value="500.0"/>
     </NamedInstance>
 
     <!-- Semibold -->
     <!-- PostScript: TestCFF2Roman-Semibold -->
-    <NamedInstance flags="0x0" postscriptNameID="265" subfamilyNameID="264">
+    <NamedInstance flags="0x0" postscriptNameID="266" subfamilyNameID="265">
       <coord axis="wght" value="600.0"/>
     </NamedInstance>
 
     <!-- Bold -->
     <!-- PostScript: TestCFF2Roman-Bold -->
-    <NamedInstance flags="0x0" postscriptNameID="267" subfamilyNameID="266">
+    <NamedInstance flags="0x0" postscriptNameID="268" subfamilyNameID="267">
       <coord axis="wght" value="700.0"/>
     </NamedInstance>
 
     <!-- Black -->
     <!-- PostScript: TestCFF2Roman-Black -->
-    <NamedInstance flags="0x0" postscriptNameID="269" subfamilyNameID="268">
+    <NamedInstance flags="0x0" postscriptNameID="270" subfamilyNameID="269">
       <coord axis="wght" value="900.0"/>
     </NamedInstance>
   </fvar>
@@ -91,8 +91,6 @@
             <StdVW>
                 <blend value="85 -51 87"/>
             </StdVW>
-            <LanguageGroup value="0"/>
-            <ExpansionFactor value="0.06"/>
           </Private>
         </FontDict>
       </FDArray>
diff --git a/Tests/varLib/data/test_results/FeatureVars.ttx b/Tests/varLib/data/test_results/FeatureVars.ttx
index ca24f41..93ad795 100644
--- a/Tests/varLib/data/test_results/FeatureVars.ttx
+++ b/Tests/varLib/data/test_results/FeatureVars.ttx
@@ -43,7 +43,7 @@
     <FeatureList>
       <!-- FeatureCount=1 -->
       <FeatureRecord index="0">
-        <FeatureTag value="rclt"/>
+        <FeatureTag value="rvrn"/>
         <Feature>
           <!-- LookupCount=0 -->
         </Feature>
@@ -55,7 +55,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="uni0024" out="uni0024.nostroke"/>
         </SingleSubst>
       </Lookup>
@@ -63,7 +63,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="uni0041" out="uni0061"/>
         </SingleSubst>
       </Lookup>
@@ -71,7 +71,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="uni0061" out="uni0041"/>
         </SingleSubst>
       </Lookup>
diff --git a/Tests/varLib/data/test_results/FeatureVarsCustomTag.ttx b/Tests/varLib/data/test_results/FeatureVarsCustomTag.ttx
deleted file mode 100644
index 3f9e1e0..0000000
--- a/Tests/varLib/data/test_results/FeatureVarsCustomTag.ttx
+++ /dev/null
@@ -1,180 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.29">
-
-  <fvar>
-
-    <!-- Weight -->
-    <Axis>
-      <AxisTag>wght</AxisTag>
-      <Flags>0x0</Flags>
-      <MinValue>0.0</MinValue>
-      <DefaultValue>368.0</DefaultValue>
-      <MaxValue>1000.0</MaxValue>
-      <AxisNameID>256</AxisNameID>
-    </Axis>
-
-    <!-- Contrast -->
-    <Axis>
-      <AxisTag>cntr</AxisTag>
-      <Flags>0x0</Flags>
-      <MinValue>0.0</MinValue>
-      <DefaultValue>0.0</DefaultValue>
-      <MaxValue>100.0</MaxValue>
-      <AxisNameID>257</AxisNameID>
-    </Axis>
-  </fvar>
-
-  <GSUB>
-    <Version value="0x00010001"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=1 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="calt"/>
-        <Feature>
-          <!-- LookupCount=0 -->
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=3 -->
-      <Lookup index="0">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="uni0024" out="uni0024.nostroke"/>
-        </SingleSubst>
-      </Lookup>
-      <Lookup index="1">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="uni0041" out="uni0061"/>
-        </SingleSubst>
-      </Lookup>
-      <Lookup index="2">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="uni0061" out="uni0041"/>
-        </SingleSubst>
-      </Lookup>
-    </LookupList>
-    <FeatureVariations>
-      <Version value="0x00010000"/>
-      <!-- FeatureVariationCount=4 -->
-      <FeatureVariationRecord index="0">
-        <ConditionSet>
-          <!-- ConditionCount=2 -->
-          <ConditionTable index="0" Format="1">
-            <AxisIndex value="1"/>
-            <FilterRangeMinValue value="0.75"/>
-            <FilterRangeMaxValue value="1.0"/>
-          </ConditionTable>
-          <ConditionTable index="1" Format="1">
-            <AxisIndex value="0"/>
-            <FilterRangeMinValue value="0.20886"/>
-            <FilterRangeMaxValue value="1.0"/>
-          </ConditionTable>
-        </ConditionSet>
-        <FeatureTableSubstitution>
-          <Version value="0x00010000"/>
-          <!-- SubstitutionCount=1 -->
-          <SubstitutionRecord index="0">
-            <FeatureIndex value="0"/>
-            <Feature>
-              <!-- LookupCount=2 -->
-              <LookupListIndex index="0" value="0"/>
-              <LookupListIndex index="1" value="1"/>
-            </Feature>
-          </SubstitutionRecord>
-        </FeatureTableSubstitution>
-      </FeatureVariationRecord>
-      <FeatureVariationRecord index="1">
-        <ConditionSet>
-          <!-- ConditionCount=2 -->
-          <ConditionTable index="0" Format="1">
-            <AxisIndex value="1"/>
-            <FilterRangeMinValue value="0.0"/>
-            <FilterRangeMaxValue value="0.25"/>
-          </ConditionTable>
-          <ConditionTable index="1" Format="1">
-            <AxisIndex value="0"/>
-            <FilterRangeMinValue value="-1.0"/>
-            <FilterRangeMaxValue value="-0.45654"/>
-          </ConditionTable>
-        </ConditionSet>
-        <FeatureTableSubstitution>
-          <Version value="0x00010000"/>
-          <!-- SubstitutionCount=1 -->
-          <SubstitutionRecord index="0">
-            <FeatureIndex value="0"/>
-            <Feature>
-              <!-- LookupCount=1 -->
-              <LookupListIndex index="0" value="2"/>
-            </Feature>
-          </SubstitutionRecord>
-        </FeatureTableSubstitution>
-      </FeatureVariationRecord>
-      <FeatureVariationRecord index="2">
-        <ConditionSet>
-          <!-- ConditionCount=1 -->
-          <ConditionTable index="0" Format="1">
-            <AxisIndex value="1"/>
-            <FilterRangeMinValue value="0.75"/>
-            <FilterRangeMaxValue value="1.0"/>
-          </ConditionTable>
-        </ConditionSet>
-        <FeatureTableSubstitution>
-          <Version value="0x00010000"/>
-          <!-- SubstitutionCount=1 -->
-          <SubstitutionRecord index="0">
-            <FeatureIndex value="0"/>
-            <Feature>
-              <!-- LookupCount=1 -->
-              <LookupListIndex index="0" value="1"/>
-            </Feature>
-          </SubstitutionRecord>
-        </FeatureTableSubstitution>
-      </FeatureVariationRecord>
-      <FeatureVariationRecord index="3">
-        <ConditionSet>
-          <!-- ConditionCount=1 -->
-          <ConditionTable index="0" Format="1">
-            <AxisIndex value="0"/>
-            <FilterRangeMinValue value="0.20886"/>
-            <FilterRangeMaxValue value="1.0"/>
-          </ConditionTable>
-        </ConditionSet>
-        <FeatureTableSubstitution>
-          <Version value="0x00010000"/>
-          <!-- SubstitutionCount=1 -->
-          <SubstitutionRecord index="0">
-            <FeatureIndex value="0"/>
-            <Feature>
-              <!-- LookupCount=1 -->
-              <LookupListIndex index="0" value="0"/>
-            </Feature>
-          </SubstitutionRecord>
-        </FeatureTableSubstitution>
-      </FeatureVariationRecord>
-    </FeatureVariations>
-  </GSUB>
-
-</ttFont>
diff --git a/Tests/varLib/data/test_results/FeatureVarsWholeRange.ttx b/Tests/varLib/data/test_results/FeatureVarsWholeRange.ttx
deleted file mode 100644
index 8ae64da..0000000
--- a/Tests/varLib/data/test_results/FeatureVarsWholeRange.ttx
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.9">
-
-  <fvar>
-
-    <!-- Weight -->
-    <Axis>
-      <AxisTag>wght</AxisTag>
-      <Flags>0x0</Flags>
-      <MinValue>0.0</MinValue>
-      <DefaultValue>368.0</DefaultValue>
-      <MaxValue>1000.0</MaxValue>
-      <AxisNameID>256</AxisNameID>
-    </Axis>
-  </fvar>
-
-  <GSUB>
-    <Version value="0x00010001"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="DFLT"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="0"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=0 -->
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=1 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="rclt"/>
-        <Feature>
-          <!-- LookupCount=0 -->
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=1 -->
-      <Lookup index="0">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="uni0024" out="uni0024.nostroke"/>
-        </SingleSubst>
-      </Lookup>
-    </LookupList>
-    <FeatureVariations>
-      <Version value="0x00010000"/>
-      <!-- FeatureVariationCount=1 -->
-      <FeatureVariationRecord index="0">
-        <ConditionSet>
-          <!-- ConditionCount=0 -->
-        </ConditionSet>
-        <FeatureTableSubstitution>
-          <Version value="0x00010000"/>
-          <!-- SubstitutionCount=1 -->
-          <SubstitutionRecord index="0">
-            <FeatureIndex value="0"/>
-            <Feature>
-              <!-- LookupCount=1 -->
-              <LookupListIndex index="0" value="0"/>
-            </Feature>
-          </SubstitutionRecord>
-        </FeatureTableSubstitution>
-      </FeatureVariationRecord>
-    </FeatureVariations>
-  </GSUB>
-
-</ttFont>
diff --git a/Tests/varLib/data/test_results/FeatureVars_rclt.ttx b/Tests/varLib/data/test_results/FeatureVars_rclt.ttx
deleted file mode 100644
index b889f3a..0000000
--- a/Tests/varLib/data/test_results/FeatureVars_rclt.ttx
+++ /dev/null
@@ -1,249 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.29">
-
-  <fvar>
-
-    <!-- Weight -->
-    <Axis>
-      <AxisTag>wght</AxisTag>
-      <Flags>0x0</Flags>
-      <MinValue>0.0</MinValue>
-      <DefaultValue>368.0</DefaultValue>
-      <MaxValue>1000.0</MaxValue>
-      <AxisNameID>256</AxisNameID>
-    </Axis>
-
-    <!-- Contrast -->
-    <Axis>
-      <AxisTag>cntr</AxisTag>
-      <Flags>0x0</Flags>
-      <MinValue>0.0</MinValue>
-      <DefaultValue>0.0</DefaultValue>
-      <MaxValue>100.0</MaxValue>
-      <AxisNameID>257</AxisNameID>
-    </Axis>
-  </fvar>
-
-  <GSUB>
-    <Version value="0x00010001"/>
-    <ScriptList>
-      <!-- ScriptCount=1 -->
-      <ScriptRecord index="0">
-        <ScriptTag value="latn"/>
-        <Script>
-          <DefaultLangSys>
-            <ReqFeatureIndex value="65535"/>
-            <!-- FeatureCount=1 -->
-            <FeatureIndex index="0" value="1"/>
-          </DefaultLangSys>
-          <!-- LangSysCount=1 -->
-          <LangSysRecord index="0">
-            <LangSysTag value="NLD "/>
-            <LangSys>
-              <ReqFeatureIndex value="65535"/>
-              <!-- FeatureCount=1 -->
-              <FeatureIndex index="0" value="0"/>
-            </LangSys>
-          </LangSysRecord>
-        </Script>
-      </ScriptRecord>
-    </ScriptList>
-    <FeatureList>
-      <!-- FeatureCount=2 -->
-      <FeatureRecord index="0">
-        <FeatureTag value="rclt"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="0"/>
-        </Feature>
-      </FeatureRecord>
-      <FeatureRecord index="1">
-        <FeatureTag value="rclt"/>
-        <Feature>
-          <!-- LookupCount=1 -->
-          <LookupListIndex index="0" value="1"/>
-        </Feature>
-      </FeatureRecord>
-    </FeatureList>
-    <LookupList>
-      <!-- LookupCount=5 -->
-      <Lookup index="0">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="uni0041" out="uni0061"/>
-        </SingleSubst>
-      </Lookup>
-      <Lookup index="1">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="uni0041" out="uni0061"/>
-        </SingleSubst>
-      </Lookup>
-      <Lookup index="2">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="uni0024" out="uni0024.nostroke"/>
-        </SingleSubst>
-      </Lookup>
-      <Lookup index="3">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="uni0041" out="uni0061"/>
-        </SingleSubst>
-      </Lookup>
-      <Lookup index="4">
-        <LookupType value="1"/>
-        <LookupFlag value="0"/>
-        <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
-          <Substitution in="uni0061" out="uni0041"/>
-        </SingleSubst>
-      </Lookup>
-    </LookupList>
-    <FeatureVariations>
-      <Version value="0x00010000"/>
-      <!-- FeatureVariationCount=4 -->
-      <FeatureVariationRecord index="0">
-        <ConditionSet>
-          <!-- ConditionCount=2 -->
-          <ConditionTable index="0" Format="1">
-            <AxisIndex value="1"/>
-            <FilterRangeMinValue value="0.75"/>
-            <FilterRangeMaxValue value="1.0"/>
-          </ConditionTable>
-          <ConditionTable index="1" Format="1">
-            <AxisIndex value="0"/>
-            <FilterRangeMinValue value="0.20886"/>
-            <FilterRangeMaxValue value="1.0"/>
-          </ConditionTable>
-        </ConditionSet>
-        <FeatureTableSubstitution>
-          <Version value="0x00010000"/>
-          <!-- SubstitutionCount=2 -->
-          <SubstitutionRecord index="0">
-            <FeatureIndex value="0"/>
-            <Feature>
-              <!-- LookupCount=3 -->
-              <LookupListIndex index="0" value="0"/>
-              <LookupListIndex index="1" value="2"/>
-              <LookupListIndex index="2" value="3"/>
-            </Feature>
-          </SubstitutionRecord>
-          <SubstitutionRecord index="1">
-            <FeatureIndex value="1"/>
-            <Feature>
-              <!-- LookupCount=3 -->
-              <LookupListIndex index="0" value="1"/>
-              <LookupListIndex index="1" value="2"/>
-              <LookupListIndex index="2" value="3"/>
-            </Feature>
-          </SubstitutionRecord>
-        </FeatureTableSubstitution>
-      </FeatureVariationRecord>
-      <FeatureVariationRecord index="1">
-        <ConditionSet>
-          <!-- ConditionCount=2 -->
-          <ConditionTable index="0" Format="1">
-            <AxisIndex value="1"/>
-            <FilterRangeMinValue value="0.0"/>
-            <FilterRangeMaxValue value="0.25"/>
-          </ConditionTable>
-          <ConditionTable index="1" Format="1">
-            <AxisIndex value="0"/>
-            <FilterRangeMinValue value="-1.0"/>
-            <FilterRangeMaxValue value="-0.45654"/>
-          </ConditionTable>
-        </ConditionSet>
-        <FeatureTableSubstitution>
-          <Version value="0x00010000"/>
-          <!-- SubstitutionCount=2 -->
-          <SubstitutionRecord index="0">
-            <FeatureIndex value="0"/>
-            <Feature>
-              <!-- LookupCount=2 -->
-              <LookupListIndex index="0" value="0"/>
-              <LookupListIndex index="1" value="4"/>
-            </Feature>
-          </SubstitutionRecord>
-          <SubstitutionRecord index="1">
-            <FeatureIndex value="1"/>
-            <Feature>
-              <!-- LookupCount=2 -->
-              <LookupListIndex index="0" value="1"/>
-              <LookupListIndex index="1" value="4"/>
-            </Feature>
-          </SubstitutionRecord>
-        </FeatureTableSubstitution>
-      </FeatureVariationRecord>
-      <FeatureVariationRecord index="2">
-        <ConditionSet>
-          <!-- ConditionCount=1 -->
-          <ConditionTable index="0" Format="1">
-            <AxisIndex value="1"/>
-            <FilterRangeMinValue value="0.75"/>
-            <FilterRangeMaxValue value="1.0"/>
-          </ConditionTable>
-        </ConditionSet>
-        <FeatureTableSubstitution>
-          <Version value="0x00010000"/>
-          <!-- SubstitutionCount=2 -->
-          <SubstitutionRecord index="0">
-            <FeatureIndex value="0"/>
-            <Feature>
-              <!-- LookupCount=2 -->
-              <LookupListIndex index="0" value="0"/>
-              <LookupListIndex index="1" value="3"/>
-            </Feature>
-          </SubstitutionRecord>
-          <SubstitutionRecord index="1">
-            <FeatureIndex value="1"/>
-            <Feature>
-              <!-- LookupCount=2 -->
-              <LookupListIndex index="0" value="1"/>
-              <LookupListIndex index="1" value="3"/>
-            </Feature>
-          </SubstitutionRecord>
-        </FeatureTableSubstitution>
-      </FeatureVariationRecord>
-      <FeatureVariationRecord index="3">
-        <ConditionSet>
-          <!-- ConditionCount=1 -->
-          <ConditionTable index="0" Format="1">
-            <AxisIndex value="0"/>
-            <FilterRangeMinValue value="0.20886"/>
-            <FilterRangeMaxValue value="1.0"/>
-          </ConditionTable>
-        </ConditionSet>
-        <FeatureTableSubstitution>
-          <Version value="0x00010000"/>
-          <!-- SubstitutionCount=2 -->
-          <SubstitutionRecord index="0">
-            <FeatureIndex value="0"/>
-            <Feature>
-              <!-- LookupCount=2 -->
-              <LookupListIndex index="0" value="0"/>
-              <LookupListIndex index="1" value="2"/>
-            </Feature>
-          </SubstitutionRecord>
-          <SubstitutionRecord index="1">
-            <FeatureIndex value="1"/>
-            <Feature>
-              <!-- LookupCount=2 -->
-              <LookupListIndex index="0" value="1"/>
-              <LookupListIndex index="1" value="2"/>
-            </Feature>
-          </SubstitutionRecord>
-        </FeatureTableSubstitution>
-      </FeatureVariationRecord>
-    </FeatureVariations>
-  </GSUB>
-
-</ttFont>
diff --git a/Tests/varLib/data/test_results/InterpolateLayout.ttx b/Tests/varLib/data/test_results/InterpolateLayout.ttx
index 81e50fb..b1ea1e9 100644
--- a/Tests/varLib/data/test_results/InterpolateLayout.ttx
+++ b/Tests/varLib/data/test_results/InterpolateLayout.ttx
@@ -93,7 +93,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="A" out="A.sc"/>
         </SingleSubst>
       </Lookup>
@@ -101,7 +101,7 @@
         <LookupType value="1"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <SingleSubst index="0">
+        <SingleSubst index="0" Format="1">
           <Substitution in="a" out="a.alt"/>
         </SingleSubst>
       </Lookup>
@@ -109,7 +109,7 @@
         <LookupType value="2"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <MultipleSubst index="0">
+        <MultipleSubst index="0" Format="1">
           <Substitution in="ampersand" out="a,n,d"/>
         </MultipleSubst>
       </Lookup>
@@ -117,7 +117,7 @@
         <LookupType value="3"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <AlternateSubst index="0">
+        <AlternateSubst index="0" Format="1">
           <AlternateSet glyph="a">
             <Alternate glyph="a.alt"/>
             <Alternate glyph="A.sc"/>
@@ -128,7 +128,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="f">
             <Ligature components="t" glyph="f_t"/>
           </LigatureSet>
@@ -141,11 +141,11 @@
         <ChainContextSubst index="0" Format="3">
           <!-- BacktrackGlyphCount=0 -->
           <!-- InputGlyphCount=1 -->
-          <InputCoverage index="0">
+          <InputCoverage index="0" Format="1">
             <Glyph value="a"/>
           </InputCoverage>
           <!-- LookAheadGlyphCount=1 -->
-          <LookAheadCoverage index="0">
+          <LookAheadCoverage index="0" Format="1">
             <Glyph value="t"/>
           </LookAheadCoverage>
           <!-- SubstCount=1 -->
diff --git a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_1_diff.ttx b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_1_diff.ttx
index 4180a33..74e9cc5 100644
--- a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_1_diff.ttx
+++ b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_1_diff.ttx
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
           </Coverage>
           <ValueFormat value="5"/>
diff --git a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_1_diff2.ttx b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_1_diff2.ttx
index 44a7558..2e21b26 100644
--- a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_1_diff2.ttx
+++ b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_1_diff2.ttx
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
             <Glyph value="a"/>
           </Coverage>
diff --git a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_1_same.ttx b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_1_same.ttx
index 83407c1..a61e75f 100644
--- a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_1_same.ttx
+++ b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_1_same.ttx
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <SinglePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
           </Coverage>
           <ValueFormat value="5"/>
diff --git a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_class_diff.ttx b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_class_diff.ttx
index 0aeb497..4f94c37 100644
--- a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_class_diff.ttx
+++ b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_class_diff.ttx
@@ -34,14 +34,14 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="2">
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="1">
             <ClassDef glyph="a" class="1"/>
           </ClassDef2>
           <!-- Class1Count=1 -->
diff --git a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_class_diff2.ttx b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_class_diff2.ttx
index f00c4c3..811ed58 100644
--- a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_class_diff2.ttx
+++ b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_class_diff2.ttx
@@ -34,16 +34,16 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
             <Glyph value="a"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="1">
             <ClassDef glyph="a" class="1"/>
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="1">
             <ClassDef glyph="a" class="1"/>
           </ClassDef2>
           <!-- Class1Count=2 -->
diff --git a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_class_same.ttx b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_class_same.ttx
index 3656964..9872533 100644
--- a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_class_same.ttx
+++ b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_class_same.ttx
@@ -34,14 +34,14 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="2">
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="1">
             <ClassDef glyph="a" class="1"/>
           </ClassDef2>
           <!-- Class1Count=1 -->
diff --git a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_spec_diff.ttx b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_spec_diff.ttx
index f85985b..113bd0b 100644
--- a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_spec_diff.ttx
+++ b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_spec_diff.ttx
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
           </Coverage>
           <ValueFormat1 value="4"/>
diff --git a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_spec_diff2.ttx b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_spec_diff2.ttx
index b085109..efc5ee5 100644
--- a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_spec_diff2.ttx
+++ b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_spec_diff2.ttx
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
             <Glyph value="a"/>
           </Coverage>
diff --git a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_spec_same.ttx b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_spec_same.ttx
index 2a2a546..014c1ec 100644
--- a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_spec_same.ttx
+++ b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_2_spec_same.ttx
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
           </Coverage>
           <ValueFormat1 value="4"/>
diff --git a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_3_diff.ttx b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_3_diff.ttx
index 993e0a6..65d77f9 100644
--- a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_3_diff.ttx
+++ b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_3_diff.ttx
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <CursivePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="a"/>
           </Coverage>
           <!-- EntryExitCount=1 -->
diff --git a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_3_same.ttx b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_3_same.ttx
index 1d5ebcd..b7c8a25 100644
--- a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_3_same.ttx
+++ b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_3_same.ttx
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <CursivePos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="a"/>
           </Coverage>
           <!-- EntryExitCount=1 -->
diff --git a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_4_diff.ttx b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_4_diff.ttx
index 7c50f96..72a8ccf 100644
--- a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_4_diff.ttx
+++ b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_4_diff.ttx
@@ -34,10 +34,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <MarkBasePos index="0" Format="1">
-          <MarkCoverage>
+          <MarkCoverage Format="1">
             <Glyph value="uni0303"/>
           </MarkCoverage>
-          <BaseCoverage>
+          <BaseCoverage Format="1">
             <Glyph value="a"/>
           </BaseCoverage>
           <!-- ClassCount=1 -->
diff --git a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_4_same.ttx b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_4_same.ttx
index ab96180..9b41519 100644
--- a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_4_same.ttx
+++ b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_4_same.ttx
@@ -34,10 +34,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <MarkBasePos index="0" Format="1">
-          <MarkCoverage>
+          <MarkCoverage Format="1">
             <Glyph value="uni0303"/>
           </MarkCoverage>
-          <BaseCoverage>
+          <BaseCoverage Format="1">
             <Glyph value="a"/>
           </BaseCoverage>
           <!-- ClassCount=1 -->
diff --git a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_5_diff.ttx b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_5_diff.ttx
index 28b5f91..28480e7 100644
--- a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_5_diff.ttx
+++ b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_5_diff.ttx
@@ -34,10 +34,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <MarkLigPos index="0" Format="1">
-          <MarkCoverage>
+          <MarkCoverage Format="1">
             <Glyph value="uni0330"/>
           </MarkCoverage>
-          <LigatureCoverage>
+          <LigatureCoverage Format="1">
             <Glyph value="f_t"/>
           </LigatureCoverage>
           <!-- ClassCount=1 -->
diff --git a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_5_same.ttx b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_5_same.ttx
index 0df08c0..4830f9a 100644
--- a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_5_same.ttx
+++ b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_5_same.ttx
@@ -34,10 +34,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <MarkLigPos index="0" Format="1">
-          <MarkCoverage>
+          <MarkCoverage Format="1">
             <Glyph value="uni0330"/>
           </MarkCoverage>
-          <LigatureCoverage>
+          <LigatureCoverage Format="1">
             <Glyph value="f_t"/>
           </LigatureCoverage>
           <!-- ClassCount=1 -->
diff --git a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_6_diff.ttx b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_6_diff.ttx
index 667d4f1..38d6437 100644
--- a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_6_diff.ttx
+++ b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_6_diff.ttx
@@ -34,10 +34,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <MarkMarkPos index="0" Format="1">
-          <Mark1Coverage>
+          <Mark1Coverage Format="1">
             <Glyph value="uni0303"/>
           </Mark1Coverage>
-          <Mark2Coverage>
+          <Mark2Coverage Format="1">
             <Glyph value="uni0308"/>
           </Mark2Coverage>
           <!-- ClassCount=1 -->
diff --git a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_6_same.ttx b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_6_same.ttx
index 34d0bff..05e4b51 100644
--- a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_6_same.ttx
+++ b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_6_same.ttx
@@ -34,10 +34,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <MarkMarkPos index="0" Format="1">
-          <Mark1Coverage>
+          <Mark1Coverage Format="1">
             <Glyph value="uni0303"/>
           </Mark1Coverage>
-          <Mark2Coverage>
+          <Mark2Coverage Format="1">
             <Glyph value="uni0308"/>
           </Mark2Coverage>
           <!-- ClassCount=1 -->
diff --git a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_7_diff.ttx b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_8_diff.ttx
similarity index 73%
rename from Tests/varLib/data/test_results/InterpolateLayoutGPOS_7_diff.ttx
rename to Tests/varLib/data/test_results/InterpolateLayoutGPOS_8_diff.ttx
index 14e1209..12f4269 100644
--- a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_7_diff.ttx
+++ b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_8_diff.ttx
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
           </Coverage>
           <ValueFormat1 value="4"/>
@@ -54,10 +54,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <MarkBasePos index="0" Format="1">
-          <MarkCoverage>
+          <MarkCoverage Format="1">
             <Glyph value="uni0303"/>
           </MarkCoverage>
-          <BaseCoverage>
+          <BaseCoverage Format="1">
             <Glyph value="a"/>
           </BaseCoverage>
           <!-- ClassCount=1 -->
@@ -83,32 +83,32 @@
         </MarkBasePos>
       </Lookup>
       <Lookup index="2">
-        <LookupType value="7"/>
+        <LookupType value="8"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <ContextPos index="0" Format="1">
-          <Coverage>
+        <ChainContextPos index="0" Format="3">
+          <!-- BacktrackGlyphCount=0 -->
+          <!-- InputGlyphCount=3 -->
+          <InputCoverage index="0" Format="1">
             <Glyph value="A"/>
-          </Coverage>
-          <!-- PosRuleSetCount=1 -->
-          <PosRuleSet index="0">
-            <!-- PosRuleCount=1 -->
-            <PosRule index="0">
-              <!-- GlyphCount=3 -->
-              <!-- PosCount=2 -->
-              <Input index="0" value="a"/>
-              <Input index="1" value="uni0303"/>
-              <PosLookupRecord index="0">
-                <SequenceIndex value="0"/>
-                <LookupListIndex value="0"/>
-              </PosLookupRecord>
-              <PosLookupRecord index="1">
-                <SequenceIndex value="2"/>
-                <LookupListIndex value="1"/>
-              </PosLookupRecord>
-            </PosRule>
-          </PosRuleSet>
-        </ContextPos>
+          </InputCoverage>
+          <InputCoverage index="1" Format="1">
+            <Glyph value="a"/>
+          </InputCoverage>
+          <InputCoverage index="2" Format="1">
+            <Glyph value="uni0303"/>
+          </InputCoverage>
+          <!-- LookAheadGlyphCount=0 -->
+          <!-- PosCount=2 -->
+          <PosLookupRecord index="0">
+            <SequenceIndex value="0"/>
+            <LookupListIndex value="0"/>
+          </PosLookupRecord>
+          <PosLookupRecord index="1">
+            <SequenceIndex value="2"/>
+            <LookupListIndex value="1"/>
+          </PosLookupRecord>
+        </ChainContextPos>
       </Lookup>
     </LookupList>
   </GPOS>
diff --git a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_7_same.ttx b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_8_same.ttx
similarity index 73%
rename from Tests/varLib/data/test_results/InterpolateLayoutGPOS_7_same.ttx
rename to Tests/varLib/data/test_results/InterpolateLayoutGPOS_8_same.ttx
index eff24fc..b7e86ba 100644
--- a/Tests/varLib/data/test_results/InterpolateLayoutGPOS_7_same.ttx
+++ b/Tests/varLib/data/test_results/InterpolateLayoutGPOS_8_same.ttx
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
           </Coverage>
           <ValueFormat1 value="4"/>
@@ -54,10 +54,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <MarkBasePos index="0" Format="1">
-          <MarkCoverage>
+          <MarkCoverage Format="1">
             <Glyph value="uni0303"/>
           </MarkCoverage>
-          <BaseCoverage>
+          <BaseCoverage Format="1">
             <Glyph value="a"/>
           </BaseCoverage>
           <!-- ClassCount=1 -->
@@ -83,32 +83,32 @@
         </MarkBasePos>
       </Lookup>
       <Lookup index="2">
-        <LookupType value="7"/>
+        <LookupType value="8"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <ContextPos index="0" Format="1">
-          <Coverage>
+        <ChainContextPos index="0" Format="3">
+          <!-- BacktrackGlyphCount=0 -->
+          <!-- InputGlyphCount=3 -->
+          <InputCoverage index="0" Format="1">
             <Glyph value="A"/>
-          </Coverage>
-          <!-- PosRuleSetCount=1 -->
-          <PosRuleSet index="0">
-            <!-- PosRuleCount=1 -->
-            <PosRule index="0">
-              <!-- GlyphCount=3 -->
-              <!-- PosCount=2 -->
-              <Input index="0" value="a"/>
-              <Input index="1" value="uni0303"/>
-              <PosLookupRecord index="0">
-                <SequenceIndex value="0"/>
-                <LookupListIndex value="0"/>
-              </PosLookupRecord>
-              <PosLookupRecord index="1">
-                <SequenceIndex value="2"/>
-                <LookupListIndex value="1"/>
-              </PosLookupRecord>
-            </PosRule>
-          </PosRuleSet>
-        </ContextPos>
+          </InputCoverage>
+          <InputCoverage index="1" Format="1">
+            <Glyph value="a"/>
+          </InputCoverage>
+          <InputCoverage index="2" Format="1">
+            <Glyph value="uni0303"/>
+          </InputCoverage>
+          <!-- LookAheadGlyphCount=0 -->
+          <!-- PosCount=2 -->
+          <PosLookupRecord index="0">
+            <SequenceIndex value="0"/>
+            <LookupListIndex value="0"/>
+          </PosLookupRecord>
+          <PosLookupRecord index="1">
+            <SequenceIndex value="2"/>
+            <LookupListIndex value="1"/>
+          </PosLookupRecord>
+        </ChainContextPos>
       </Lookup>
     </LookupList>
   </GPOS>
diff --git a/Tests/varLib/data/test_results/InterpolateLayoutMain.ttx b/Tests/varLib/data/test_results/InterpolateLayoutMain.ttx
index 49d491f..6a0635d 100644
--- a/Tests/varLib/data/test_results/InterpolateLayoutMain.ttx
+++ b/Tests/varLib/data/test_results/InterpolateLayoutMain.ttx
@@ -498,7 +498,7 @@
 
   <GDEF>
     <Version value="0x00010003"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="uni0024" class="1"/>
       <ClassDef glyph="uni0024.nostroke" class="1"/>
       <ClassDef glyph="uni0041" class="1"/>
diff --git a/Tests/varLib/data/test_results/InterpolateTestCFF2VF.ttx b/Tests/varLib/data/test_results/InterpolateTestCFF2VF.ttx
index 949e6da..e2d0f71 100644
--- a/Tests/varLib/data/test_results/InterpolateTestCFF2VF.ttx
+++ b/Tests/varLib/data/test_results/InterpolateTestCFF2VF.ttx
@@ -24,8 +24,6 @@
             <BlueFuzz value="0"/>
             <StdHW value="28"/>
             <StdVW value="34"/>
-            <LanguageGroup value="0"/>
-            <ExpansionFactor value="0.06"/>
           </Private>
         </FontDict>
       </FDArray>
diff --git a/Tests/varLib/data/test_results/Mutator.ttx b/Tests/varLib/data/test_results/Mutator.ttx
index 71e5f28..75a0879 100644
--- a/Tests/varLib/data/test_results/Mutator.ttx
+++ b/Tests/varLib/data/test_results/Mutator.ttx
@@ -498,7 +498,7 @@
 
   <GDEF>
     <Version value="0x00010000"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="2">
       <ClassDef glyph="uni0024" class="1"/>
       <ClassDef glyph="uni0024.nostroke" class="1"/>
       <ClassDef glyph="uni0041" class="1"/>
diff --git a/Tests/varLib/instancer/data/test_results/PartialInstancerTest2-VF-instance-100,100.ttx b/Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-100,100.ttx
similarity index 86%
rename from Tests/varLib/instancer/data/test_results/PartialInstancerTest2-VF-instance-100,100.ttx
rename to Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-100,100.ttx
index 776a92f..c64049f 100644
--- a/Tests/varLib/instancer/data/test_results/PartialInstancerTest2-VF-instance-100,100.ttx
+++ b/Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-100,100.ttx
@@ -14,12 +14,12 @@
     <!-- Most of this table will be recalculated by the compiler -->
     <tableVersion value="1.0"/>
     <fontRevision value="2.001"/>
-    <checkSumAdjustment value="0x90f1c28"/>
+    <checkSumAdjustment value="0x982d27a8"/>
     <magicNumber value="0x5f0f3cf5"/>
     <flags value="00000000 00000011"/>
     <unitsPerEm value="1000"/>
     <created value="Tue Mar 15 19:50:39 2016"/>
-    <modified value="Thu Oct 17 14:43:10 2019"/>
+    <modified value="Tue May 21 16:23:19 2019"/>
     <xMin value="0"/>
     <yMin value="0"/>
     <xMax value="577"/>
@@ -238,18 +238,6 @@
   </glyf>
 
   <name>
-    <namerecord nameID="256" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Weight
-    </namerecord>
-    <namerecord nameID="257" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Width
-    </namerecord>
-    <namerecord nameID="258" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Thin
-    </namerecord>
-    <namerecord nameID="261" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Regular
-    </namerecord>
     <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
       Copyright 2015 Google Inc. All Rights Reserved.
     </namerecord>
@@ -295,18 +283,6 @@
     <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
       http://scripts.sil.org/OFL
     </namerecord>
-    <namerecord nameID="256" platformID="3" platEncID="1" langID="0x409">
-      Weight
-    </namerecord>
-    <namerecord nameID="257" platformID="3" platEncID="1" langID="0x409">
-      Width
-    </namerecord>
-    <namerecord nameID="258" platformID="3" platEncID="1" langID="0x409">
-      Thin
-    </namerecord>
-    <namerecord nameID="261" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
   </name>
 
   <post>
@@ -335,7 +311,7 @@
 
   <GDEF>
     <Version value="0x00010002"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="1">
       <ClassDef glyph="A" class="1"/>
       <ClassDef glyph="Agrave" class="1"/>
       <ClassDef glyph="T" class="1"/>
@@ -343,13 +319,13 @@
     <MarkGlyphSetsDef>
       <MarkSetTableFormat value="1"/>
       <!-- MarkSetCount=4 -->
-      <Coverage index="0">
+      <Coverage index="0" Format="1">
       </Coverage>
-      <Coverage index="1">
+      <Coverage index="1" Format="1">
       </Coverage>
-      <Coverage index="2">
+      <Coverage index="2" Format="1">
       </Coverage>
-      <Coverage index="3">
+      <Coverage index="3" Format="1">
       </Coverage>
     </MarkGlyphSetsDef>
   </GDEF>
@@ -417,20 +393,20 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
             <Glyph value="T"/>
             <Glyph value="Agrave"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="1">
             <ClassDef glyph="T" class="1"/>
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="1">
             <ClassDef glyph="A" class="1"/>
             <ClassDef glyph="Agrave" class="1"/>
             <ClassDef glyph="T" class="2"/>
@@ -505,40 +481,4 @@
     </LookupList>
   </GSUB>
 
-  <STAT>
-    <Version value="0x00010001"/>
-    <DesignAxisRecordSize value="8"/>
-    <!-- DesignAxisCount=2 -->
-    <DesignAxisRecord>
-      <Axis index="0">
-        <AxisTag value="wght"/>
-        <AxisNameID value="256"/>  <!-- Weight -->
-        <AxisOrdering value="1"/>
-      </Axis>
-      <Axis index="1">
-        <AxisTag value="wdth"/>
-        <AxisNameID value="257"/>  <!-- Width -->
-        <AxisOrdering value="0"/>
-      </Axis>
-    </DesignAxisRecord>
-    <!-- AxisValueCount=2 -->
-    <AxisValueArray>
-      <AxisValue index="0" Format="1">
-        <AxisIndex value="0"/>
-        <Flags value="0"/>
-        <ValueNameID value="258"/>  <!-- Thin -->
-        <Value value="100.0"/>
-      </AxisValue>
-      <AxisValue index="1" Format="2">
-        <AxisIndex value="1"/>
-        <Flags value="2"/>  <!-- ElidableAxisValueName -->
-        <ValueNameID value="261"/>  <!-- Regular -->
-        <NominalValue value="100.0"/>
-        <RangeMinValue value="93.75"/>
-        <RangeMaxValue value="100.0"/>
-      </AxisValue>
-    </AxisValueArray>
-    <ElidedFallbackNameID value="2"/>  <!-- Regular -->
-  </STAT>
-
 </ttFont>
diff --git a/Tests/varLib/instancer/data/test_results/PartialInstancerTest2-VF-instance-100,62.5.ttx b/Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-100,62.5.ttx
similarity index 86%
rename from Tests/varLib/instancer/data/test_results/PartialInstancerTest2-VF-instance-100,62.5.ttx
rename to Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-100,62.5.ttx
index 61bc41c..87d0c65 100644
--- a/Tests/varLib/instancer/data/test_results/PartialInstancerTest2-VF-instance-100,62.5.ttx
+++ b/Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-100,62.5.ttx
@@ -14,12 +14,12 @@
     <!-- Most of this table will be recalculated by the compiler -->
     <tableVersion value="1.0"/>
     <fontRevision value="2.001"/>
-    <checkSumAdjustment value="0x31525751"/>
+    <checkSumAdjustment value="0x1d4f3a2e"/>
     <magicNumber value="0x5f0f3cf5"/>
     <flags value="00000000 00000011"/>
     <unitsPerEm value="1000"/>
     <created value="Tue Mar 15 19:50:39 2016"/>
-    <modified value="Thu Oct 17 14:43:10 2019"/>
+    <modified value="Tue May 21 16:23:19 2019"/>
     <xMin value="0"/>
     <yMin value="0"/>
     <xMax value="496"/>
@@ -238,18 +238,6 @@
   </glyf>
 
   <name>
-    <namerecord nameID="256" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Weight
-    </namerecord>
-    <namerecord nameID="257" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Width
-    </namerecord>
-    <namerecord nameID="258" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Thin
-    </namerecord>
-    <namerecord nameID="288" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      ExtraCondensed
-    </namerecord>
     <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
       Copyright 2015 Google Inc. All Rights Reserved.
     </namerecord>
@@ -295,18 +283,6 @@
     <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
       http://scripts.sil.org/OFL
     </namerecord>
-    <namerecord nameID="256" platformID="3" platEncID="1" langID="0x409">
-      Weight
-    </namerecord>
-    <namerecord nameID="257" platformID="3" platEncID="1" langID="0x409">
-      Width
-    </namerecord>
-    <namerecord nameID="258" platformID="3" platEncID="1" langID="0x409">
-      Thin
-    </namerecord>
-    <namerecord nameID="288" platformID="3" platEncID="1" langID="0x409">
-      ExtraCondensed
-    </namerecord>
   </name>
 
   <post>
@@ -335,7 +311,7 @@
 
   <GDEF>
     <Version value="0x00010002"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="1">
       <ClassDef glyph="A" class="1"/>
       <ClassDef glyph="Agrave" class="1"/>
       <ClassDef glyph="T" class="1"/>
@@ -343,13 +319,13 @@
     <MarkGlyphSetsDef>
       <MarkSetTableFormat value="1"/>
       <!-- MarkSetCount=4 -->
-      <Coverage index="0">
+      <Coverage index="0" Format="1">
       </Coverage>
-      <Coverage index="1">
+      <Coverage index="1" Format="1">
       </Coverage>
-      <Coverage index="2">
+      <Coverage index="2" Format="1">
       </Coverage>
-      <Coverage index="3">
+      <Coverage index="3" Format="1">
       </Coverage>
     </MarkGlyphSetsDef>
   </GDEF>
@@ -417,20 +393,20 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
             <Glyph value="T"/>
             <Glyph value="Agrave"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="1">
             <ClassDef glyph="T" class="1"/>
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="1">
             <ClassDef glyph="A" class="1"/>
             <ClassDef glyph="Agrave" class="1"/>
             <ClassDef glyph="T" class="2"/>
@@ -505,40 +481,4 @@
     </LookupList>
   </GSUB>
 
-  <STAT>
-    <Version value="0x00010001"/>
-    <DesignAxisRecordSize value="8"/>
-    <!-- DesignAxisCount=2 -->
-    <DesignAxisRecord>
-      <Axis index="0">
-        <AxisTag value="wght"/>
-        <AxisNameID value="256"/>  <!-- Weight -->
-        <AxisOrdering value="1"/>
-      </Axis>
-      <Axis index="1">
-        <AxisTag value="wdth"/>
-        <AxisNameID value="257"/>  <!-- Width -->
-        <AxisOrdering value="0"/>
-      </Axis>
-    </DesignAxisRecord>
-    <!-- AxisValueCount=2 -->
-    <AxisValueArray>
-      <AxisValue index="0" Format="1">
-        <AxisIndex value="0"/>
-        <Flags value="0"/>
-        <ValueNameID value="258"/>  <!-- Thin -->
-        <Value value="100.0"/>
-      </AxisValue>
-      <AxisValue index="1" Format="2">
-        <AxisIndex value="1"/>
-        <Flags value="0"/>
-        <ValueNameID value="288"/>  <!-- ExtraCondensed -->
-        <NominalValue value="62.5"/>
-        <RangeMinValue value="62.5"/>
-        <RangeMaxValue value="68.75"/>
-      </AxisValue>
-    </AxisValueArray>
-    <ElidedFallbackNameID value="2"/>  <!-- Regular -->
-  </STAT>
-
 </ttFont>
diff --git a/Tests/varLib/instancer/data/test_results/PartialInstancerTest2-VF-instance-400,100.ttx b/Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-400,100.ttx
similarity index 87%
rename from Tests/varLib/instancer/data/test_results/PartialInstancerTest2-VF-instance-400,100.ttx
rename to Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-400,100.ttx
index c2d2057..fc64365 100644
--- a/Tests/varLib/instancer/data/test_results/PartialInstancerTest2-VF-instance-400,100.ttx
+++ b/Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-400,100.ttx
@@ -14,12 +14,12 @@
     <!-- Most of this table will be recalculated by the compiler -->
     <tableVersion value="1.0"/>
     <fontRevision value="2.001"/>
-    <checkSumAdjustment value="0x4b2d3480"/>
+    <checkSumAdjustment value="0xf43664b4"/>
     <magicNumber value="0x5f0f3cf5"/>
     <flags value="00000000 00000011"/>
     <unitsPerEm value="1000"/>
     <created value="Tue Mar 15 19:50:39 2016"/>
-    <modified value="Thu Oct 17 14:43:10 2019"/>
+    <modified value="Tue May 21 16:23:19 2019"/>
     <xMin value="0"/>
     <yMin value="0"/>
     <xMax value="638"/>
@@ -238,15 +238,6 @@
   </glyf>
 
   <name>
-    <namerecord nameID="256" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Weight
-    </namerecord>
-    <namerecord nameID="257" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Width
-    </namerecord>
-    <namerecord nameID="261" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Regular
-    </namerecord>
     <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
       Copyright 2015 Google Inc. All Rights Reserved.
     </namerecord>
@@ -292,15 +283,6 @@
     <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
       http://scripts.sil.org/OFL
     </namerecord>
-    <namerecord nameID="256" platformID="3" platEncID="1" langID="0x409">
-      Weight
-    </namerecord>
-    <namerecord nameID="257" platformID="3" platEncID="1" langID="0x409">
-      Width
-    </namerecord>
-    <namerecord nameID="261" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
   </name>
 
   <post>
@@ -329,7 +311,7 @@
 
   <GDEF>
     <Version value="0x00010002"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="1">
       <ClassDef glyph="A" class="1"/>
       <ClassDef glyph="Agrave" class="1"/>
       <ClassDef glyph="T" class="1"/>
@@ -337,13 +319,13 @@
     <MarkGlyphSetsDef>
       <MarkSetTableFormat value="1"/>
       <!-- MarkSetCount=4 -->
-      <Coverage index="0">
+      <Coverage index="0" Format="1">
       </Coverage>
-      <Coverage index="1">
+      <Coverage index="1" Format="1">
       </Coverage>
-      <Coverage index="2">
+      <Coverage index="2" Format="1">
       </Coverage>
-      <Coverage index="3">
+      <Coverage index="3" Format="1">
       </Coverage>
     </MarkGlyphSetsDef>
   </GDEF>
@@ -411,20 +393,20 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
             <Glyph value="T"/>
             <Glyph value="Agrave"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="1">
             <ClassDef glyph="T" class="1"/>
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="1">
             <ClassDef glyph="A" class="1"/>
             <ClassDef glyph="Agrave" class="1"/>
             <ClassDef glyph="T" class="2"/>
@@ -499,41 +481,4 @@
     </LookupList>
   </GSUB>
 
-  <STAT>
-    <Version value="0x00010001"/>
-    <DesignAxisRecordSize value="8"/>
-    <!-- DesignAxisCount=2 -->
-    <DesignAxisRecord>
-      <Axis index="0">
-        <AxisTag value="wght"/>
-        <AxisNameID value="256"/>  <!-- Weight -->
-        <AxisOrdering value="1"/>
-      </Axis>
-      <Axis index="1">
-        <AxisTag value="wdth"/>
-        <AxisNameID value="257"/>  <!-- Width -->
-        <AxisOrdering value="0"/>
-      </Axis>
-    </DesignAxisRecord>
-    <!-- AxisValueCount=2 -->
-    <AxisValueArray>
-      <AxisValue index="0" Format="3">
-        <AxisIndex value="0"/>
-        <Flags value="2"/>  <!-- ElidableAxisValueName -->
-        <ValueNameID value="261"/>  <!-- Regular -->
-        <Value value="400.0"/>
-        <LinkedValue value="700.0"/>
-      </AxisValue>
-      <AxisValue index="1" Format="2">
-        <AxisIndex value="1"/>
-        <Flags value="2"/>  <!-- ElidableAxisValueName -->
-        <ValueNameID value="261"/>  <!-- Regular -->
-        <NominalValue value="100.0"/>
-        <RangeMinValue value="93.75"/>
-        <RangeMaxValue value="100.0"/>
-      </AxisValue>
-    </AxisValueArray>
-    <ElidedFallbackNameID value="2"/>  <!-- Regular -->
-  </STAT>
-
 </ttFont>
diff --git a/Tests/varLib/instancer/data/test_results/PartialInstancerTest2-VF-instance-400,62.5.ttx b/Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-400,62.5.ttx
similarity index 86%
rename from Tests/varLib/instancer/data/test_results/PartialInstancerTest2-VF-instance-400,62.5.ttx
rename to Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-400,62.5.ttx
index 63eeb0e..9b40106 100644
--- a/Tests/varLib/instancer/data/test_results/PartialInstancerTest2-VF-instance-400,62.5.ttx
+++ b/Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-400,62.5.ttx
@@ -14,12 +14,12 @@
     <!-- Most of this table will be recalculated by the compiler -->
     <tableVersion value="1.0"/>
     <fontRevision value="2.001"/>
-    <checkSumAdjustment value="0x39ab2622"/>
+    <checkSumAdjustment value="0xd9290bac"/>
     <magicNumber value="0x5f0f3cf5"/>
     <flags value="00000000 00000011"/>
     <unitsPerEm value="1000"/>
     <created value="Tue Mar 15 19:50:39 2016"/>
-    <modified value="Thu Oct 17 14:43:10 2019"/>
+    <modified value="Tue May 21 16:23:19 2019"/>
     <xMin value="0"/>
     <yMin value="0"/>
     <xMax value="496"/>
@@ -238,18 +238,6 @@
   </glyf>
 
   <name>
-    <namerecord nameID="256" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Weight
-    </namerecord>
-    <namerecord nameID="257" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Width
-    </namerecord>
-    <namerecord nameID="261" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Regular
-    </namerecord>
-    <namerecord nameID="288" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      ExtraCondensed
-    </namerecord>
     <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
       Copyright 2015 Google Inc. All Rights Reserved.
     </namerecord>
@@ -295,18 +283,6 @@
     <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
       http://scripts.sil.org/OFL
     </namerecord>
-    <namerecord nameID="256" platformID="3" platEncID="1" langID="0x409">
-      Weight
-    </namerecord>
-    <namerecord nameID="257" platformID="3" platEncID="1" langID="0x409">
-      Width
-    </namerecord>
-    <namerecord nameID="261" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="288" platformID="3" platEncID="1" langID="0x409">
-      ExtraCondensed
-    </namerecord>
   </name>
 
   <post>
@@ -335,7 +311,7 @@
 
   <GDEF>
     <Version value="0x00010002"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="1">
       <ClassDef glyph="A" class="1"/>
       <ClassDef glyph="Agrave" class="1"/>
       <ClassDef glyph="T" class="1"/>
@@ -343,13 +319,13 @@
     <MarkGlyphSetsDef>
       <MarkSetTableFormat value="1"/>
       <!-- MarkSetCount=4 -->
-      <Coverage index="0">
+      <Coverage index="0" Format="1">
       </Coverage>
-      <Coverage index="1">
+      <Coverage index="1" Format="1">
       </Coverage>
-      <Coverage index="2">
+      <Coverage index="2" Format="1">
       </Coverage>
-      <Coverage index="3">
+      <Coverage index="3" Format="1">
       </Coverage>
     </MarkGlyphSetsDef>
   </GDEF>
@@ -417,20 +393,20 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
             <Glyph value="T"/>
             <Glyph value="Agrave"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="1">
             <ClassDef glyph="T" class="1"/>
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="1">
             <ClassDef glyph="A" class="1"/>
             <ClassDef glyph="Agrave" class="1"/>
             <ClassDef glyph="T" class="2"/>
@@ -505,41 +481,4 @@
     </LookupList>
   </GSUB>
 
-  <STAT>
-    <Version value="0x00010001"/>
-    <DesignAxisRecordSize value="8"/>
-    <!-- DesignAxisCount=2 -->
-    <DesignAxisRecord>
-      <Axis index="0">
-        <AxisTag value="wght"/>
-        <AxisNameID value="256"/>  <!-- Weight -->
-        <AxisOrdering value="1"/>
-      </Axis>
-      <Axis index="1">
-        <AxisTag value="wdth"/>
-        <AxisNameID value="257"/>  <!-- Width -->
-        <AxisOrdering value="0"/>
-      </Axis>
-    </DesignAxisRecord>
-    <!-- AxisValueCount=2 -->
-    <AxisValueArray>
-      <AxisValue index="0" Format="3">
-        <AxisIndex value="0"/>
-        <Flags value="2"/>  <!-- ElidableAxisValueName -->
-        <ValueNameID value="261"/>  <!-- Regular -->
-        <Value value="400.0"/>
-        <LinkedValue value="700.0"/>
-      </AxisValue>
-      <AxisValue index="1" Format="2">
-        <AxisIndex value="1"/>
-        <Flags value="0"/>
-        <ValueNameID value="288"/>  <!-- ExtraCondensed -->
-        <NominalValue value="62.5"/>
-        <RangeMinValue value="62.5"/>
-        <RangeMaxValue value="68.75"/>
-      </AxisValue>
-    </AxisValueArray>
-    <ElidedFallbackNameID value="2"/>  <!-- Regular -->
-  </STAT>
-
 </ttFont>
diff --git a/Tests/varLib/instancer/data/test_results/PartialInstancerTest2-VF-instance-900,100.ttx b/Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-900,100.ttx
similarity index 86%
rename from Tests/varLib/instancer/data/test_results/PartialInstancerTest2-VF-instance-900,100.ttx
rename to Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-900,100.ttx
index 013ba1e..8f85179 100644
--- a/Tests/varLib/instancer/data/test_results/PartialInstancerTest2-VF-instance-900,100.ttx
+++ b/Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-900,100.ttx
@@ -14,12 +14,12 @@
     <!-- Most of this table will be recalculated by the compiler -->
     <tableVersion value="1.0"/>
     <fontRevision value="2.001"/>
-    <checkSumAdjustment value="0x7b5e7903"/>
+    <checkSumAdjustment value="0xa514fda"/>
     <magicNumber value="0x5f0f3cf5"/>
     <flags value="00000000 00000011"/>
     <unitsPerEm value="1000"/>
     <created value="Tue Mar 15 19:50:39 2016"/>
-    <modified value="Thu Oct 17 14:43:10 2019"/>
+    <modified value="Tue May 21 16:23:19 2019"/>
     <xMin value="0"/>
     <yMin value="0"/>
     <xMax value="726"/>
@@ -238,18 +238,6 @@
   </glyf>
 
   <name>
-    <namerecord nameID="256" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Weight
-    </namerecord>
-    <namerecord nameID="257" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Width
-    </namerecord>
-    <namerecord nameID="261" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Regular
-    </namerecord>
-    <namerecord nameID="266" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Black
-    </namerecord>
     <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
       Copyright 2015 Google Inc. All Rights Reserved.
     </namerecord>
@@ -295,18 +283,6 @@
     <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
       http://scripts.sil.org/OFL
     </namerecord>
-    <namerecord nameID="256" platformID="3" platEncID="1" langID="0x409">
-      Weight
-    </namerecord>
-    <namerecord nameID="257" platformID="3" platEncID="1" langID="0x409">
-      Width
-    </namerecord>
-    <namerecord nameID="261" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="266" platformID="3" platEncID="1" langID="0x409">
-      Black
-    </namerecord>
   </name>
 
   <post>
@@ -335,7 +311,7 @@
 
   <GDEF>
     <Version value="0x00010002"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="1">
       <ClassDef glyph="A" class="1"/>
       <ClassDef glyph="Agrave" class="1"/>
       <ClassDef glyph="T" class="1"/>
@@ -343,13 +319,13 @@
     <MarkGlyphSetsDef>
       <MarkSetTableFormat value="1"/>
       <!-- MarkSetCount=4 -->
-      <Coverage index="0">
+      <Coverage index="0" Format="1">
       </Coverage>
-      <Coverage index="1">
+      <Coverage index="1" Format="1">
       </Coverage>
-      <Coverage index="2">
+      <Coverage index="2" Format="1">
       </Coverage>
-      <Coverage index="3">
+      <Coverage index="3" Format="1">
       </Coverage>
     </MarkGlyphSetsDef>
   </GDEF>
@@ -417,20 +393,20 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
             <Glyph value="T"/>
             <Glyph value="Agrave"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="1">
             <ClassDef glyph="T" class="1"/>
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="1">
             <ClassDef glyph="A" class="1"/>
             <ClassDef glyph="Agrave" class="1"/>
             <ClassDef glyph="T" class="2"/>
@@ -505,40 +481,4 @@
     </LookupList>
   </GSUB>
 
-  <STAT>
-    <Version value="0x00010001"/>
-    <DesignAxisRecordSize value="8"/>
-    <!-- DesignAxisCount=2 -->
-    <DesignAxisRecord>
-      <Axis index="0">
-        <AxisTag value="wght"/>
-        <AxisNameID value="256"/>  <!-- Weight -->
-        <AxisOrdering value="1"/>
-      </Axis>
-      <Axis index="1">
-        <AxisTag value="wdth"/>
-        <AxisNameID value="257"/>  <!-- Width -->
-        <AxisOrdering value="0"/>
-      </Axis>
-    </DesignAxisRecord>
-    <!-- AxisValueCount=2 -->
-    <AxisValueArray>
-      <AxisValue index="0" Format="1">
-        <AxisIndex value="0"/>
-        <Flags value="0"/>
-        <ValueNameID value="266"/>  <!-- Black -->
-        <Value value="900.0"/>
-      </AxisValue>
-      <AxisValue index="1" Format="2">
-        <AxisIndex value="1"/>
-        <Flags value="2"/>  <!-- ElidableAxisValueName -->
-        <ValueNameID value="261"/>  <!-- Regular -->
-        <NominalValue value="100.0"/>
-        <RangeMinValue value="93.75"/>
-        <RangeMaxValue value="100.0"/>
-      </AxisValue>
-    </AxisValueArray>
-    <ElidedFallbackNameID value="2"/>  <!-- Regular -->
-  </STAT>
-
 </ttFont>
diff --git a/Tests/varLib/instancer/data/test_results/PartialInstancerTest2-VF-instance-900,62.5.ttx b/Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-900,62.5.ttx
similarity index 86%
rename from Tests/varLib/instancer/data/test_results/PartialInstancerTest2-VF-instance-900,62.5.ttx
rename to Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-900,62.5.ttx
index 45e34cb..bc8c7e9 100644
--- a/Tests/varLib/instancer/data/test_results/PartialInstancerTest2-VF-instance-900,62.5.ttx
+++ b/Tests/varLib/data/test_results/PartialInstancerTest2-VF-instance-900,62.5.ttx
@@ -14,12 +14,12 @@
     <!-- Most of this table will be recalculated by the compiler -->
     <tableVersion value="1.0"/>
     <fontRevision value="2.001"/>
-    <checkSumAdjustment value="0x7f9149e4"/>
+    <checkSumAdjustment value="0xc8e8b846"/>
     <magicNumber value="0x5f0f3cf5"/>
     <flags value="00000000 00000011"/>
     <unitsPerEm value="1000"/>
     <created value="Tue Mar 15 19:50:39 2016"/>
-    <modified value="Thu Oct 17 14:43:10 2019"/>
+    <modified value="Tue May 21 16:23:19 2019"/>
     <xMin value="0"/>
     <yMin value="0"/>
     <xMax value="574"/>
@@ -238,18 +238,6 @@
   </glyf>
 
   <name>
-    <namerecord nameID="256" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Weight
-    </namerecord>
-    <namerecord nameID="257" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Width
-    </namerecord>
-    <namerecord nameID="266" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Black
-    </namerecord>
-    <namerecord nameID="288" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      ExtraCondensed
-    </namerecord>
     <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
       Copyright 2015 Google Inc. All Rights Reserved.
     </namerecord>
@@ -295,18 +283,6 @@
     <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
       http://scripts.sil.org/OFL
     </namerecord>
-    <namerecord nameID="256" platformID="3" platEncID="1" langID="0x409">
-      Weight
-    </namerecord>
-    <namerecord nameID="257" platformID="3" platEncID="1" langID="0x409">
-      Width
-    </namerecord>
-    <namerecord nameID="266" platformID="3" platEncID="1" langID="0x409">
-      Black
-    </namerecord>
-    <namerecord nameID="288" platformID="3" platEncID="1" langID="0x409">
-      ExtraCondensed
-    </namerecord>
   </name>
 
   <post>
@@ -335,7 +311,7 @@
 
   <GDEF>
     <Version value="0x00010002"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="1">
       <ClassDef glyph="A" class="1"/>
       <ClassDef glyph="Agrave" class="1"/>
       <ClassDef glyph="T" class="1"/>
@@ -343,13 +319,13 @@
     <MarkGlyphSetsDef>
       <MarkSetTableFormat value="1"/>
       <!-- MarkSetCount=4 -->
-      <Coverage index="0">
+      <Coverage index="0" Format="1">
       </Coverage>
-      <Coverage index="1">
+      <Coverage index="1" Format="1">
       </Coverage>
-      <Coverage index="2">
+      <Coverage index="2" Format="1">
       </Coverage>
-      <Coverage index="3">
+      <Coverage index="3" Format="1">
       </Coverage>
     </MarkGlyphSetsDef>
   </GDEF>
@@ -417,20 +393,20 @@
       <!-- LookupCount=1 -->
       <Lookup index="0">
         <LookupType value="2"/>
-        <LookupFlag value="8"/><!-- ignoreMarks -->
+        <LookupFlag value="8"/>
         <!-- SubTableCount=1 -->
         <PairPos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="A"/>
             <Glyph value="T"/>
             <Glyph value="Agrave"/>
           </Coverage>
           <ValueFormat1 value="4"/>
           <ValueFormat2 value="0"/>
-          <ClassDef1>
+          <ClassDef1 Format="1">
             <ClassDef glyph="T" class="1"/>
           </ClassDef1>
-          <ClassDef2>
+          <ClassDef2 Format="1">
             <ClassDef glyph="A" class="1"/>
             <ClassDef glyph="Agrave" class="1"/>
             <ClassDef glyph="T" class="2"/>
@@ -505,40 +481,4 @@
     </LookupList>
   </GSUB>
 
-  <STAT>
-    <Version value="0x00010001"/>
-    <DesignAxisRecordSize value="8"/>
-    <!-- DesignAxisCount=2 -->
-    <DesignAxisRecord>
-      <Axis index="0">
-        <AxisTag value="wght"/>
-        <AxisNameID value="256"/>  <!-- Weight -->
-        <AxisOrdering value="1"/>
-      </Axis>
-      <Axis index="1">
-        <AxisTag value="wdth"/>
-        <AxisNameID value="257"/>  <!-- Width -->
-        <AxisOrdering value="0"/>
-      </Axis>
-    </DesignAxisRecord>
-    <!-- AxisValueCount=2 -->
-    <AxisValueArray>
-      <AxisValue index="0" Format="1">
-        <AxisIndex value="0"/>
-        <Flags value="0"/>
-        <ValueNameID value="266"/>  <!-- Black -->
-        <Value value="900.0"/>
-      </AxisValue>
-      <AxisValue index="1" Format="2">
-        <AxisIndex value="1"/>
-        <Flags value="0"/>
-        <ValueNameID value="288"/>  <!-- ExtraCondensed -->
-        <NominalValue value="62.5"/>
-        <RangeMinValue value="62.5"/>
-        <RangeMaxValue value="68.75"/>
-      </AxisValue>
-    </AxisValueArray>
-    <ElidedFallbackNameID value="2"/>  <!-- Regular -->
-  </STAT>
-
 </ttFont>
diff --git a/Tests/varLib/data/test_results/SingleMaster.ttx b/Tests/varLib/data/test_results/SingleMaster.ttx
deleted file mode 100644
index 02cfe32..0000000
--- a/Tests/varLib/data/test_results/SingleMaster.ttx
+++ /dev/null
@@ -1,103 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.0">
-
-  <GDEF>
-    <Version value="0x00010003"/>
-    <GlyphClassDef>
-      <ClassDef glyph="uni0024" class="1"/>
-      <ClassDef glyph="uni0024.nostroke" class="1"/>
-      <ClassDef glyph="uni0041" class="1"/>
-      <ClassDef glyph="uni0061" class="1"/>
-    </GlyphClassDef>
-  </GDEF>
-
-  <HVAR>
-    <Version value="0x00010000"/>
-    <VarStore Format="1">
-      <Format value="1"/>
-      <VarRegionList>
-        <!-- RegionAxisCount=1 -->
-        <!-- RegionCount=0 -->
-      </VarRegionList>
-      <!-- VarDataCount=1 -->
-      <VarData index="0">
-        <!-- ItemCount=6 -->
-        <NumShorts value="0"/>
-        <!-- VarRegionCount=0 -->
-        <Item index="0" value="[]"/>
-        <Item index="1" value="[]"/>
-        <Item index="2" value="[]"/>
-        <Item index="3" value="[]"/>
-        <Item index="4" value="[]"/>
-        <Item index="5" value="[]"/>
-      </VarData>
-    </VarStore>
-  </HVAR>
-
-  <STAT>
-    <Version value="0x00010001"/>
-    <DesignAxisRecordSize value="8"/>
-    <!-- DesignAxisCount=1 -->
-    <DesignAxisRecord>
-      <Axis index="0">
-        <AxisTag value="wght"/>
-        <AxisNameID value="256"/>  <!-- Weight -->
-        <AxisOrdering value="0"/>
-      </Axis>
-    </DesignAxisRecord>
-    <!-- AxisValueCount=0 -->
-    <ElidedFallbackNameID value="2"/>  <!-- Regular -->
-  </STAT>
-
-  <fvar>
-
-    <!-- Weight -->
-    <Axis>
-      <AxisTag>wght</AxisTag>
-      <Flags>0x0</Flags>
-      <MinValue>400.0</MinValue>
-      <DefaultValue>400.0</DefaultValue>
-      <MaxValue>400.0</MaxValue>
-      <AxisNameID>256</AxisNameID>
-    </Axis>
-  </fvar>
-
-  <gvar>
-    <version value="1"/>
-    <reserved value="0"/>
-  </gvar>
-
-  <name>
-    <namerecord nameID="256" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Weight
-    </namerecord>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      Test Family
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      Version 1.001;ADBO;Test Family Regular
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      Test Family
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version 1.001
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      TestFamily-Master0
-    </namerecord>
-    <namerecord nameID="9" platformID="3" platEncID="1" langID="0x409">
-      Frank Grießhammer
-    </namerecord>
-    <namerecord nameID="17" platformID="3" platEncID="1" langID="0x409">
-      Master 0
-    </namerecord>
-    <namerecord nameID="256" platformID="3" platEncID="1" langID="0x409">
-      Weight
-    </namerecord>
-  </name>
-
-</ttFont>
diff --git a/Tests/varLib/data/test_results/SparseMasters.ttx b/Tests/varLib/data/test_results/SparseMasters.ttx
index a3f8e61..c2aa335 100644
--- a/Tests/varLib/data/test_results/SparseMasters.ttx
+++ b/Tests/varLib/data/test_results/SparseMasters.ttx
@@ -290,7 +290,7 @@
 
   <GDEF>
     <Version value="0x00010003"/>
-    <GlyphClassDef>
+    <GlyphClassDef Format="1">
       <ClassDef glyph="dotabovecomb" class="3"/>
       <ClassDef glyph="e" class="1"/>
     </GlyphClassDef>
@@ -352,10 +352,10 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
         <MarkBasePos index="0" Format="1">
-          <MarkCoverage>
+          <MarkCoverage Format="1">
             <Glyph value="dotabovecomb"/>
           </MarkCoverage>
-          <BaseCoverage>
+          <BaseCoverage Format="1">
             <Glyph value="e"/>
           </BaseCoverage>
           <!-- ClassCount=1 -->
@@ -425,7 +425,7 @@
         <LookupType value="4"/>
         <LookupFlag value="0"/>
         <!-- SubTableCount=1 -->
-        <LigatureSubst index="0">
+        <LigatureSubst index="0" Format="1">
           <LigatureSet glyph="a">
             <Ligature components="e,s,s" glyph="s"/>
           </LigatureSet>
@@ -572,19 +572,6 @@
         <delta pt="21" x="0" y="0"/>
       </tuple>
     </glyphVariations>
-    <glyphVariations glyph="dotabovecomb">
-      <tuple>
-        <coord axis="wght" value="1.0"/>
-        <delta pt="0" x="-8" y="28"/>
-        <delta pt="1" x="13" y="16"/>
-        <delta pt="2" x="17" y="-13"/>
-        <delta pt="3" x="-27" y="-20"/>
-        <delta pt="4" x="0" y="0"/>
-        <delta pt="5" x="0" y="0"/>
-        <delta pt="6" x="0" y="0"/>
-        <delta pt="7" x="0" y="0"/>
-      </tuple>
-    </glyphVariations>
     <glyphVariations glyph="e">
       <tuple>
         <coord axis="wght" min="0.0" value="0.36365" max="1.0"/>
@@ -627,12 +614,6 @@
         <delta pt="16" x="0" y="0"/>
       </tuple>
     </glyphVariations>
-    <glyphVariations glyph="edotabove">
-      <tuple>
-        <coord axis="wght" value="1.0"/>
-        <delta pt="1" x="-6" y="91"/>
-      </tuple>
-    </glyphVariations>
     <glyphVariations glyph="s">
       <tuple>
         <coord axis="wght" value="1.0"/>
@@ -654,6 +635,25 @@
         <delta pt="15" x="0" y="0"/>
       </tuple>
     </glyphVariations>
+    <glyphVariations glyph="dotabovecomb">
+      <tuple>
+        <coord axis="wght" value="1.0"/>
+        <delta pt="0" x="-8" y="28"/>
+        <delta pt="1" x="13" y="16"/>
+        <delta pt="2" x="17" y="-13"/>
+        <delta pt="3" x="-27" y="-20"/>
+        <delta pt="4" x="0" y="0"/>
+        <delta pt="5" x="0" y="0"/>
+        <delta pt="6" x="0" y="0"/>
+        <delta pt="7" x="0" y="0"/>
+      </tuple>
+    </glyphVariations>
+    <glyphVariations glyph="edotabove">
+      <tuple>
+        <coord axis="wght" value="1.0"/>
+        <delta pt="1" x="-6" y="91"/>
+      </tuple>
+    </glyphVariations>
   </gvar>
 
 </ttFont>
diff --git a/Tests/varLib/data/test_results/TestBASE.ttx b/Tests/varLib/data/test_results/TestBASE.ttx
deleted file mode 100644
index 23d9337..0000000
--- a/Tests/varLib/data/test_results/TestBASE.ttx
+++ /dev/null
@@ -1,477 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="OTTO" ttLibVersion="4.4">
-
-  <BASE>
-    <Version value="0x00010001"/>
-    <HorizAxis>
-      <BaseTagList>
-        <!-- BaseTagCount=5 -->
-        <BaselineTag index="0" value="icfb"/>
-        <BaselineTag index="1" value="icft"/>
-        <BaselineTag index="2" value="ideo"/>
-        <BaselineTag index="3" value="idtp"/>
-        <BaselineTag index="4" value="romn"/>
-      </BaseTagList>
-      <BaseScriptList>
-        <!-- BaseScriptCount=6 -->
-        <BaseScriptRecord index="0">
-          <BaseScriptTag value="DFLT"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="2"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="3">
-                <Coordinate value="-75"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="0"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="1" Format="3">
-                <Coordinate value="835"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="1"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="-120"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="880"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="1">
-          <BaseScriptTag value="cyrl"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="4"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="3">
-                <Coordinate value="-75"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="0"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="1" Format="3">
-                <Coordinate value="835"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="1"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="-120"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="880"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="2">
-          <BaseScriptTag value="grek"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="4"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="3">
-                <Coordinate value="-75"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="0"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="1" Format="3">
-                <Coordinate value="835"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="1"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="-120"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="880"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="3">
-          <BaseScriptTag value="hani"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="2"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="3">
-                <Coordinate value="-75"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="0"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="1" Format="3">
-                <Coordinate value="835"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="1"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="-120"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="880"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="4">
-          <BaseScriptTag value="kana"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="2"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="3">
-                <Coordinate value="-75"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="0"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="1" Format="3">
-                <Coordinate value="835"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="1"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="-120"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="880"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="5">
-          <BaseScriptTag value="latn"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="4"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="3">
-                <Coordinate value="-75"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="0"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="1" Format="3">
-                <Coordinate value="835"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="1"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="-120"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="880"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-      </BaseScriptList>
-    </HorizAxis>
-    <VertAxis>
-      <BaseTagList>
-        <!-- BaseTagCount=5 -->
-        <BaselineTag index="0" value="icfb"/>
-        <BaselineTag index="1" value="icft"/>
-        <BaselineTag index="2" value="ideo"/>
-        <BaselineTag index="3" value="idtp"/>
-        <BaselineTag index="4" value="romn"/>
-      </BaseTagList>
-      <BaseScriptList>
-        <!-- BaseScriptCount=6 -->
-        <BaseScriptRecord index="0">
-          <BaseScriptTag value="DFLT"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="2"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="3">
-                <Coordinate value="45"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="0"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="1" Format="3">
-                <Coordinate value="955"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="1"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="1000"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="120"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="1">
-          <BaseScriptTag value="cyrl"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="4"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="3">
-                <Coordinate value="45"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="0"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="1" Format="3">
-                <Coordinate value="955"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="1"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="1000"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="120"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="2">
-          <BaseScriptTag value="grek"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="4"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="3">
-                <Coordinate value="45"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="0"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="1" Format="3">
-                <Coordinate value="955"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="1"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="1000"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="120"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="3">
-          <BaseScriptTag value="hani"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="2"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="3">
-                <Coordinate value="45"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="0"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="1" Format="3">
-                <Coordinate value="955"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="1"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="1000"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="120"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="4">
-          <BaseScriptTag value="kana"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="2"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="3">
-                <Coordinate value="45"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="0"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="1" Format="3">
-                <Coordinate value="955"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="1"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="1000"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="120"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-        <BaseScriptRecord index="5">
-          <BaseScriptTag value="latn"/>
-          <BaseScript>
-            <BaseValues>
-              <DefaultIndex value="4"/>
-              <!-- BaseCoordCount=5 -->
-              <BaseCoord index="0" Format="3">
-                <Coordinate value="45"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="0"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="1" Format="3">
-                <Coordinate value="955"/>
-                <DeviceTable>
-                  <StartSize value="0"/>
-                  <EndSize value="1"/>
-                  <DeltaFormat value="32768"/>
-                </DeviceTable>
-              </BaseCoord>
-              <BaseCoord index="2" Format="1">
-                <Coordinate value="0"/>
-              </BaseCoord>
-              <BaseCoord index="3" Format="1">
-                <Coordinate value="1000"/>
-              </BaseCoord>
-              <BaseCoord index="4" Format="1">
-                <Coordinate value="120"/>
-              </BaseCoord>
-            </BaseValues>
-            <!-- BaseLangSysCount=0 -->
-          </BaseScript>
-        </BaseScriptRecord>
-      </BaseScriptList>
-    </VertAxis>
-    <VarStore Format="1">
-      <Format value="1"/>
-      <VarRegionList>
-        <!-- RegionAxisCount=1 -->
-        <!-- RegionCount=1 -->
-        <Region index="0">
-          <VarRegionAxis index="0">
-            <StartCoord value="0.0"/>
-            <PeakCoord value="1.0"/>
-            <EndCoord value="1.0"/>
-          </VarRegionAxis>
-        </Region>
-      </VarRegionList>
-      <!-- VarDataCount=1 -->
-      <VarData index="0">
-        <!-- ItemCount=2 -->
-        <NumShorts value="0"/>
-        <!-- VarRegionCount=1 -->
-        <VarRegionIndex index="0" value="0"/>
-        <Item index="0" value="[-17]"/>
-        <Item index="1" value="[17]"/>
-      </VarData>
-    </VarStore>
-  </BASE>
-
-</ttFont>
diff --git a/Tests/varLib/data/test_results/TestNonMarkingCFF2.ttx b/Tests/varLib/data/test_results/TestNonMarkingCFF2.ttx
index a78e6a6..26bd7ba 100644
--- a/Tests/varLib/data/test_results/TestNonMarkingCFF2.ttx
+++ b/Tests/varLib/data/test_results/TestNonMarkingCFF2.ttx
@@ -36,8 +36,6 @@
             <StdVW>
                 <blend value="34 51"/>
             </StdVW>
-            <LanguageGroup value="0"/>
-            <ExpansionFactor value="0.06"/>
           </Private>
         </FontDict>
       </FDArray>
diff --git a/Tests/varLib/data/test_results/TestSparseCFF2VF.ttx b/Tests/varLib/data/test_results/TestSparseCFF2VF.ttx
index 264a3d4..f05f62f 100644
--- a/Tests/varLib/data/test_results/TestSparseCFF2VF.ttx
+++ b/Tests/varLib/data/test_results/TestSparseCFF2VF.ttx
@@ -138,8 +138,6 @@
             <BlueFuzz value="0"/>
             <StdHW value="1"/>
             <StdVW value="1"/>
-            <LanguageGroup value="1"/>
-            <ExpansionFactor value="0.06"/>
           </Private>
         </FontDict>
         <FontDict index="1">
@@ -150,8 +148,6 @@
             <BlueFuzz value="0"/>
             <StdHW value="1"/>
             <StdVW value="1"/>
-            <LanguageGroup value="1"/>
-            <ExpansionFactor value="0.06"/>
           </Private>
         </FontDict>
         <FontDict index="2">
@@ -160,8 +156,6 @@
             <BlueScale value="0.039625"/>
             <BlueShift value="7"/>
             <BlueFuzz value="1"/>
-            <LanguageGroup value="0"/>
-            <ExpansionFactor value="0.06"/>
           </Private>
         </FontDict>
       </FDArray>
@@ -296,7 +290,7 @@
         </CharString>
         <CharString name="cid06449" fdSelectIndex="1">
           2 vsindex
-          -60 30 203 30 -9 9 67 7 -7 14 -14 30 -20 20 80 30 59 30 121 30 18 93 -30 30 -30 108 -23 0 -26 67 2 76 -98 -2 -111 42 0 47 -13 0 -14 13 0 14 -33 0 -37 11 0 13 -11 0 -13 8 0 8 -8 0 -8 53 0 60 -32 0 -36 32 0 36 -52 0 -59 57 1 65 -33 0 -38 53 0 60 -83 -1 -93 54 0 60 -6 -19 -24 33 19 55 -76 -1 -86 76 1 86 -76 -1 -86 59 1 67 26 blend
+          -60 30 203 30 -9 9 67 7 -7 14 -14 30 -20 20 80 30 59 30 121 30 18 93 -30 30 -30 108 -23 0 -26 67 2 76 -98 -2 -111 42 0 47 -13 0 -14 13 0 14 -33 0 -37 11 0 13 -11 0 -13 8 0 9 -7 0 -8 53 0 60 -32 0 -36 32 0 36 -52 0 -59 57 1 65 -33 0 -38 53 0 60 -83 -1 -93 54 0 60 -6 -19 -24 33 19 55 -76 -1 -86 76 1 86 -76 -1 -86 59 1 67 26 blend
           hstemhm
           77 30 42 30 139 30 23 30 71 10 74 30 15 30 16 30 158 30 28 30 -4 29 -14 0 -16 88 1 99 -82 -1 -92 87 1 98 -130 -1 -146 102 1 114 -73 -1 -82 74 2 84 -112 -2 -126 27 0 30 13 0 15 90 1 101 -126 -1 -142 75 1 84 -68 -1 -76 102 1 115 -144 -1 -162 94 1 105 -79 -1 -88 95 1 106 -81 -1 -91 74 1 83 22 blend
           vstemhm
diff --git a/Tests/varLib/data/test_results/test_vpal.ttx b/Tests/varLib/data/test_results/test_vpal.ttx
index be61293..334ced5 100644
--- a/Tests/varLib/data/test_results/test_vpal.ttx
+++ b/Tests/varLib/data/test_results/test_vpal.ttx
@@ -34,7 +34,7 @@
         <LookupFlag value="0"/>
         <!-- SubTableCount=6 -->
         <SinglePos index="0" Format="2">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="uniFF1A"/>
             <Glyph value="uni3074"/>
           </Coverage>
@@ -44,7 +44,7 @@
           <Value index="1" XPlacement="0" YPlacement="0" XAdvance="-30"/>
         </SinglePos>
         <SinglePos index="1" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="uni3001"/>
           </Coverage>
           <ValueFormat value="23"/>
@@ -57,7 +57,7 @@
           </Value>
         </SinglePos>
         <SinglePos index="2" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="uni30FB"/>
           </Coverage>
           <ValueFormat value="39"/>
@@ -70,7 +70,7 @@
           </Value>
         </SinglePos>
         <SinglePos index="3" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="uniFF2D"/>
           </Coverage>
           <ValueFormat value="87"/>
@@ -88,7 +88,7 @@
           </Value>
         </SinglePos>
         <SinglePos index="4" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="uni3073"/>
           </Coverage>
           <ValueFormat value="71"/>
@@ -101,7 +101,7 @@
           </Value>
         </SinglePos>
         <SinglePos index="5" Format="1">
-          <Coverage>
+          <Coverage Format="1">
             <Glyph value="uni307B"/>
           </Coverage>
           <ValueFormat value="23"/>
diff --git a/Tests/varLib/featureVars_test.py b/Tests/varLib/featureVars_test.py
index 89675af..4db2e62 100644
--- a/Tests/varLib/featureVars_test.py
+++ b/Tests/varLib/featureVars_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.varLib.featureVars import (
     overlayFeatureVariations)
 
diff --git a/Tests/varLib/instancer/conftest.py b/Tests/varLib/instancer/conftest.py
deleted file mode 100644
index 0ac8091..0000000
--- a/Tests/varLib/instancer/conftest.py
+++ /dev/null
@@ -1,13 +0,0 @@
-import os
-from fontTools import ttLib
-import pytest
-
-
-TESTDATA = os.path.join(os.path.dirname(__file__), "data")
-
-
-@pytest.fixture
-def varfont():
-    f = ttLib.TTFont()
-    f.importXML(os.path.join(TESTDATA, "PartialInstancerTest-VF.ttx"))
-    return f
diff --git a/Tests/varLib/instancer/data/PartialInstancerTest3-VF.ttx b/Tests/varLib/instancer/data/PartialInstancerTest3-VF.ttx
deleted file mode 100644
index 01c7d05..0000000
--- a/Tests/varLib/instancer/data/PartialInstancerTest3-VF.ttx
+++ /dev/null
@@ -1,439 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.15">
-
-  <GlyphOrder>
-    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="A"/>
-    <GlyphID id="2" name="B"/>
-    <GlyphID id="3" name="C"/>
-    <GlyphID id="4" name="D"/>
-    <GlyphID id="5" name="E"/>
-    <GlyphID id="6" name="F"/>
-    <GlyphID id="7" name="space"/>
-  </GlyphOrder>
-
-  <head>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="1.0"/>
-    <fontRevision value="1.0"/>
-    <checkSumAdjustment value="0xc3d4abe6"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00000011"/>
-    <unitsPerEm value="1000"/>
-    <created value="Wed Sep 23 12:54:22 2020"/>
-    <modified value="Tue Sep 29 18:06:03 2020"/>
-    <xMin value="-152"/>
-    <yMin value="-200"/>
-    <xMax value="1059"/>
-    <yMax value="800"/>
-    <macStyle value="00000000 00000000"/>
-    <lowestRecPPEM value="6"/>
-    <fontDirectionHint value="2"/>
-    <indexToLocFormat value="0"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="1000"/>
-    <descent value="-200"/>
-    <lineGap value="0"/>
-    <advanceWidthMax value="600"/>
-    <minLeftSideBearing value="-152"/>
-    <minRightSideBearing value="-559"/>
-    <xMaxExtent value="1059"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfHMetrics value="8"/>
-  </hhea>
-
-  <maxp>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="0x10000"/>
-    <numGlyphs value="8"/>
-    <maxPoints value="8"/>
-    <maxContours value="2"/>
-    <maxCompositePoints value="12"/>
-    <maxCompositeContours value="3"/>
-    <maxZones value="1"/>
-    <maxTwilightPoints value="0"/>
-    <maxStorage value="0"/>
-    <maxFunctionDefs value="0"/>
-    <maxInstructionDefs value="0"/>
-    <maxStackElements value="0"/>
-    <maxSizeOfInstructions value="0"/>
-    <maxComponentElements value="3"/>
-    <maxComponentDepth value="1"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="4"/>
-    <xAvgCharWidth value="513"/>
-    <usWeightClass value="400"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00001000"/>
-    <ySubscriptXSize value="650"/>
-    <ySubscriptYSize value="600"/>
-    <ySubscriptXOffset value="0"/>
-    <ySubscriptYOffset value="75"/>
-    <ySuperscriptXSize value="650"/>
-    <ySuperscriptYSize value="600"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="350"/>
-    <yStrikeoutSize value="50"/>
-    <yStrikeoutPosition value="300"/>
-    <sFamilyClass value="0"/>
-    <panose>
-      <bFamilyType value="0"/>
-      <bSerifStyle value="0"/>
-      <bWeight value="0"/>
-      <bProportion value="0"/>
-      <bContrast value="0"/>
-      <bStrokeVariation value="0"/>
-      <bArmStyle value="0"/>
-      <bLetterForm value="0"/>
-      <bMidline value="0"/>
-      <bXHeight value="0"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="NONE"/>
-    <fsSelection value="00000000 01000000"/>
-    <usFirstCharIndex value="32"/>
-    <usLastCharIndex value="70"/>
-    <sTypoAscender value="800"/>
-    <sTypoDescender value="-200"/>
-    <sTypoLineGap value="200"/>
-    <usWinAscent value="1000"/>
-    <usWinDescent value="200"/>
-    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
-    <sxHeight value="500"/>
-    <sCapHeight value="700"/>
-    <usDefaultChar value="0"/>
-    <usBreakChar value="32"/>
-    <usMaxContext value="0"/>
-  </OS_2>
-
-  <hmtx>
-    <mtx name=".notdef" width="500" lsb="50"/>
-    <mtx name="A" width="500" lsb="153"/>
-    <mtx name="B" width="500" lsb="-152"/>
-    <mtx name="C" width="500" lsb="-133"/>
-    <mtx name="D" width="500" lsb="-97"/>
-    <mtx name="E" width="500" lsb="-87"/>
-    <mtx name="F" width="500" lsb="-107"/>
-    <mtx name="space" width="600" lsb="0"/>
-  </hmtx>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_4 platformID="0" platEncID="3" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x42" name="B"/><!-- LATIN CAPITAL LETTER B -->
-      <map code="0x43" name="C"/><!-- LATIN CAPITAL LETTER C -->
-      <map code="0x44" name="D"/><!-- LATIN CAPITAL LETTER D -->
-      <map code="0x45" name="E"/><!-- LATIN CAPITAL LETTER E -->
-      <map code="0x46" name="F"/><!-- LATIN CAPITAL LETTER F -->
-    </cmap_format_4>
-    <cmap_format_4 platformID="3" platEncID="1" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x42" name="B"/><!-- LATIN CAPITAL LETTER B -->
-      <map code="0x43" name="C"/><!-- LATIN CAPITAL LETTER C -->
-      <map code="0x44" name="D"/><!-- LATIN CAPITAL LETTER D -->
-      <map code="0x45" name="E"/><!-- LATIN CAPITAL LETTER E -->
-      <map code="0x46" name="F"/><!-- LATIN CAPITAL LETTER F -->
-    </cmap_format_4>
-  </cmap>
-
-  <loca>
-    <!-- The 'loca' table will be calculated by the compiler -->
-  </loca>
-
-  <glyf>
-
-    <!-- The xMin, yMin, xMax and yMax values
-         will be recalculated by the compiler. -->
-
-    <TTGlyph name=".notdef" xMin="50" yMin="-200" xMax="450" yMax="800">
-      <contour>
-        <pt x="50" y="-200" on="1"/>
-        <pt x="50" y="800" on="1"/>
-        <pt x="450" y="800" on="1"/>
-        <pt x="450" y="-200" on="1"/>
-      </contour>
-      <contour>
-        <pt x="100" y="-150" on="1"/>
-        <pt x="400" y="-150" on="1"/>
-        <pt x="400" y="750" on="1"/>
-        <pt x="100" y="750" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="A" xMin="153" yMin="-66" xMax="350" yMax="646">
-      <contour>
-        <pt x="153" y="646" on="1"/>
-        <pt x="350" y="646" on="1"/>
-        <pt x="350" y="-66" on="1"/>
-        <pt x="153" y="-66" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="B" xMin="-152" yMin="39" xMax="752" yMax="592">
-      <contour>
-        <pt x="-152" y="448" on="1"/>
-        <pt x="752" y="448" on="1"/>
-        <pt x="752" y="215" on="1"/>
-        <pt x="-152" y="215" on="1"/>
-      </contour>
-      <contour>
-        <pt x="129" y="592" on="1"/>
-        <pt x="401" y="592" on="1"/>
-        <pt x="401" y="39" on="1"/>
-        <pt x="129" y="39" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="C" xMin="-133" yMin="-66" xMax="771" yMax="646">
-      <component glyphName="A" x="-250" y="0" flags="0x4"/>
-      <component glyphName="B" x="19" y="-28" flags="0x4"/>
-    </TTGlyph>
-
-    <TTGlyph name="D" xMin="-97" yMin="-66" xMax="1059" yMax="646">
-      <component glyphName="A" x="-250" y="0" flags="0x4"/>
-      <component glyphName="B" x="307" y="-28" flags="0x4"/>
-    </TTGlyph>
-
-    <TTGlyph name="E" xMin="-87" yMin="-87" xMax="801" yMax="650">
-      <component glyphName="A" x="450" y="-77" scalex="0.9397" scale01="0.34204" scale10="-0.34204" scaley="0.9397" flags="0x4"/>
-      <component glyphName="A" x="8" y="4" flags="0x4"/>
-      <component glyphName="A" x="-240" y="0" flags="0x4"/>
-    </TTGlyph>
-
-    <TTGlyph name="F" xMin="-107" yMin="-95" xMax="837" yMax="650">
-      <component glyphName="A" x="501" y="-114" scalex="0.866" scale01="0.5" scale10="-0.5" scaley="0.866" flags="0x4"/>
-      <component glyphName="A" x="-12" y="4" flags="0x4"/>
-      <component glyphName="A" x="-260" y="0" flags="0x4"/>
-    </TTGlyph>
-
-    <TTGlyph name="space"/><!-- contains no outline data -->
-
-  </glyf>
-
-  <name>
-    <namerecord nameID="256" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Weight
-    </namerecord>
-    <namerecord nameID="257" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Regular
-    </namerecord>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      Remove Overlaps Test
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      1.000;NONE;RemoveOverlapsTest-Regular
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      Remove Overlaps Test Regular
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version 1.000
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      RemoveOverlapsTest-Regular
-    </namerecord>
-    <namerecord nameID="256" platformID="3" platEncID="1" langID="0x409">
-      Weight
-    </namerecord>
-    <namerecord nameID="257" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-  </name>
-
-  <post>
-    <formatType value="2.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-100"/>
-    <underlineThickness value="50"/>
-    <isFixedPitch value="0"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="0"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="0"/>
-    <psNames>
-      <!-- This file uses unique glyph names based on the information
-           found in the 'post' table. Since these names might not be unique,
-           we have to invent artificial names in case of clashes. In order to
-           be able to retain the original information, we need a name to
-           ps name mapping for those cases where they differ. That's what
-           you see below.
-            -->
-    </psNames>
-    <extraNames>
-      <!-- following are the name that are not taken from the standard Mac glyph order -->
-    </extraNames>
-  </post>
-
-  <HVAR>
-    <Version value="0x00010000"/>
-    <VarStore Format="1">
-      <Format value="1"/>
-      <VarRegionList>
-        <!-- RegionAxisCount=1 -->
-        <!-- RegionCount=1 -->
-        <Region index="0">
-          <VarRegionAxis index="0">
-            <StartCoord value="0.0"/>
-            <PeakCoord value="1.0"/>
-            <EndCoord value="1.0"/>
-          </VarRegionAxis>
-        </Region>
-      </VarRegionList>
-      <!-- VarDataCount=1 -->
-      <VarData index="0">
-        <!-- ItemCount=8 -->
-        <NumShorts value="0"/>
-        <!-- VarRegionCount=0 -->
-        <Item index="0" value="[]"/>
-        <Item index="1" value="[]"/>
-        <Item index="2" value="[]"/>
-        <Item index="3" value="[]"/>
-        <Item index="4" value="[]"/>
-        <Item index="5" value="[]"/>
-        <Item index="6" value="[]"/>
-        <Item index="7" value="[]"/>
-      </VarData>
-    </VarStore>
-  </HVAR>
-
-  <STAT>
-    <Version value="0x00010001"/>
-    <DesignAxisRecordSize value="8"/>
-    <!-- DesignAxisCount=1 -->
-    <DesignAxisRecord>
-      <Axis index="0">
-        <AxisTag value="wght"/>
-        <AxisNameID value="256"/>  <!-- Weight -->
-        <AxisOrdering value="0"/>
-      </Axis>
-    </DesignAxisRecord>
-    <!-- AxisValueCount=0 -->
-    <ElidedFallbackNameID value="2"/>  <!-- Regular -->
-  </STAT>
-
-  <fvar>
-
-    <!-- Weight -->
-    <Axis>
-      <AxisTag>wght</AxisTag>
-      <Flags>0x0</Flags>
-      <MinValue>400.0</MinValue>
-      <DefaultValue>400.0</DefaultValue>
-      <MaxValue>700.0</MaxValue>
-      <AxisNameID>256</AxisNameID>
-    </Axis>
-
-    <!-- Regular -->
-    <NamedInstance flags="0x0" subfamilyNameID="257">
-      <coord axis="wght" value="400.0"/>
-    </NamedInstance>
-
-    <!-- Regular -->
-    <NamedInstance flags="0x0" subfamilyNameID="257">
-      <coord axis="wght" value="700.0"/>
-    </NamedInstance>
-  </fvar>
-
-  <gvar>
-    <version value="1"/>
-    <reserved value="0"/>
-    <glyphVariations glyph="A">
-      <tuple>
-        <coord axis="wght" value="1.0"/>
-        <delta pt="0" x="-40" y="0"/>
-        <delta pt="1" x="40" y="0"/>
-        <delta pt="2" x="40" y="0"/>
-        <delta pt="3" x="-40" y="0"/>
-        <delta pt="4" x="0" y="0"/>
-        <delta pt="5" x="0" y="0"/>
-        <delta pt="6" x="0" y="0"/>
-        <delta pt="7" x="0" y="0"/>
-      </tuple>
-    </glyphVariations>
-    <glyphVariations glyph="B">
-      <tuple>
-        <coord axis="wght" value="1.0"/>
-        <delta pt="0" x="-40" y="0"/>
-        <delta pt="2" x="40" y="0"/>
-        <delta pt="5" x="40" y="20"/>
-        <delta pt="7" x="-40" y="-20"/>
-      </tuple>
-    </glyphVariations>
-    <glyphVariations glyph="C">
-      <tuple>
-        <coord axis="wght" value="1.0"/>
-        <delta pt="0" x="0" y="0"/>
-        <delta pt="1" x="0" y="0"/>
-        <delta pt="2" x="0" y="0"/>
-        <delta pt="3" x="0" y="0"/>
-        <delta pt="4" x="0" y="0"/>
-        <delta pt="5" x="0" y="0"/>
-      </tuple>
-    </glyphVariations>
-    <glyphVariations glyph="D">
-      <tuple>
-        <coord axis="wght" value="1.0"/>
-        <delta pt="0" x="0" y="0"/>
-        <delta pt="1" x="0" y="0"/>
-        <delta pt="2" x="0" y="0"/>
-        <delta pt="3" x="0" y="0"/>
-        <delta pt="4" x="0" y="0"/>
-        <delta pt="5" x="0" y="0"/>
-      </tuple>
-    </glyphVariations>
-    <glyphVariations glyph="E">
-      <tuple>
-        <coord axis="wght" value="1.0"/>
-        <delta pt="0" x="0" y="0"/>
-        <delta pt="1" x="0" y="0"/>
-        <delta pt="2" x="0" y="0"/>
-        <delta pt="3" x="0" y="0"/>
-        <delta pt="4" x="0" y="0"/>
-        <delta pt="5" x="0" y="0"/>
-        <delta pt="6" x="0" y="0"/>
-      </tuple>
-    </glyphVariations>
-    <glyphVariations glyph="F">
-      <tuple>
-        <coord axis="wght" value="1.0"/>
-        <delta pt="0" x="0" y="0"/>
-        <delta pt="1" x="0" y="0"/>
-        <delta pt="2" x="0" y="0"/>
-        <delta pt="3" x="0" y="0"/>
-        <delta pt="4" x="0" y="0"/>
-        <delta pt="5" x="0" y="0"/>
-        <delta pt="6" x="0" y="0"/>
-      </tuple>
-    </glyphVariations>
-  </gvar>
-
-</ttFont>
diff --git a/Tests/varLib/instancer/data/test_results/PartialInstancerTest3-VF-instance-400-no-overlap-flags.ttx b/Tests/varLib/instancer/data/test_results/PartialInstancerTest3-VF-instance-400-no-overlap-flags.ttx
deleted file mode 100644
index fc6310d..0000000
--- a/Tests/varLib/instancer/data/test_results/PartialInstancerTest3-VF-instance-400-no-overlap-flags.ttx
+++ /dev/null
@@ -1,305 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.15">
-
-  <GlyphOrder>
-    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="A"/>
-    <GlyphID id="2" name="B"/>
-    <GlyphID id="3" name="C"/>
-    <GlyphID id="4" name="D"/>
-    <GlyphID id="5" name="E"/>
-    <GlyphID id="6" name="F"/>
-    <GlyphID id="7" name="space"/>
-  </GlyphOrder>
-
-  <head>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="1.0"/>
-    <fontRevision value="1.0"/>
-    <checkSumAdjustment value="0x98c89e17"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00000011"/>
-    <unitsPerEm value="1000"/>
-    <created value="Wed Sep 23 12:54:22 2020"/>
-    <modified value="Tue Sep 29 18:06:03 2020"/>
-    <xMin value="-152"/>
-    <yMin value="-200"/>
-    <xMax value="1059"/>
-    <yMax value="800"/>
-    <macStyle value="00000000 00000000"/>
-    <lowestRecPPEM value="6"/>
-    <fontDirectionHint value="2"/>
-    <indexToLocFormat value="0"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="1000"/>
-    <descent value="-200"/>
-    <lineGap value="0"/>
-    <advanceWidthMax value="600"/>
-    <minLeftSideBearing value="-152"/>
-    <minRightSideBearing value="-559"/>
-    <xMaxExtent value="1059"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfHMetrics value="8"/>
-  </hhea>
-
-  <maxp>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="0x10000"/>
-    <numGlyphs value="8"/>
-    <maxPoints value="8"/>
-    <maxContours value="2"/>
-    <maxCompositePoints value="12"/>
-    <maxCompositeContours value="3"/>
-    <maxZones value="1"/>
-    <maxTwilightPoints value="0"/>
-    <maxStorage value="0"/>
-    <maxFunctionDefs value="0"/>
-    <maxInstructionDefs value="0"/>
-    <maxStackElements value="0"/>
-    <maxSizeOfInstructions value="0"/>
-    <maxComponentElements value="3"/>
-    <maxComponentDepth value="1"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="4"/>
-    <xAvgCharWidth value="513"/>
-    <usWeightClass value="400"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00001000"/>
-    <ySubscriptXSize value="650"/>
-    <ySubscriptYSize value="600"/>
-    <ySubscriptXOffset value="0"/>
-    <ySubscriptYOffset value="75"/>
-    <ySuperscriptXSize value="650"/>
-    <ySuperscriptYSize value="600"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="350"/>
-    <yStrikeoutSize value="50"/>
-    <yStrikeoutPosition value="300"/>
-    <sFamilyClass value="0"/>
-    <panose>
-      <bFamilyType value="0"/>
-      <bSerifStyle value="0"/>
-      <bWeight value="0"/>
-      <bProportion value="0"/>
-      <bContrast value="0"/>
-      <bStrokeVariation value="0"/>
-      <bArmStyle value="0"/>
-      <bLetterForm value="0"/>
-      <bMidline value="0"/>
-      <bXHeight value="0"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="NONE"/>
-    <fsSelection value="00000000 01000000"/>
-    <usFirstCharIndex value="32"/>
-    <usLastCharIndex value="70"/>
-    <sTypoAscender value="800"/>
-    <sTypoDescender value="-200"/>
-    <sTypoLineGap value="200"/>
-    <usWinAscent value="1000"/>
-    <usWinDescent value="200"/>
-    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
-    <sxHeight value="500"/>
-    <sCapHeight value="700"/>
-    <usDefaultChar value="0"/>
-    <usBreakChar value="32"/>
-    <usMaxContext value="0"/>
-  </OS_2>
-
-  <hmtx>
-    <mtx name=".notdef" width="500" lsb="50"/>
-    <mtx name="A" width="500" lsb="153"/>
-    <mtx name="B" width="500" lsb="-152"/>
-    <mtx name="C" width="500" lsb="-133"/>
-    <mtx name="D" width="500" lsb="-97"/>
-    <mtx name="E" width="500" lsb="-87"/>
-    <mtx name="F" width="500" lsb="-107"/>
-    <mtx name="space" width="600" lsb="0"/>
-  </hmtx>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_4 platformID="0" platEncID="3" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x42" name="B"/><!-- LATIN CAPITAL LETTER B -->
-      <map code="0x43" name="C"/><!-- LATIN CAPITAL LETTER C -->
-      <map code="0x44" name="D"/><!-- LATIN CAPITAL LETTER D -->
-      <map code="0x45" name="E"/><!-- LATIN CAPITAL LETTER E -->
-      <map code="0x46" name="F"/><!-- LATIN CAPITAL LETTER F -->
-    </cmap_format_4>
-    <cmap_format_4 platformID="3" platEncID="1" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x42" name="B"/><!-- LATIN CAPITAL LETTER B -->
-      <map code="0x43" name="C"/><!-- LATIN CAPITAL LETTER C -->
-      <map code="0x44" name="D"/><!-- LATIN CAPITAL LETTER D -->
-      <map code="0x45" name="E"/><!-- LATIN CAPITAL LETTER E -->
-      <map code="0x46" name="F"/><!-- LATIN CAPITAL LETTER F -->
-    </cmap_format_4>
-  </cmap>
-
-  <loca>
-    <!-- The 'loca' table will be calculated by the compiler -->
-  </loca>
-
-  <glyf>
-
-    <!-- The xMin, yMin, xMax and yMax values
-         will be recalculated by the compiler. -->
-
-    <TTGlyph name=".notdef" xMin="50" yMin="-200" xMax="450" yMax="800">
-      <contour>
-        <pt x="50" y="-200" on="1"/>
-        <pt x="50" y="800" on="1"/>
-        <pt x="450" y="800" on="1"/>
-        <pt x="450" y="-200" on="1"/>
-      </contour>
-      <contour>
-        <pt x="100" y="-150" on="1"/>
-        <pt x="400" y="-150" on="1"/>
-        <pt x="400" y="750" on="1"/>
-        <pt x="100" y="750" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="A" xMin="153" yMin="-66" xMax="350" yMax="646">
-      <contour>
-        <pt x="153" y="646" on="1"/>
-        <pt x="350" y="646" on="1"/>
-        <pt x="350" y="-66" on="1"/>
-        <pt x="153" y="-66" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="B" xMin="-152" yMin="39" xMax="752" yMax="592">
-      <contour>
-        <pt x="-152" y="448" on="1"/>
-        <pt x="752" y="448" on="1"/>
-        <pt x="752" y="215" on="1"/>
-        <pt x="-152" y="215" on="1"/>
-      </contour>
-      <contour>
-        <pt x="129" y="592" on="1"/>
-        <pt x="401" y="592" on="1"/>
-        <pt x="401" y="39" on="1"/>
-        <pt x="129" y="39" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="C" xMin="-133" yMin="-66" xMax="771" yMax="646">
-      <component glyphName="A" x="-250" y="0" flags="0x4"/>
-      <component glyphName="B" x="19" y="-28" flags="0x4"/>
-    </TTGlyph>
-
-    <TTGlyph name="D" xMin="-97" yMin="-66" xMax="1059" yMax="646">
-      <component glyphName="A" x="-250" y="0" flags="0x4"/>
-      <component glyphName="B" x="307" y="-28" flags="0x4"/>
-    </TTGlyph>
-
-    <TTGlyph name="E" xMin="-87" yMin="-87" xMax="801" yMax="650">
-      <component glyphName="A" x="450" y="-77" scalex="0.9397" scale01="0.34204" scale10="-0.34204" scaley="0.9397" flags="0x4"/>
-      <component glyphName="A" x="8" y="4" flags="0x4"/>
-      <component glyphName="A" x="-240" y="0" flags="0x4"/>
-    </TTGlyph>
-
-    <TTGlyph name="F" xMin="-107" yMin="-95" xMax="837" yMax="650">
-      <component glyphName="A" x="501" y="-114" scalex="0.866" scale01="0.5" scale10="-0.5" scaley="0.866" flags="0x4"/>
-      <component glyphName="A" x="-12" y="4" flags="0x4"/>
-      <component glyphName="A" x="-260" y="0" flags="0x4"/>
-    </TTGlyph>
-
-    <TTGlyph name="space"/><!-- contains no outline data -->
-
-  </glyf>
-
-  <name>
-    <namerecord nameID="256" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Weight
-    </namerecord>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      Remove Overlaps Test
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      1.000;NONE;RemoveOverlapsTest-Regular
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      Remove Overlaps Test Regular
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version 1.000
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      RemoveOverlapsTest-Regular
-    </namerecord>
-    <namerecord nameID="256" platformID="3" platEncID="1" langID="0x409">
-      Weight
-    </namerecord>
-  </name>
-
-  <post>
-    <formatType value="2.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-100"/>
-    <underlineThickness value="50"/>
-    <isFixedPitch value="0"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="0"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="0"/>
-    <psNames>
-      <!-- This file uses unique glyph names based on the information
-           found in the 'post' table. Since these names might not be unique,
-           we have to invent artificial names in case of clashes. In order to
-           be able to retain the original information, we need a name to
-           ps name mapping for those cases where they differ. That's what
-           you see below.
-            -->
-    </psNames>
-    <extraNames>
-      <!-- following are the name that are not taken from the standard Mac glyph order -->
-    </extraNames>
-  </post>
-
-  <STAT>
-    <Version value="0x00010001"/>
-    <DesignAxisRecordSize value="8"/>
-    <!-- DesignAxisCount=1 -->
-    <DesignAxisRecord>
-      <Axis index="0">
-        <AxisTag value="wght"/>
-        <AxisNameID value="256"/>  <!-- Weight -->
-        <AxisOrdering value="0"/>
-      </Axis>
-    </DesignAxisRecord>
-    <!-- AxisValueCount=0 -->
-    <ElidedFallbackNameID value="2"/>  <!-- Regular -->
-  </STAT>
-
-</ttFont>
diff --git a/Tests/varLib/instancer/data/test_results/PartialInstancerTest3-VF-instance-400-no-overlaps.ttx b/Tests/varLib/instancer/data/test_results/PartialInstancerTest3-VF-instance-400-no-overlaps.ttx
deleted file mode 100644
index 3e18c9b..0000000
--- a/Tests/varLib/instancer/data/test_results/PartialInstancerTest3-VF-instance-400-no-overlaps.ttx
+++ /dev/null
@@ -1,343 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.15">
-
-  <GlyphOrder>
-    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="A"/>
-    <GlyphID id="2" name="B"/>
-    <GlyphID id="3" name="C"/>
-    <GlyphID id="4" name="D"/>
-    <GlyphID id="5" name="E"/>
-    <GlyphID id="6" name="F"/>
-    <GlyphID id="7" name="space"/>
-  </GlyphOrder>
-
-  <head>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="1.0"/>
-    <fontRevision value="1.0"/>
-    <checkSumAdjustment value="0x1cd9cd87"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00000011"/>
-    <unitsPerEm value="1000"/>
-    <created value="Wed Sep 23 12:54:22 2020"/>
-    <modified value="Tue Sep 29 18:06:03 2020"/>
-    <xMin value="-152"/>
-    <yMin value="-200"/>
-    <xMax value="1059"/>
-    <yMax value="800"/>
-    <macStyle value="00000000 00000000"/>
-    <lowestRecPPEM value="6"/>
-    <fontDirectionHint value="2"/>
-    <indexToLocFormat value="0"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="1000"/>
-    <descent value="-200"/>
-    <lineGap value="0"/>
-    <advanceWidthMax value="600"/>
-    <minLeftSideBearing value="-152"/>
-    <minRightSideBearing value="-559"/>
-    <xMaxExtent value="1059"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfHMetrics value="8"/>
-  </hhea>
-
-  <maxp>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="0x10000"/>
-    <numGlyphs value="8"/>
-    <maxPoints value="20"/>
-    <maxContours value="2"/>
-    <maxCompositePoints value="16"/>
-    <maxCompositeContours value="3"/>
-    <maxZones value="1"/>
-    <maxTwilightPoints value="0"/>
-    <maxStorage value="0"/>
-    <maxFunctionDefs value="0"/>
-    <maxInstructionDefs value="0"/>
-    <maxStackElements value="0"/>
-    <maxSizeOfInstructions value="0"/>
-    <maxComponentElements value="3"/>
-    <maxComponentDepth value="1"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="4"/>
-    <xAvgCharWidth value="513"/>
-    <usWeightClass value="400"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00001000"/>
-    <ySubscriptXSize value="650"/>
-    <ySubscriptYSize value="600"/>
-    <ySubscriptXOffset value="0"/>
-    <ySubscriptYOffset value="75"/>
-    <ySuperscriptXSize value="650"/>
-    <ySuperscriptYSize value="600"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="350"/>
-    <yStrikeoutSize value="50"/>
-    <yStrikeoutPosition value="300"/>
-    <sFamilyClass value="0"/>
-    <panose>
-      <bFamilyType value="0"/>
-      <bSerifStyle value="0"/>
-      <bWeight value="0"/>
-      <bProportion value="0"/>
-      <bContrast value="0"/>
-      <bStrokeVariation value="0"/>
-      <bArmStyle value="0"/>
-      <bLetterForm value="0"/>
-      <bMidline value="0"/>
-      <bXHeight value="0"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="NONE"/>
-    <fsSelection value="00000000 01000000"/>
-    <usFirstCharIndex value="32"/>
-    <usLastCharIndex value="70"/>
-    <sTypoAscender value="800"/>
-    <sTypoDescender value="-200"/>
-    <sTypoLineGap value="200"/>
-    <usWinAscent value="1000"/>
-    <usWinDescent value="200"/>
-    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
-    <sxHeight value="500"/>
-    <sCapHeight value="700"/>
-    <usDefaultChar value="0"/>
-    <usBreakChar value="32"/>
-    <usMaxContext value="0"/>
-  </OS_2>
-
-  <hmtx>
-    <mtx name=".notdef" width="500" lsb="50"/>
-    <mtx name="A" width="500" lsb="153"/>
-    <mtx name="B" width="500" lsb="-152"/>
-    <mtx name="C" width="500" lsb="-133"/>
-    <mtx name="D" width="500" lsb="-97"/>
-    <mtx name="E" width="500" lsb="-87"/>
-    <mtx name="F" width="500" lsb="-107"/>
-    <mtx name="space" width="600" lsb="0"/>
-  </hmtx>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_4 platformID="0" platEncID="3" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x42" name="B"/><!-- LATIN CAPITAL LETTER B -->
-      <map code="0x43" name="C"/><!-- LATIN CAPITAL LETTER C -->
-      <map code="0x44" name="D"/><!-- LATIN CAPITAL LETTER D -->
-      <map code="0x45" name="E"/><!-- LATIN CAPITAL LETTER E -->
-      <map code="0x46" name="F"/><!-- LATIN CAPITAL LETTER F -->
-    </cmap_format_4>
-    <cmap_format_4 platformID="3" platEncID="1" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x42" name="B"/><!-- LATIN CAPITAL LETTER B -->
-      <map code="0x43" name="C"/><!-- LATIN CAPITAL LETTER C -->
-      <map code="0x44" name="D"/><!-- LATIN CAPITAL LETTER D -->
-      <map code="0x45" name="E"/><!-- LATIN CAPITAL LETTER E -->
-      <map code="0x46" name="F"/><!-- LATIN CAPITAL LETTER F -->
-    </cmap_format_4>
-  </cmap>
-
-  <loca>
-    <!-- The 'loca' table will be calculated by the compiler -->
-  </loca>
-
-  <glyf>
-
-    <!-- The xMin, yMin, xMax and yMax values
-         will be recalculated by the compiler. -->
-
-    <TTGlyph name=".notdef" xMin="50" yMin="-200" xMax="450" yMax="800">
-      <contour>
-        <pt x="50" y="-200" on="1"/>
-        <pt x="50" y="800" on="1"/>
-        <pt x="450" y="800" on="1"/>
-        <pt x="450" y="-200" on="1"/>
-      </contour>
-      <contour>
-        <pt x="100" y="-150" on="1"/>
-        <pt x="400" y="-150" on="1"/>
-        <pt x="400" y="750" on="1"/>
-        <pt x="100" y="750" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="A" xMin="153" yMin="-66" xMax="350" yMax="646">
-      <contour>
-        <pt x="153" y="646" on="1"/>
-        <pt x="350" y="646" on="1"/>
-        <pt x="350" y="-66" on="1"/>
-        <pt x="153" y="-66" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="B" xMin="-152" yMin="39" xMax="752" yMax="592">
-      <contour>
-        <pt x="-152" y="448" on="1"/>
-        <pt x="129" y="448" on="1"/>
-        <pt x="129" y="592" on="1"/>
-        <pt x="401" y="592" on="1"/>
-        <pt x="401" y="448" on="1"/>
-        <pt x="752" y="448" on="1"/>
-        <pt x="752" y="215" on="1"/>
-        <pt x="401" y="215" on="1"/>
-        <pt x="401" y="39" on="1"/>
-        <pt x="129" y="39" on="1"/>
-        <pt x="129" y="215" on="1"/>
-        <pt x="-152" y="215" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="C" xMin="-133" yMin="-66" xMax="771" yMax="646">
-      <contour>
-        <pt x="-97" y="646" on="1"/>
-        <pt x="100" y="646" on="1"/>
-        <pt x="100" y="420" on="1"/>
-        <pt x="148" y="420" on="1"/>
-        <pt x="148" y="564" on="1"/>
-        <pt x="420" y="564" on="1"/>
-        <pt x="420" y="420" on="1"/>
-        <pt x="771" y="420" on="1"/>
-        <pt x="771" y="187" on="1"/>
-        <pt x="420" y="187" on="1"/>
-        <pt x="420" y="11" on="1"/>
-        <pt x="148" y="11" on="1"/>
-        <pt x="148" y="187" on="1"/>
-        <pt x="100" y="187" on="1"/>
-        <pt x="100" y="-66" on="1"/>
-        <pt x="-97" y="-66" on="1"/>
-        <pt x="-97" y="187" on="1"/>
-        <pt x="-133" y="187" on="1"/>
-        <pt x="-133" y="420" on="1"/>
-        <pt x="-97" y="420" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="D" xMin="-97" yMin="-66" xMax="1059" yMax="646">
-      <component glyphName="A" x="-250" y="0" flags="0x4"/>
-      <component glyphName="B" x="307" y="-28" flags="0x4"/>
-    </TTGlyph>
-
-    <TTGlyph name="E" xMin="-87" yMin="-87" xMax="801" yMax="650">
-      <component glyphName="A" x="450" y="-77" scalex="0.9397" scale01="0.34204" scale10="-0.34204" scaley="0.9397" flags="0x4"/>
-      <component glyphName="A" x="8" y="4" flags="0x4"/>
-      <component glyphName="A" x="-240" y="0" flags="0x4"/>
-    </TTGlyph>
-
-    <TTGlyph name="F" xMin="-107" yMin="-95" xMax="837" yMax="650">
-      <contour>
-        <pt x="141" y="650" on="1"/>
-        <pt x="338" y="650" on="1"/>
-        <pt x="338" y="538" on="1"/>
-        <pt x="481" y="620" on="1"/>
-        <pt x="837" y="4" on="1"/>
-        <pt x="667" y="-95" on="1"/>
-        <pt x="338" y="474" on="1"/>
-        <pt x="338" y="-62" on="1"/>
-        <pt x="141" y="-62" on="1"/>
-      </contour>
-      <contour>
-        <pt x="-107" y="646" on="1"/>
-        <pt x="90" y="646" on="1"/>
-        <pt x="90" y="-66" on="1"/>
-        <pt x="-107" y="-66" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="space"/><!-- contains no outline data -->
-
-  </glyf>
-
-  <name>
-    <namerecord nameID="256" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Weight
-    </namerecord>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      Remove Overlaps Test
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      1.000;NONE;RemoveOverlapsTest-Regular
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      Remove Overlaps Test Regular
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version 1.000
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      RemoveOverlapsTest-Regular
-    </namerecord>
-    <namerecord nameID="256" platformID="3" platEncID="1" langID="0x409">
-      Weight
-    </namerecord>
-  </name>
-
-  <post>
-    <formatType value="2.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-100"/>
-    <underlineThickness value="50"/>
-    <isFixedPitch value="0"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="0"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="0"/>
-    <psNames>
-      <!-- This file uses unique glyph names based on the information
-           found in the 'post' table. Since these names might not be unique,
-           we have to invent artificial names in case of clashes. In order to
-           be able to retain the original information, we need a name to
-           ps name mapping for those cases where they differ. That's what
-           you see below.
-            -->
-    </psNames>
-    <extraNames>
-      <!-- following are the name that are not taken from the standard Mac glyph order -->
-    </extraNames>
-  </post>
-
-  <STAT>
-    <Version value="0x00010001"/>
-    <DesignAxisRecordSize value="8"/>
-    <!-- DesignAxisCount=1 -->
-    <DesignAxisRecord>
-      <Axis index="0">
-        <AxisTag value="wght"/>
-        <AxisNameID value="256"/>  <!-- Weight -->
-        <AxisOrdering value="0"/>
-      </Axis>
-    </DesignAxisRecord>
-    <!-- AxisValueCount=0 -->
-    <ElidedFallbackNameID value="2"/>  <!-- Regular -->
-  </STAT>
-
-</ttFont>
diff --git a/Tests/varLib/instancer/data/test_results/PartialInstancerTest3-VF-instance-700-no-overlaps.ttx b/Tests/varLib/instancer/data/test_results/PartialInstancerTest3-VF-instance-700-no-overlaps.ttx
deleted file mode 100644
index be0353d..0000000
--- a/Tests/varLib/instancer/data/test_results/PartialInstancerTest3-VF-instance-700-no-overlaps.ttx
+++ /dev/null
@@ -1,367 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.15">
-
-  <GlyphOrder>
-    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
-    <GlyphID id="0" name=".notdef"/>
-    <GlyphID id="1" name="A"/>
-    <GlyphID id="2" name="B"/>
-    <GlyphID id="3" name="C"/>
-    <GlyphID id="4" name="D"/>
-    <GlyphID id="5" name="E"/>
-    <GlyphID id="6" name="F"/>
-    <GlyphID id="7" name="space"/>
-  </GlyphOrder>
-
-  <head>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="1.0"/>
-    <fontRevision value="1.0"/>
-    <checkSumAdjustment value="0xc12af6d1"/>
-    <magicNumber value="0x5f0f3cf5"/>
-    <flags value="00000000 00000011"/>
-    <unitsPerEm value="1000"/>
-    <created value="Wed Sep 23 12:54:22 2020"/>
-    <modified value="Tue Sep 29 18:06:03 2020"/>
-    <xMin value="-192"/>
-    <yMin value="-200"/>
-    <xMax value="1099"/>
-    <yMax value="800"/>
-    <macStyle value="00000000 00000000"/>
-    <lowestRecPPEM value="6"/>
-    <fontDirectionHint value="2"/>
-    <indexToLocFormat value="0"/>
-    <glyphDataFormat value="0"/>
-  </head>
-
-  <hhea>
-    <tableVersion value="0x00010000"/>
-    <ascent value="1000"/>
-    <descent value="-200"/>
-    <lineGap value="0"/>
-    <advanceWidthMax value="600"/>
-    <minLeftSideBearing value="-192"/>
-    <minRightSideBearing value="-599"/>
-    <xMaxExtent value="1099"/>
-    <caretSlopeRise value="1"/>
-    <caretSlopeRun value="0"/>
-    <caretOffset value="0"/>
-    <reserved0 value="0"/>
-    <reserved1 value="0"/>
-    <reserved2 value="0"/>
-    <reserved3 value="0"/>
-    <metricDataFormat value="0"/>
-    <numberOfHMetrics value="8"/>
-  </hhea>
-
-  <maxp>
-    <!-- Most of this table will be recalculated by the compiler -->
-    <tableVersion value="0x10000"/>
-    <numGlyphs value="8"/>
-    <maxPoints value="16"/>
-    <maxContours value="2"/>
-    <maxCompositePoints value="0"/>
-    <maxCompositeContours value="0"/>
-    <maxZones value="1"/>
-    <maxTwilightPoints value="0"/>
-    <maxStorage value="0"/>
-    <maxFunctionDefs value="0"/>
-    <maxInstructionDefs value="0"/>
-    <maxStackElements value="0"/>
-    <maxSizeOfInstructions value="0"/>
-    <maxComponentElements value="0"/>
-    <maxComponentDepth value="0"/>
-  </maxp>
-
-  <OS_2>
-    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
-         will be recalculated by the compiler -->
-    <version value="4"/>
-    <xAvgCharWidth value="513"/>
-    <usWeightClass value="700"/>
-    <usWidthClass value="5"/>
-    <fsType value="00000000 00001000"/>
-    <ySubscriptXSize value="650"/>
-    <ySubscriptYSize value="600"/>
-    <ySubscriptXOffset value="0"/>
-    <ySubscriptYOffset value="75"/>
-    <ySuperscriptXSize value="650"/>
-    <ySuperscriptYSize value="600"/>
-    <ySuperscriptXOffset value="0"/>
-    <ySuperscriptYOffset value="350"/>
-    <yStrikeoutSize value="50"/>
-    <yStrikeoutPosition value="300"/>
-    <sFamilyClass value="0"/>
-    <panose>
-      <bFamilyType value="0"/>
-      <bSerifStyle value="0"/>
-      <bWeight value="0"/>
-      <bProportion value="0"/>
-      <bContrast value="0"/>
-      <bStrokeVariation value="0"/>
-      <bArmStyle value="0"/>
-      <bLetterForm value="0"/>
-      <bMidline value="0"/>
-      <bXHeight value="0"/>
-    </panose>
-    <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
-    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
-    <achVendID value="NONE"/>
-    <fsSelection value="00000000 01000000"/>
-    <usFirstCharIndex value="32"/>
-    <usLastCharIndex value="70"/>
-    <sTypoAscender value="800"/>
-    <sTypoDescender value="-200"/>
-    <sTypoLineGap value="200"/>
-    <usWinAscent value="1000"/>
-    <usWinDescent value="200"/>
-    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
-    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
-    <sxHeight value="500"/>
-    <sCapHeight value="700"/>
-    <usDefaultChar value="0"/>
-    <usBreakChar value="32"/>
-    <usMaxContext value="0"/>
-  </OS_2>
-
-  <hmtx>
-    <mtx name=".notdef" width="500" lsb="50"/>
-    <mtx name="A" width="500" lsb="113"/>
-    <mtx name="B" width="500" lsb="-192"/>
-    <mtx name="C" width="500" lsb="-173"/>
-    <mtx name="D" width="500" lsb="-137"/>
-    <mtx name="E" width="500" lsb="-127"/>
-    <mtx name="F" width="500" lsb="-147"/>
-    <mtx name="space" width="600" lsb="0"/>
-  </hmtx>
-
-  <cmap>
-    <tableVersion version="0"/>
-    <cmap_format_4 platformID="0" platEncID="3" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x42" name="B"/><!-- LATIN CAPITAL LETTER B -->
-      <map code="0x43" name="C"/><!-- LATIN CAPITAL LETTER C -->
-      <map code="0x44" name="D"/><!-- LATIN CAPITAL LETTER D -->
-      <map code="0x45" name="E"/><!-- LATIN CAPITAL LETTER E -->
-      <map code="0x46" name="F"/><!-- LATIN CAPITAL LETTER F -->
-    </cmap_format_4>
-    <cmap_format_4 platformID="3" platEncID="1" language="0">
-      <map code="0x20" name="space"/><!-- SPACE -->
-      <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
-      <map code="0x42" name="B"/><!-- LATIN CAPITAL LETTER B -->
-      <map code="0x43" name="C"/><!-- LATIN CAPITAL LETTER C -->
-      <map code="0x44" name="D"/><!-- LATIN CAPITAL LETTER D -->
-      <map code="0x45" name="E"/><!-- LATIN CAPITAL LETTER E -->
-      <map code="0x46" name="F"/><!-- LATIN CAPITAL LETTER F -->
-    </cmap_format_4>
-  </cmap>
-
-  <loca>
-    <!-- The 'loca' table will be calculated by the compiler -->
-  </loca>
-
-  <glyf>
-
-    <!-- The xMin, yMin, xMax and yMax values
-         will be recalculated by the compiler. -->
-
-    <TTGlyph name=".notdef" xMin="50" yMin="-200" xMax="450" yMax="800">
-      <contour>
-        <pt x="50" y="-200" on="1"/>
-        <pt x="50" y="800" on="1"/>
-        <pt x="450" y="800" on="1"/>
-        <pt x="450" y="-200" on="1"/>
-      </contour>
-      <contour>
-        <pt x="100" y="-150" on="1"/>
-        <pt x="400" y="-150" on="1"/>
-        <pt x="400" y="750" on="1"/>
-        <pt x="100" y="750" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="A" xMin="113" yMin="-66" xMax="390" yMax="646">
-      <contour>
-        <pt x="113" y="646" on="1"/>
-        <pt x="390" y="646" on="1"/>
-        <pt x="390" y="-66" on="1"/>
-        <pt x="113" y="-66" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="B" xMin="-192" yMin="19" xMax="792" yMax="612">
-      <contour>
-        <pt x="-192" y="448" on="1"/>
-        <pt x="89" y="448" on="1"/>
-        <pt x="89" y="612" on="1"/>
-        <pt x="441" y="612" on="1"/>
-        <pt x="441" y="448" on="1"/>
-        <pt x="792" y="448" on="1"/>
-        <pt x="792" y="215" on="1"/>
-        <pt x="441" y="215" on="1"/>
-        <pt x="441" y="19" on="1"/>
-        <pt x="89" y="19" on="1"/>
-        <pt x="89" y="215" on="1"/>
-        <pt x="-192" y="215" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="C" xMin="-173" yMin="-66" xMax="811" yMax="646">
-      <contour>
-        <pt x="-137" y="646" on="1"/>
-        <pt x="140" y="646" on="1"/>
-        <pt x="140" y="584" on="1"/>
-        <pt x="460" y="584" on="1"/>
-        <pt x="460" y="420" on="1"/>
-        <pt x="811" y="420" on="1"/>
-        <pt x="811" y="187" on="1"/>
-        <pt x="460" y="187" on="1"/>
-        <pt x="460" y="-9" on="1"/>
-        <pt x="140" y="-9" on="1"/>
-        <pt x="140" y="-66" on="1"/>
-        <pt x="-137" y="-66" on="1"/>
-        <pt x="-137" y="187" on="1"/>
-        <pt x="-173" y="187" on="1"/>
-        <pt x="-173" y="420" on="1"/>
-        <pt x="-137" y="420" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="D" xMin="-137" yMin="-66" xMax="1099" yMax="646">
-      <contour>
-        <pt x="-137" y="646" on="1"/>
-        <pt x="140" y="646" on="1"/>
-        <pt x="140" y="420" on="1"/>
-        <pt x="396" y="420" on="1"/>
-        <pt x="396" y="584" on="1"/>
-        <pt x="748" y="584" on="1"/>
-        <pt x="748" y="420" on="1"/>
-        <pt x="1099" y="420" on="1"/>
-        <pt x="1099" y="187" on="1"/>
-        <pt x="748" y="187" on="1"/>
-        <pt x="748" y="-9" on="1"/>
-        <pt x="396" y="-9" on="1"/>
-        <pt x="396" y="187" on="1"/>
-        <pt x="140" y="187" on="1"/>
-        <pt x="140" y="-66" on="1"/>
-        <pt x="-137" y="-66" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="E" xMin="-127" yMin="-100" xMax="839" yMax="663">
-      <contour>
-        <pt x="121" y="650" on="1"/>
-        <pt x="398" y="650" on="1"/>
-        <pt x="398" y="592" on="1"/>
-        <pt x="596" y="663" on="1"/>
-        <pt x="839" y="-6" on="1"/>
-        <pt x="579" y="-100" on="1"/>
-        <pt x="398" y="396" on="1"/>
-        <pt x="398" y="-62" on="1"/>
-        <pt x="150" y="-62" on="1"/>
-        <pt x="150" y="-66" on="1"/>
-        <pt x="-127" y="-66" on="1"/>
-        <pt x="-127" y="646" on="1"/>
-        <pt x="121" y="646" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="F" xMin="-147" yMin="-115" xMax="872" yMax="650">
-      <contour>
-        <pt x="101" y="650" on="1"/>
-        <pt x="378" y="650" on="1"/>
-        <pt x="378" y="561" on="1"/>
-        <pt x="516" y="640" on="1"/>
-        <pt x="872" y="24" on="1"/>
-        <pt x="632" y="-115" on="1"/>
-        <pt x="378" y="325" on="1"/>
-        <pt x="378" y="-62" on="1"/>
-        <pt x="130" y="-62" on="1"/>
-        <pt x="130" y="-66" on="1"/>
-        <pt x="-147" y="-66" on="1"/>
-        <pt x="-147" y="646" on="1"/>
-        <pt x="101" y="646" on="1"/>
-      </contour>
-      <instructions/>
-    </TTGlyph>
-
-    <TTGlyph name="space"/><!-- contains no outline data -->
-
-  </glyf>
-
-  <name>
-    <namerecord nameID="256" platformID="1" platEncID="0" langID="0x0" unicode="True">
-      Weight
-    </namerecord>
-    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
-      Remove Overlaps Test
-    </namerecord>
-    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
-      Regular
-    </namerecord>
-    <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
-      1.000;NONE;RemoveOverlapsTest-Regular
-    </namerecord>
-    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
-      Remove Overlaps Test Regular
-    </namerecord>
-    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
-      Version 1.000
-    </namerecord>
-    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
-      RemoveOverlapsTest-Regular
-    </namerecord>
-    <namerecord nameID="256" platformID="3" platEncID="1" langID="0x409">
-      Weight
-    </namerecord>
-  </name>
-
-  <post>
-    <formatType value="2.0"/>
-    <italicAngle value="0.0"/>
-    <underlinePosition value="-100"/>
-    <underlineThickness value="50"/>
-    <isFixedPitch value="0"/>
-    <minMemType42 value="0"/>
-    <maxMemType42 value="0"/>
-    <minMemType1 value="0"/>
-    <maxMemType1 value="0"/>
-    <psNames>
-      <!-- This file uses unique glyph names based on the information
-           found in the 'post' table. Since these names might not be unique,
-           we have to invent artificial names in case of clashes. In order to
-           be able to retain the original information, we need a name to
-           ps name mapping for those cases where they differ. That's what
-           you see below.
-            -->
-    </psNames>
-    <extraNames>
-      <!-- following are the name that are not taken from the standard Mac glyph order -->
-    </extraNames>
-  </post>
-
-  <STAT>
-    <Version value="0x00010001"/>
-    <DesignAxisRecordSize value="8"/>
-    <!-- DesignAxisCount=1 -->
-    <DesignAxisRecord>
-      <Axis index="0">
-        <AxisTag value="wght"/>
-        <AxisNameID value="256"/>  <!-- Weight -->
-        <AxisOrdering value="0"/>
-      </Axis>
-    </DesignAxisRecord>
-    <!-- AxisValueCount=0 -->
-    <ElidedFallbackNameID value="2"/>  <!-- Regular -->
-  </STAT>
-
-</ttFont>
diff --git a/Tests/varLib/instancer/names_test.py b/Tests/varLib/instancer/names_test.py
deleted file mode 100644
index 9774458..0000000
--- a/Tests/varLib/instancer/names_test.py
+++ /dev/null
@@ -1,322 +0,0 @@
-from fontTools.ttLib.tables import otTables
-from fontTools.otlLib.builder import buildStatTable
-from fontTools.varLib import instancer
-
-import pytest
-
-
-def test_pruningUnusedNames(varfont):
-    varNameIDs = instancer.names.getVariationNameIDs(varfont)
-
-    assert varNameIDs == set(range(256, 297 + 1))
-
-    fvar = varfont["fvar"]
-    stat = varfont["STAT"].table
-
-    with instancer.names.pruningUnusedNames(varfont):
-        del fvar.axes[0]  # Weight (nameID=256)
-        del fvar.instances[0]  # Thin (nameID=258)
-        del stat.DesignAxisRecord.Axis[0]  # Weight (nameID=256)
-        del stat.AxisValueArray.AxisValue[0]  # Thin (nameID=258)
-
-    assert not any(n for n in varfont["name"].names if n.nameID in {256, 258})
-
-    with instancer.names.pruningUnusedNames(varfont):
-        del varfont["fvar"]
-        del varfont["STAT"]
-
-    assert not any(n for n in varfont["name"].names if n.nameID in varNameIDs)
-    assert "ltag" not in varfont
-
-
-def _test_name_records(varfont, expected, isNonRIBBI, platforms=[0x409]):
-    nametable = varfont["name"]
-    font_names = {
-        (r.nameID, r.platformID, r.platEncID, r.langID): r.toUnicode()
-        for r in nametable.names
-    }
-    for k in expected:
-        if k[-1] not in platforms:
-            continue
-        assert font_names[k] == expected[k]
-
-    font_nameids = set(i[0] for i in font_names)
-    if isNonRIBBI:
-        assert 16 in font_nameids
-        assert 17 in font_nameids
-
-    if "fvar" not in varfont:
-        assert 25 not in font_nameids
-
-
-@pytest.mark.parametrize(
-    "limits, expected, isNonRIBBI",
-    [
-        # Regular
-        (
-            {"wght": 400},
-            {
-                (1, 3, 1, 0x409): "Test Variable Font",
-                (2, 3, 1, 0x409): "Regular",
-                (3, 3, 1, 0x409): "2.001;GOOG;TestVariableFont-Regular",
-                (6, 3, 1, 0x409): "TestVariableFont-Regular",
-            },
-            False,
-        ),
-        # Regular Normal (width axis Normal isn't included since it is elided)
-        (
-            {"wght": 400, "wdth": 100},
-            {
-                (1, 3, 1, 0x409): "Test Variable Font",
-                (2, 3, 1, 0x409): "Regular",
-                (3, 3, 1, 0x409): "2.001;GOOG;TestVariableFont-Regular",
-                (6, 3, 1, 0x409): "TestVariableFont-Regular",
-            },
-            False,
-        ),
-        # Black
-        (
-            {"wght": 900},
-            {
-                (1, 3, 1, 0x409): "Test Variable Font Black",
-                (2, 3, 1, 0x409): "Regular",
-                (3, 3, 1, 0x409): "2.001;GOOG;TestVariableFont-Black",
-                (6, 3, 1, 0x409): "TestVariableFont-Black",
-                (16, 3, 1, 0x409): "Test Variable Font",
-                (17, 3, 1, 0x409): "Black",
-            },
-            True,
-        ),
-        # Thin
-        (
-            {"wght": 100},
-            {
-                (1, 3, 1, 0x409): "Test Variable Font Thin",
-                (2, 3, 1, 0x409): "Regular",
-                (3, 3, 1, 0x409): "2.001;GOOG;TestVariableFont-Thin",
-                (6, 3, 1, 0x409): "TestVariableFont-Thin",
-                (16, 3, 1, 0x409): "Test Variable Font",
-                (17, 3, 1, 0x409): "Thin",
-            },
-            True,
-        ),
-        # Thin Condensed
-        (
-            {"wght": 100, "wdth": 79},
-            {
-                (1, 3, 1, 0x409): "Test Variable Font Thin Condensed",
-                (2, 3, 1, 0x409): "Regular",
-                (3, 3, 1, 0x409): "2.001;GOOG;TestVariableFont-ThinCondensed",
-                (6, 3, 1, 0x409): "TestVariableFont-ThinCondensed",
-                (16, 3, 1, 0x409): "Test Variable Font",
-                (17, 3, 1, 0x409): "Thin Condensed",
-            },
-            True,
-        ),
-        # Condensed with unpinned weights
-        (
-            {"wdth": 79, "wght": instancer.AxisRange(400, 900)},
-            {
-                (1, 3, 1, 0x409): "Test Variable Font Condensed",
-                (2, 3, 1, 0x409): "Regular",
-                (3, 3, 1, 0x409): "2.001;GOOG;TestVariableFont-Condensed",
-                (6, 3, 1, 0x409): "TestVariableFont-Condensed",
-                (16, 3, 1, 0x409): "Test Variable Font",
-                (17, 3, 1, 0x409): "Condensed",
-            },
-            True,
-        ),
-    ],
-)
-def test_updateNameTable_with_registered_axes_ribbi(
-    varfont, limits, expected, isNonRIBBI
-):
-    instancer.names.updateNameTable(varfont, limits)
-    _test_name_records(varfont, expected, isNonRIBBI)
-
-
-def test_updatetNameTable_axis_order(varfont):
-    axes = [
-        dict(
-            tag="wght",
-            name="Weight",
-            values=[
-                dict(value=400, name="Regular"),
-            ],
-        ),
-        dict(
-            tag="wdth",
-            name="Width",
-            values=[
-                dict(value=75, name="Condensed"),
-            ],
-        ),
-    ]
-    nametable = varfont["name"]
-    buildStatTable(varfont, axes)
-    instancer.names.updateNameTable(varfont, {"wdth": 75, "wght": 400})
-    assert nametable.getName(17, 3, 1, 0x409).toUnicode() == "Regular Condensed"
-
-    # Swap the axes so the names get swapped
-    axes[0], axes[1] = axes[1], axes[0]
-
-    buildStatTable(varfont, axes)
-    instancer.names.updateNameTable(varfont, {"wdth": 75, "wght": 400})
-    assert nametable.getName(17, 3, 1, 0x409).toUnicode() == "Condensed Regular"
-
-
-@pytest.mark.parametrize(
-    "limits, expected, isNonRIBBI",
-    [
-        # Regular | Normal
-        (
-            {"wght": 400},
-            {
-                (1, 3, 1, 0x409): "Test Variable Font",
-                (2, 3, 1, 0x409): "Normal",
-            },
-            False,
-        ),
-        # Black | Negreta
-        (
-            {"wght": 900},
-            {
-                (1, 3, 1, 0x409): "Test Variable Font Negreta",
-                (2, 3, 1, 0x409): "Normal",
-                (16, 3, 1, 0x409): "Test Variable Font",
-                (17, 3, 1, 0x409): "Negreta",
-            },
-            True,
-        ),
-        # Black Condensed | Negreta Zhuštěné
-        (
-            {"wght": 900, "wdth": 79},
-            {
-                (1, 3, 1, 0x409): "Test Variable Font Negreta Zhuštěné",
-                (2, 3, 1, 0x409): "Normal",
-                (16, 3, 1, 0x409): "Test Variable Font",
-                (17, 3, 1, 0x409): "Negreta Zhuštěné",
-            },
-            True,
-        ),
-    ],
-)
-def test_updateNameTable_with_multilingual_names(varfont, limits, expected, isNonRIBBI):
-    name = varfont["name"]
-    # langID 0x405 is the Czech Windows langID
-    name.setName("Test Variable Font", 1, 3, 1, 0x405)
-    name.setName("Normal", 2, 3, 1, 0x405)
-    name.setName("Normal", 261, 3, 1, 0x405)  # nameID 261=Regular STAT entry
-    name.setName("Negreta", 266, 3, 1, 0x405)  # nameID 266=Black STAT entry
-    name.setName("Zhuštěné", 279, 3, 1, 0x405)  # nameID 279=Condensed STAT entry
-
-    instancer.names.updateNameTable(varfont, limits)
-    _test_name_records(varfont, expected, isNonRIBBI, platforms=[0x405])
-
-
-def test_updateNameTable_missing_axisValues(varfont):
-    with pytest.raises(ValueError, match="Cannot find Axis Values \['wght=200'\]"):
-        instancer.names.updateNameTable(varfont, {"wght": 200})
-
-
-def test_updateNameTable_missing_stat(varfont):
-    del varfont["STAT"]
-    with pytest.raises(
-        ValueError, match="Cannot update name table since there is no STAT table."
-    ):
-        instancer.names.updateNameTable(varfont, {"wght": 400})
-
-
-@pytest.mark.parametrize(
-    "limits, expected, isNonRIBBI",
-    [
-        # Regular | Normal
-        (
-            {"wght": 400},
-            {
-                (1, 3, 1, 0x409): "Test Variable Font",
-                (2, 3, 1, 0x409): "Italic",
-                (6, 3, 1, 0x409): "TestVariableFont-Italic",
-            },
-            False,
-        ),
-        # Black Condensed Italic
-        (
-            {"wght": 900, "wdth": 79},
-            {
-                (1, 3, 1, 0x409): "Test Variable Font Black Condensed",
-                (2, 3, 1, 0x409): "Italic",
-                (6, 3, 1, 0x409): "TestVariableFont-BlackCondensedItalic",
-                (16, 3, 1, 0x409): "Test Variable Font",
-                (17, 3, 1, 0x409): "Black Condensed Italic",
-            },
-            True,
-        ),
-    ],
-)
-def test_updateNameTable_vf_with_italic_attribute(
-    varfont, limits, expected, isNonRIBBI
-):
-    font_link_axisValue = varfont["STAT"].table.AxisValueArray.AxisValue[4]
-    # Unset ELIDABLE_AXIS_VALUE_NAME flag
-    font_link_axisValue.Flags &= ~instancer.names.ELIDABLE_AXIS_VALUE_NAME
-    font_link_axisValue.ValueNameID = 294  # Roman --> Italic
-
-    instancer.names.updateNameTable(varfont, limits)
-    _test_name_records(varfont, expected, isNonRIBBI)
-
-
-def test_updateNameTable_format4_axisValues(varfont):
-    # format 4 axisValues should dominate the other axisValues
-    stat = varfont["STAT"].table
-
-    axisValue = otTables.AxisValue()
-    axisValue.Format = 4
-    axisValue.Flags = 0
-    varfont["name"].setName("Dominant Value", 297, 3, 1, 0x409)
-    axisValue.ValueNameID = 297
-    axisValue.AxisValueRecord = []
-    for tag, value in (("wght", 900), ("wdth", 79)):
-        rec = otTables.AxisValueRecord()
-        rec.AxisIndex = next(
-            i for i, a in enumerate(stat.DesignAxisRecord.Axis) if a.AxisTag == tag
-        )
-        rec.Value = value
-        axisValue.AxisValueRecord.append(rec)
-    stat.AxisValueArray.AxisValue.append(axisValue)
-
-    instancer.names.updateNameTable(varfont, {"wdth": 79, "wght": 900})
-    expected = {
-        (1, 3, 1, 0x409): "Test Variable Font Dominant Value",
-        (2, 3, 1, 0x409): "Regular",
-        (16, 3, 1, 0x409): "Test Variable Font",
-        (17, 3, 1, 0x409): "Dominant Value",
-    }
-    _test_name_records(varfont, expected, isNonRIBBI=True)
-
-
-def test_updateNameTable_elided_axisValues(varfont):
-    stat = varfont["STAT"].table
-    # set ELIDABLE_AXIS_VALUE_NAME flag for all axisValues
-    for axisValue in stat.AxisValueArray.AxisValue:
-        axisValue.Flags |= instancer.names.ELIDABLE_AXIS_VALUE_NAME
-
-    stat.ElidedFallbackNameID = 266  # Regular --> Black
-    instancer.names.updateNameTable(varfont, {"wght": 400})
-    # Since all axis values are elided, the elided fallback name
-    # must be used to construct the style names. Since we
-    # changed it to Black, we need both a typoSubFamilyName and
-    # the subFamilyName set so it conforms to the RIBBI model.
-    expected = {(2, 3, 1, 0x409): "Regular", (17, 3, 1, 0x409): "Black"}
-    _test_name_records(varfont, expected, isNonRIBBI=True)
-
-
-def test_updateNameTable_existing_subfamily_name_is_not_regular(varfont):
-    # Check the subFamily name will be set to Regular when we update a name
-    # table to a non-RIBBI style and the current subFamily name is a RIBBI
-    # style which isn't Regular.
-    varfont["name"].setName("Bold", 2, 3, 1, 0x409)  # subFamily Regular --> Bold
-
-    instancer.names.updateNameTable(varfont, {"wght": 100})
-    expected = {(2, 3, 1, 0x409): "Regular", (17, 3, 1, 0x409): "Thin"}
-    _test_name_records(varfont, expected, isNonRIBBI=True)
diff --git a/Tests/varLib/instancer/instancer_test.py b/Tests/varLib/instancer_test.py
similarity index 66%
rename from Tests/varLib/instancer/instancer_test.py
rename to Tests/varLib/instancer_test.py
index cb7e854..7c587b5 100644
--- a/Tests/varLib/instancer/instancer_test.py
+++ b/Tests/varLib/instancer_test.py
@@ -1,5 +1,5 @@
-from fontTools.misc.py23 import Tag
-from fontTools.misc.fixedTools import floatToFixedToFloat
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools import ttLib
 from fontTools import designspaceLib
 from fontTools.feaLib.builder import addOpenTypeFeaturesFromString
@@ -14,19 +14,22 @@
 from fontTools.varLib import models
 import collections
 from copy import deepcopy
-from io import BytesIO, StringIO
 import logging
 import os
 import re
-from types import SimpleNamespace
 import pytest
 
 
-# see Tests/varLib/instancer/conftest.py for "varfont" fixture definition
-
 TESTDATA = os.path.join(os.path.dirname(__file__), "data")
 
 
+@pytest.fixture
+def varfont():
+    f = ttLib.TTFont()
+    f.importXML(os.path.join(TESTDATA, "PartialInstancerTest-VF.ttx"))
+    return f
+
+
 @pytest.fixture(params=[True, False], ids=["optimize", "no-optimize"])
 def optimize(request):
     return request.param
@@ -141,7 +144,7 @@
         assert "gvar" not in varfont
 
     def test_composite_glyph_not_in_gvar(self, varfont):
-        """The 'minus' glyph is a composite glyph, which references 'hyphen' as a
+        """ The 'minus' glyph is a composite glyph, which references 'hyphen' as a
         component, but has no tuple variations in gvar table, so the component offset
         and the phantom points do not change; however the sidebearings and bounding box
         do change as a result of the parent glyph 'hyphen' changing.
@@ -334,12 +337,12 @@
                 {"wdth": -1.0},
                 [
                     {"wght": (-1.0, -1.0, 0.0)},
-                    {"wght": (0.0, 0.6099854, 1.0)},
-                    {"wght": (0.6099854, 1.0, 1.0)},
+                    {"wght": (0.0, 0.61, 1.0)},
+                    {"wght": (0.61, 1.0, 1.0)},
                 ],
                 [-11, 31, 51],
             ),
-            ({"wdth": 0}, [{"wght": (0.6099854, 1.0, 1.0)}], [-4]),
+            ({"wdth": 0}, [{"wght": (0.61, 1.0, 1.0)}], [-4]),
         ],
     )
     def test_partial_instance(self, varfont, location, expectedRegions, expectedDeltas):
@@ -351,12 +354,7 @@
 
         regions = varStore.VarRegionList.Region
         fvarAxes = [a for a in varfont["fvar"].axes if a.axisTag not in location]
-        regionDicts = [reg.get_support(fvarAxes) for reg in regions]
-        assert len(regionDicts) == len(expectedRegions)
-        for region, expectedRegion in zip(regionDicts, expectedRegions):
-            assert region.keys() == expectedRegion.keys()
-            for axisTag, support in region.items():
-                assert support == pytest.approx(expectedRegion[axisTag])
+        assert [reg.get_support(fvarAxes) for reg in regions] == expectedRegions
 
         assert len(varStore.VarData) == 1
         assert varStore.VarData[0].ItemCount == 2
@@ -379,26 +377,6 @@
 
         assert "HVAR" not in varfont
 
-    def test_partial_instance_keep_empty_table(self, varfont):
-        # Append an additional dummy axis to fvar, for which the current HVAR table
-        # in our test 'varfont' contains no variation data.
-        # Instancing the other two wght and wdth axes should leave HVAR table empty,
-        # to signal there are variations to the glyph's advance widths.
-        fvar = varfont["fvar"]
-        axis = _f_v_a_r.Axis()
-        axis.axisTag = "TEST"
-        fvar.axes.append(axis)
-
-        instancer.instantiateHVAR(varfont, {"wght": 0, "wdth": 0})
-
-        assert "HVAR" in varfont
-
-        varStore = varfont["HVAR"].table.VarStore
-
-        assert varStore.VarRegionList.RegionCount == 0
-        assert not varStore.VarRegionList.Region
-        assert varStore.VarRegionList.RegionAxisCount == 1
-
 
 class InstantiateItemVariationStoreTest(object):
     def test_VarRegion_get_support(self):
@@ -511,40 +489,33 @@
             [TupleVariation({"wdth": (-1.0, -1.0, 0)}, [-12, 8])],
         ]
 
-    def test_rebuildRegions(self):
+    def test_dropAxes(self):
         regions = [
             {"wght": (-1.0, -1.0, 0)},
             {"wght": (0.0, 1.0, 1.0)},
             {"wdth": (-1.0, -1.0, 0)},
+            {"opsz": (0.0, 1.0, 1.0)},
             {"wght": (-1.0, -1.0, 0), "wdth": (-1.0, -1.0, 0)},
-            {"wght": (0, 1.0, 1.0), "wdth": (-1.0, -1.0, 0)},
+            {"wght": (0, 0.5, 1.0), "wdth": (-1.0, -1.0, 0)},
+            {"wght": (0.5, 1.0, 1.0), "wdth": (-1.0, -1.0, 0)},
         ]
-        axisOrder = ["wght", "wdth"]
-        variations = []
-        for region in regions:
-            variations.append(TupleVariation(region, [100]))
-        tupleVarData = [variations[:3], variations[3:]]
-        adapter = instancer._TupleVarStoreAdapter(
-            regions, axisOrder, tupleVarData, itemCounts=[1, 1]
-        )
+        axisOrder = ["wght", "wdth", "opsz"]
+        adapter = instancer._TupleVarStoreAdapter(regions, axisOrder, [], itemCounts=[])
 
-        adapter.rebuildRegions()
-
-        assert adapter.regions == regions
-
-        del tupleVarData[0][2]
-        tupleVarData[1][0].axes = {"wght": (-1.0, -0.5, 0)}
-        tupleVarData[1][1].axes = {"wght": (0, 0.5, 1.0)}
-
-        adapter.rebuildRegions()
+        adapter.dropAxes({"wdth"})
 
         assert adapter.regions == [
             {"wght": (-1.0, -1.0, 0)},
             {"wght": (0.0, 1.0, 1.0)},
-            {"wght": (-1.0, -0.5, 0)},
-            {"wght": (0, 0.5, 1.0)},
+            {"opsz": (0.0, 1.0, 1.0)},
+            {"wght": (0.0, 0.5, 1.0)},
+            {"wght": (0.5, 1.0, 1.0)},
         ]
 
+        adapter.dropAxes({"wght", "opsz"})
+
+        assert adapter.regions == []
+
     def test_roundtrip(self, fvarAxes):
         regions = [
             {"wght": (-1.0, -1.0, 0)},
@@ -949,208 +920,6 @@
 
         assert "avar" not in varfont
 
-    @staticmethod
-    def quantizeF2Dot14Floats(mapping):
-        return {
-            floatToFixedToFloat(k, 14): floatToFixedToFloat(v, 14)
-            for k, v in mapping.items()
-        }
-
-    # the following values come from NotoSans-VF.ttf
-    DFLT_WGHT_MAPPING = {
-        -1.0: -1.0,
-        -0.6667: -0.7969,
-        -0.3333: -0.5,
-        0: 0,
-        0.2: 0.18,
-        0.4: 0.38,
-        0.6: 0.61,
-        0.8: 0.79,
-        1.0: 1.0,
-    }
-
-    DFLT_WDTH_MAPPING = {-1.0: -1.0, -0.6667: -0.7, -0.3333: -0.36664, 0: 0, 1.0: 1.0}
-
-    @pytest.fixture
-    def varfont(self):
-        fvarAxes = ("wght", (100, 400, 900)), ("wdth", (62.5, 100, 100))
-        avarSegments = {
-            "wght": self.quantizeF2Dot14Floats(self.DFLT_WGHT_MAPPING),
-            "wdth": self.quantizeF2Dot14Floats(self.DFLT_WDTH_MAPPING),
-        }
-        varfont = ttLib.TTFont()
-        varfont["name"] = ttLib.newTable("name")
-        varLib._add_fvar(varfont, _makeDSAxesDict(fvarAxes), instances=())
-        avar = varfont["avar"] = ttLib.newTable("avar")
-        avar.segments = avarSegments
-        return varfont
-
-    @pytest.mark.parametrize(
-        "axisLimits, expectedSegments",
-        [
-            pytest.param(
-                {"wght": (100, 900)},
-                {"wght": DFLT_WGHT_MAPPING, "wdth": DFLT_WDTH_MAPPING},
-                id="wght=100:900",
-            ),
-            pytest.param(
-                {"wght": (400, 900)},
-                {
-                    "wght": {
-                        -1.0: -1.0,
-                        0: 0,
-                        0.2: 0.18,
-                        0.4: 0.38,
-                        0.6: 0.61,
-                        0.8: 0.79,
-                        1.0: 1.0,
-                    },
-                    "wdth": DFLT_WDTH_MAPPING,
-                },
-                id="wght=400:900",
-            ),
-            pytest.param(
-                {"wght": (100, 400)},
-                {
-                    "wght": {
-                        -1.0: -1.0,
-                        -0.6667: -0.7969,
-                        -0.3333: -0.5,
-                        0: 0,
-                        1.0: 1.0,
-                    },
-                    "wdth": DFLT_WDTH_MAPPING,
-                },
-                id="wght=100:400",
-            ),
-            pytest.param(
-                {"wght": (400, 800)},
-                {
-                    "wght": {
-                        -1.0: -1.0,
-                        0: 0,
-                        0.25: 0.22784,
-                        0.50006: 0.48103,
-                        0.75: 0.77214,
-                        1.0: 1.0,
-                    },
-                    "wdth": DFLT_WDTH_MAPPING,
-                },
-                id="wght=400:800",
-            ),
-            pytest.param(
-                {"wght": (400, 700)},
-                {
-                    "wght": {
-                        -1.0: -1.0,
-                        0: 0,
-                        0.3334: 0.2951,
-                        0.66675: 0.623,
-                        1.0: 1.0,
-                    },
-                    "wdth": DFLT_WDTH_MAPPING,
-                },
-                id="wght=400:700",
-            ),
-            pytest.param(
-                {"wght": (400, 600)},
-                {
-                    "wght": {-1.0: -1.0, 0: 0, 0.5: 0.47363, 1.0: 1.0},
-                    "wdth": DFLT_WDTH_MAPPING,
-                },
-                id="wght=400:600",
-            ),
-            pytest.param(
-                {"wdth": (62.5, 100)},
-                {
-                    "wght": DFLT_WGHT_MAPPING,
-                    "wdth": {
-                        -1.0: -1.0,
-                        -0.6667: -0.7,
-                        -0.3333: -0.36664,
-                        0: 0,
-                        1.0: 1.0,
-                    },
-                },
-                id="wdth=62.5:100",
-            ),
-            pytest.param(
-                {"wdth": (70, 100)},
-                {
-                    "wght": DFLT_WGHT_MAPPING,
-                    "wdth": {
-                        -1.0: -1.0,
-                        -0.8334: -0.85364,
-                        -0.4166: -0.44714,
-                        0: 0,
-                        1.0: 1.0,
-                    },
-                },
-                id="wdth=70:100",
-            ),
-            pytest.param(
-                {"wdth": (75, 100)},
-                {
-                    "wght": DFLT_WGHT_MAPPING,
-                    "wdth": {-1.0: -1.0, -0.49994: -0.52374, 0: 0, 1.0: 1.0},
-                },
-                id="wdth=75:100",
-            ),
-            pytest.param(
-                {"wdth": (77, 100)},
-                {
-                    "wght": DFLT_WGHT_MAPPING,
-                    "wdth": {-1.0: -1.0, -0.54346: -0.56696, 0: 0, 1.0: 1.0},
-                },
-                id="wdth=77:100",
-            ),
-            pytest.param(
-                {"wdth": (87.5, 100)},
-                {"wght": DFLT_WGHT_MAPPING, "wdth": {-1.0: -1.0, 0: 0, 1.0: 1.0}},
-                id="wdth=87.5:100",
-            ),
-        ],
-    )
-    def test_limit_axes(self, varfont, axisLimits, expectedSegments):
-        instancer.instantiateAvar(varfont, axisLimits)
-
-        newSegments = varfont["avar"].segments
-        expectedSegments = {
-            axisTag: self.quantizeF2Dot14Floats(mapping)
-            for axisTag, mapping in expectedSegments.items()
-        }
-        assert newSegments == expectedSegments
-
-    @pytest.mark.parametrize(
-        "invalidSegmentMap",
-        [
-            pytest.param({0.5: 0.5}, id="missing-required-maps-1"),
-            pytest.param({-1.0: -1.0, 1.0: 1.0}, id="missing-required-maps-2"),
-            pytest.param(
-                {-1.0: -1.0, 0: 0, 0.5: 0.5, 0.6: 0.4, 1.0: 1.0},
-                id="retrograde-value-maps",
-            ),
-        ],
-    )
-    def test_drop_invalid_segment_map(self, varfont, invalidSegmentMap, caplog):
-        varfont["avar"].segments["wght"] = invalidSegmentMap
-
-        with caplog.at_level(logging.WARNING, logger="fontTools.varLib.instancer"):
-            instancer.instantiateAvar(varfont, {"wght": (100, 400)})
-
-        assert "Invalid avar" in caplog.text
-        assert "wght" not in varfont["avar"].segments
-
-    def test_isValidAvarSegmentMap(self):
-        assert instancer._isValidAvarSegmentMap("FOOO", {})
-        assert instancer._isValidAvarSegmentMap("FOOO", {-1.0: -1.0, 0: 0, 1.0: 1.0})
-        assert instancer._isValidAvarSegmentMap(
-            "FOOO", {-1.0: -1.0, 0: 0, 0.5: 0.5, 1.0: 1.0}
-        )
-        assert instancer._isValidAvarSegmentMap(
-            "FOOO", {-1.0: -1.0, 0: 0, 0.5: 0.5, 0.7: 0.5, 1.0: 1.0}
-        )
-
 
 class InstantiateFvarTest(object):
     @pytest.mark.parametrize(
@@ -1206,8 +975,8 @@
     @pytest.mark.parametrize(
         "location, expected",
         [
-            ({"wght": 400}, ["Regular", "Condensed", "Upright", "Normal"]),
-            ({"wdth": 100}, ["Thin", "Regular", "Black", "Upright", "Normal"]),
+            ({"wght": 400}, ["Condensed", "Upright"]),
+            ({"wdth": 100}, ["Thin", "Regular", "Black", "Upright"]),
         ],
     )
     def test_pin_and_drop_axis(self, varfont, location, expected):
@@ -1216,7 +985,7 @@
         stat = varfont["STAT"].table
         designAxes = {a.AxisTag for a in stat.DesignAxisRecord.Axis}
 
-        assert designAxes == {"wght", "wdth", "ital"}
+        assert designAxes == {"wght", "wdth", "ital"}.difference(location)
 
         name = varfont["name"]
         valueNames = []
@@ -1226,23 +995,7 @@
 
         assert valueNames == expected
 
-    def test_skip_table_no_axis_value_array(self, varfont):
-        varfont["STAT"].table.AxisValueArray = None
-
-        instancer.instantiateSTAT(varfont, {"wght": 100})
-
-        assert len(varfont["STAT"].table.DesignAxisRecord.Axis) == 3
-        assert varfont["STAT"].table.AxisValueArray is None
-
-    def test_skip_table_axis_value_array_empty(self, varfont):
-        varfont["STAT"].table.AxisValueArray.AxisValue = []
-
-        instancer.instantiateSTAT(varfont, {"wght": 100})
-
-        assert len(varfont["STAT"].table.DesignAxisRecord.Axis) == 3
-        assert not varfont["STAT"].table.AxisValueArray.AxisValue
-
-    def test_skip_table_no_design_axes(self, varfont):
+    def test_skip_empty_table(self, varfont):
         stat = otTables.STAT()
         stat.Version = 0x00010001
         stat.populateDefaults()
@@ -1254,88 +1007,45 @@
 
         assert not varfont["STAT"].table.DesignAxisRecord
 
-    @staticmethod
-    def get_STAT_axis_values(stat):
-        axes = stat.DesignAxisRecord.Axis
-        result = []
-        for axisValue in stat.AxisValueArray.AxisValue:
-            if axisValue.Format == 1:
-                result.append((axes[axisValue.AxisIndex].AxisTag, axisValue.Value))
-            elif axisValue.Format == 3:
-                result.append(
-                    (
-                        axes[axisValue.AxisIndex].AxisTag,
-                        (axisValue.Value, axisValue.LinkedValue),
-                    )
-                )
-            elif axisValue.Format == 2:
-                result.append(
-                    (
-                        axes[axisValue.AxisIndex].AxisTag,
-                        (
-                            axisValue.RangeMinValue,
-                            axisValue.NominalValue,
-                            axisValue.RangeMaxValue,
-                        ),
-                    )
-                )
-            elif axisValue.Format == 4:
-                result.append(
-                    tuple(
-                        (axes[rec.AxisIndex].AxisTag, rec.Value)
-                        for rec in axisValue.AxisValueRecord
-                    )
-                )
-            else:
-                raise AssertionError(axisValue.Format)
-        return result
+    def test_drop_table(self, varfont):
+        stat = otTables.STAT()
+        stat.Version = 0x00010001
+        stat.populateDefaults()
+        stat.DesignAxisRecord = otTables.AxisRecordArray()
+        axis = otTables.AxisRecord()
+        axis.AxisTag = "wght"
+        axis.AxisNameID = 0
+        axis.AxisOrdering = 0
+        stat.DesignAxisRecord.Axis = [axis]
+        varfont["STAT"].table = stat
 
-    def test_limit_axes(self, varfont2):
-        instancer.instantiateSTAT(varfont2, {"wght": (400, 500), "wdth": (75, 100)})
+        instancer.instantiateSTAT(varfont, {"wght": 100})
 
-        assert len(varfont2["STAT"].table.AxisValueArray.AxisValue) == 5
-        assert self.get_STAT_axis_values(varfont2["STAT"].table) == [
-            ("wght", (400.0, 700.0)),
-            ("wght", 500.0),
-            ("wdth", (93.75, 100.0, 100.0)),
-            ("wdth", (81.25, 87.5, 93.75)),
-            ("wdth", (68.75, 75.0, 81.25)),
-        ]
+        assert "STAT" not in varfont
 
-    def test_limit_axis_value_format_4(self, varfont2):
-        stat = varfont2["STAT"].table
 
-        axisValue = otTables.AxisValue()
-        axisValue.Format = 4
-        axisValue.AxisValueRecord = []
-        for tag, value in (("wght", 575), ("wdth", 90)):
-            rec = otTables.AxisValueRecord()
-            rec.AxisIndex = next(
-                i for i, a in enumerate(stat.DesignAxisRecord.Axis) if a.AxisTag == tag
-            )
-            rec.Value = value
-            axisValue.AxisValueRecord.append(rec)
-        stat.AxisValueArray.AxisValue.append(axisValue)
+def test_pruningUnusedNames(varfont):
+    varNameIDs = instancer.getVariationNameIDs(varfont)
 
-        instancer.instantiateSTAT(varfont2, {"wght": (100, 600)})
+    assert varNameIDs == set(range(256, 296 + 1))
 
-        assert axisValue in varfont2["STAT"].table.AxisValueArray.AxisValue
+    fvar = varfont["fvar"]
+    stat = varfont["STAT"].table
 
-        instancer.instantiateSTAT(varfont2, {"wdth": (62.5, 87.5)})
+    with instancer.pruningUnusedNames(varfont):
+        del fvar.axes[0]  # Weight (nameID=256)
+        del fvar.instances[0]  # Thin (nameID=258)
+        del stat.DesignAxisRecord.Axis[0]  # Weight (nameID=256)
+        del stat.AxisValueArray.AxisValue[0]  # Thin (nameID=258)
 
-        assert axisValue not in varfont2["STAT"].table.AxisValueArray.AxisValue
+    assert not any(n for n in varfont["name"].names if n.nameID in {256, 258})
 
-    def test_unknown_axis_value_format(self, varfont2, caplog):
-        stat = varfont2["STAT"].table
-        axisValue = otTables.AxisValue()
-        axisValue.Format = 5
-        stat.AxisValueArray.AxisValue.append(axisValue)
+    with instancer.pruningUnusedNames(varfont):
+        del varfont["fvar"]
+        del varfont["STAT"]
 
-        with caplog.at_level(logging.WARNING, logger="fontTools.varLib.instancer"):
-            instancer.instantiateSTAT(varfont2, {"wght": 400})
-
-        assert "Unknown AxisValue table format (5)" in caplog.text
-        assert axisValue in varfont2["STAT"].table.AxisValueArray.AxisValue
+    assert not any(n for n in varfont["name"].names if n.nameID in varNameIDs)
+    assert "ltag" not in varfont
 
 
 def test_setMacOverlapFlags():
@@ -1373,13 +1083,6 @@
     return f
 
 
-@pytest.fixture
-def varfont3():
-    f = ttLib.TTFont(recalcTimestamp=False)
-    f.importXML(os.path.join(TESTDATA, "PartialInstancerTest3-VF.ttx"))
-    return f
-
-
 def _dump_ttx(ttFont):
     # compile to temporary bytes stream, reload and dump to XML
     tmp = BytesIO()
@@ -1391,16 +1094,13 @@
     return _strip_ttLibVersion(s.getvalue())
 
 
-def _get_expected_instance_ttx(
-    name, *locations, overlap=instancer.OverlapMode.KEEP_AND_SET_FLAGS
-):
-    filename = f"{name}-VF-instance-{','.join(str(loc) for loc in locations)}"
-    if overlap == instancer.OverlapMode.KEEP_AND_DONT_SET_FLAGS:
-        filename += "-no-overlap-flags"
-    elif overlap == instancer.OverlapMode.REMOVE:
-        filename += "-no-overlaps"
+def _get_expected_instance_ttx(wght, wdth):
     with open(
-        os.path.join(TESTDATA, "test_results", f"{filename}.ttx"),
+        os.path.join(
+            TESTDATA,
+            "test_results",
+            "PartialInstancerTest2-VF-instance-{0},{1}.ttx".format(wght, wdth),
+        ),
         "r",
         encoding="utf-8",
     ) as fp:
@@ -1416,7 +1116,7 @@
         partial = instancer.instantiateVariableFont(varfont2, {"wght": wght})
         instance = instancer.instantiateVariableFont(partial, {"wdth": wdth})
 
-        expected = _get_expected_instance_ttx("PartialInstancerTest2", wght, wdth)
+        expected = _get_expected_instance_ttx(wght, wdth)
 
         assert _dump_ttx(instance) == expected
 
@@ -1425,30 +1125,7 @@
             varfont2, {"wght": None, "wdth": None}
         )
 
-        expected = _get_expected_instance_ttx("PartialInstancerTest2", 400, 100)
-
-        assert _dump_ttx(instance) == expected
-
-    @pytest.mark.parametrize(
-        "overlap, wght",
-        [
-            (instancer.OverlapMode.KEEP_AND_DONT_SET_FLAGS, 400),
-            (instancer.OverlapMode.REMOVE, 400),
-            (instancer.OverlapMode.REMOVE, 700),
-        ],
-    )
-    def test_overlap(self, varfont3, wght, overlap):
-        pytest.importorskip("pathops")
-
-        location = {"wght": wght}
-
-        instance = instancer.instantiateVariableFont(
-            varfont3, location, overlap=overlap
-        )
-
-        expected = _get_expected_instance_ttx(
-            "PartialInstancerTest3", wght, overlap=overlap
-        )
+        expected = _get_expected_instance_ttx(400, 100)
 
         assert _dump_ttx(instance) == expected
 
@@ -1639,218 +1316,13 @@
         assert len(rec1.ConditionSet.ConditionTable) == 2
         assert rec1.ConditionSet.ConditionTable[0].Format == 2
 
-    def test_GSUB_FeatureVariations_is_None(self, varfont2):
-        varfont2["GSUB"].table.Version = 0x00010001
-        varfont2["GSUB"].table.FeatureVariations = None
-        tmp = BytesIO()
-        varfont2.save(tmp)
-        varfont = ttLib.TTFont(tmp)
-
-        # DO NOT raise an exception when the optional 'FeatureVariations' attribute is
-        # present but is set to None (e.g. with GSUB 1.1); skip and do nothing.
-        assert varfont["GSUB"].table.FeatureVariations is None
-        instancer.instantiateFeatureVariations(varfont, {"wght": 400, "wdth": 100})
-        assert varfont["GSUB"].table.FeatureVariations is None
-
-
-class LimitTupleVariationAxisRangesTest:
-    def check_limit_single_var_axis_range(self, var, axisTag, axisRange, expected):
-        result = instancer.limitTupleVariationAxisRange(var, axisTag, axisRange)
-        print(result)
-
-        assert len(result) == len(expected)
-        for v1, v2 in zip(result, expected):
-            assert v1.coordinates == pytest.approx(v2.coordinates)
-            assert v1.axes.keys() == v2.axes.keys()
-            for k in v1.axes:
-                p, q = v1.axes[k], v2.axes[k]
-                assert p == pytest.approx(q)
-
-    @pytest.mark.parametrize(
-        "var, axisTag, newMax, expected",
-        [
-            (
-                TupleVariation({"wght": (0.0, 1.0, 1.0)}, [100, 100]),
-                "wdth",
-                0.5,
-                [TupleVariation({"wght": (0.0, 1.0, 1.0)}, [100, 100])],
-            ),
-            (
-                TupleVariation({"wght": (0.0, 1.0, 1.0)}, [100, 100]),
-                "wght",
-                0.5,
-                [TupleVariation({"wght": (0.0, 1.0, 1.0)}, [50, 50])],
-            ),
-            (
-                TupleVariation({"wght": (0.0, 1.0, 1.0)}, [100, 100]),
-                "wght",
-                0.8,
-                [TupleVariation({"wght": (0.0, 1.0, 1.0)}, [80, 80])],
-            ),
-            (
-                TupleVariation({"wght": (0.0, 1.0, 1.0)}, [100, 100]),
-                "wght",
-                1.0,
-                [TupleVariation({"wght": (0.0, 1.0, 1.0)}, [100, 100])],
-            ),
-            (TupleVariation({"wght": (0.0, 1.0, 1.0)}, [100, 100]), "wght", 0.0, []),
-            (TupleVariation({"wght": (0.5, 1.0, 1.0)}, [100, 100]), "wght", 0.4, []),
-            (
-                TupleVariation({"wght": (0.0, 0.5, 1.0)}, [100, 100]),
-                "wght",
-                0.5,
-                [TupleVariation({"wght": (0.0, 1.0, 1.0)}, [100, 100])],
-            ),
-            (
-                TupleVariation({"wght": (0.0, 0.5, 1.0)}, [100, 100]),
-                "wght",
-                0.4,
-                [TupleVariation({"wght": (0.0, 1.0, 1.0)}, [80, 80])],
-            ),
-            (
-                TupleVariation({"wght": (0.0, 0.5, 1.0)}, [100, 100]),
-                "wght",
-                0.6,
-                [TupleVariation({"wght": (0.0, 0.833334, 1.666667)}, [100, 100])],
-            ),
-            (
-                TupleVariation({"wght": (0.0, 0.2, 1.0)}, [100, 100]),
-                "wght",
-                0.4,
-                [
-                    TupleVariation({"wght": (0.0, 0.5, 1.99994)}, [100, 100]),
-                    TupleVariation({"wght": (0.5, 1.0, 1.0)}, [8.33333, 8.33333]),
-                ],
-            ),
-            (
-                TupleVariation({"wght": (0.0, 0.2, 1.0)}, [100, 100]),
-                "wght",
-                0.5,
-                [TupleVariation({"wght": (0.0, 0.4, 1.99994)}, [100, 100])],
-            ),
-            (
-                TupleVariation({"wght": (0.5, 0.5, 1.0)}, [100, 100]),
-                "wght",
-                0.5,
-                [TupleVariation({"wght": (1.0, 1.0, 1.0)}, [100, 100])],
-            ),
-        ],
-    )
-    def test_positive_var(self, var, axisTag, newMax, expected):
-        axisRange = instancer.NormalizedAxisRange(0, newMax)
-        self.check_limit_single_var_axis_range(var, axisTag, axisRange, expected)
-
-    @pytest.mark.parametrize(
-        "var, axisTag, newMin, expected",
-        [
-            (
-                TupleVariation({"wght": (-1.0, -1.0, 0.0)}, [100, 100]),
-                "wdth",
-                -0.5,
-                [TupleVariation({"wght": (-1.0, -1.0, 0.0)}, [100, 100])],
-            ),
-            (
-                TupleVariation({"wght": (-1.0, -1.0, 0.0)}, [100, 100]),
-                "wght",
-                -0.5,
-                [TupleVariation({"wght": (-1.0, -1.0, 0.0)}, [50, 50])],
-            ),
-            (
-                TupleVariation({"wght": (-1.0, -1.0, 0.0)}, [100, 100]),
-                "wght",
-                -0.8,
-                [TupleVariation({"wght": (-1.0, -1.0, 0.0)}, [80, 80])],
-            ),
-            (
-                TupleVariation({"wght": (-1.0, -1.0, 0.0)}, [100, 100]),
-                "wght",
-                -1.0,
-                [TupleVariation({"wght": (-1.0, -1.0, 0.0)}, [100, 100])],
-            ),
-            (TupleVariation({"wght": (-1.0, -1.0, 0.0)}, [100, 100]), "wght", 0.0, []),
-            (
-                TupleVariation({"wght": (-1.0, -1.0, -0.5)}, [100, 100]),
-                "wght",
-                -0.4,
-                [],
-            ),
-            (
-                TupleVariation({"wght": (-1.0, -0.5, 0.0)}, [100, 100]),
-                "wght",
-                -0.5,
-                [TupleVariation({"wght": (-1.0, -1.0, 0.0)}, [100, 100])],
-            ),
-            (
-                TupleVariation({"wght": (-1.0, -0.5, 0.0)}, [100, 100]),
-                "wght",
-                -0.4,
-                [TupleVariation({"wght": (-1.0, -1.0, 0.0)}, [80, 80])],
-            ),
-            (
-                TupleVariation({"wght": (-1.0, -0.5, 0.0)}, [100, 100]),
-                "wght",
-                -0.6,
-                [TupleVariation({"wght": (-1.666667, -0.833334, 0.0)}, [100, 100])],
-            ),
-            (
-                TupleVariation({"wght": (-1.0, -0.2, 0.0)}, [100, 100]),
-                "wght",
-                -0.4,
-                [
-                    TupleVariation({"wght": (-2.0, -0.5, -0.0)}, [100, 100]),
-                    TupleVariation({"wght": (-1.0, -1.0, -0.5)}, [8.33333, 8.33333]),
-                ],
-            ),
-            (
-                TupleVariation({"wght": (-1.0, -0.2, 0.0)}, [100, 100]),
-                "wght",
-                -0.5,
-                [TupleVariation({"wght": (-2.0, -0.4, 0.0)}, [100, 100])],
-            ),
-            (
-                TupleVariation({"wght": (-1.0, -0.5, -0.5)}, [100, 100]),
-                "wght",
-                -0.5,
-                [TupleVariation({"wght": (-1.0, -1.0, -1.0)}, [100, 100])],
-            ),
-        ],
-    )
-    def test_negative_var(self, var, axisTag, newMin, expected):
-        axisRange = instancer.NormalizedAxisRange(newMin, 0)
-        self.check_limit_single_var_axis_range(var, axisTag, axisRange, expected)
-
-
-@pytest.mark.parametrize(
-    "oldRange, newRange, expected",
-    [
-        ((1.0, -1.0), (-1.0, 1.0), None),  # invalid oldRange min > max
-        ((0.6, 1.0), (0, 0.5), None),
-        ((-1.0, -0.6), (-0.5, 0), None),
-        ((0.4, 1.0), (0, 0.5), (0.8, 1.0)),
-        ((-1.0, -0.4), (-0.5, 0), (-1.0, -0.8)),
-        ((0.4, 1.0), (0, 0.4), (1.0, 1.0)),
-        ((-1.0, -0.4), (-0.4, 0), (-1.0, -1.0)),
-        ((-0.5, 0.5), (-0.4, 0.4), (-1.0, 1.0)),
-        ((0, 1.0), (-1.0, 0), (0, 0)),  # or None?
-        ((-1.0, 0), (0, 1.0), (0, 0)),  # or None?
-    ],
-)
-def test_limitFeatureVariationConditionRange(oldRange, newRange, expected):
-    condition = featureVars.buildConditionTable(0, *oldRange)
-
-    result = instancer._limitFeatureVariationConditionRange(
-        condition, instancer.NormalizedAxisRange(*newRange)
-    )
-
-    assert result == expected
-
 
 @pytest.mark.parametrize(
     "limits, expected",
     [
         (["wght=400", "wdth=100"], {"wght": 400, "wdth": 100}),
         (["wght=400:900"], {"wght": (400, 900)}),
-        (["slnt=11.4"], {"slnt": pytest.approx(11.399994)}),
+        (["slnt=11.4"], {"slnt": 11.4}),
         (["ABCD=drop"], {"ABCD": None}),
     ],
 )
@@ -1871,17 +1343,12 @@
     assert normalized == {"wght": (-1.0, 0)}
 
 
-def test_normalizeAxisLimits_unsupported_range(varfont):
-    with pytest.raises(NotImplementedError, match="Unsupported range"):
-        instancer.normalizeAxisLimits(varfont, {"wght": (401, 700)})
-
-
 def test_normalizeAxisLimits_no_avar(varfont):
     del varfont["avar"]
 
-    normalized = instancer.normalizeAxisLimits(varfont, {"wght": (400, 500)})
+    normalized = instancer.normalizeAxisLimits(varfont, {"wght": (500, 600)})
 
-    assert normalized["wght"] == pytest.approx((0, 0.2), 1e-4)
+    assert normalized["wght"] == pytest.approx((0.2, 0.4), 1e-4)
 
 
 def test_normalizeAxisLimits_missing_from_fvar(varfont):
diff --git a/Tests/varLib/interpolatable_test.py b/Tests/varLib/interpolatable_test.py
index a30be71..4900d52 100644
--- a/Tests/varLib/interpolatable_test.py
+++ b/Tests/varLib/interpolatable_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.ttLib import TTFont
 from fontTools.varLib.interpolatable import main as interpolatable_main
 import os
diff --git a/Tests/varLib/interpolate_layout_test.py b/Tests/varLib/interpolate_layout_test.py
index d7134d7..b858a3c 100644
--- a/Tests/varLib/interpolate_layout_test.py
+++ b/Tests/varLib/interpolate_layout_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.ttLib import TTFont
 from fontTools.varLib import build
 from fontTools.varLib.interpolate_layout import interpolate_layout
@@ -747,8 +749,8 @@
         self.check_ttx_dump(instfont, expected_ttx_path, tables, suffix)
 
 
-    def test_varlib_interpolate_layout_GPOS_only_LookupType_7_same_val_ttf(self):
-        """Only GPOS; LookupType 7; same values in all masters.
+    def test_varlib_interpolate_layout_GPOS_only_LookupType_8_same_val_ttf(self):
+        """Only GPOS; LookupType 8; same values in all masters.
         """
         suffix = '.ttf'
         ds_path = self.get_test_input('InterpolateLayout.designspace')
@@ -780,13 +782,13 @@
         instfont = interpolate_layout(ds_path, {'weight': 500}, finder)
 
         tables = ['GPOS']
-        expected_ttx_path = self.get_test_output('InterpolateLayoutGPOS_7_same.ttx')
+        expected_ttx_path = self.get_test_output('InterpolateLayoutGPOS_8_same.ttx')
         self.expect_ttx(instfont, expected_ttx_path, tables)
         self.check_ttx_dump(instfont, expected_ttx_path, tables, suffix)
 
 
-    def test_varlib_interpolate_layout_GPOS_only_LookupType_7_diff_val_ttf(self):
-        """Only GPOS; LookupType 7; different values in each master.
+    def test_varlib_interpolate_layout_GPOS_only_LookupType_8_diff_val_ttf(self):
+        """Only GPOS; LookupType 8; different values in each master.
         """
         suffix = '.ttf'
         ds_path = self.get_test_input('InterpolateLayout.designspace')
@@ -832,7 +834,7 @@
         instfont = interpolate_layout(ds_path, {'weight': 500}, finder)
 
         tables = ['GPOS']
-        expected_ttx_path = self.get_test_output('InterpolateLayoutGPOS_7_diff.ttx')
+        expected_ttx_path = self.get_test_output('InterpolateLayoutGPOS_8_diff.ttx')
         self.expect_ttx(instfont, expected_ttx_path, tables)
         self.check_ttx_dump(instfont, expected_ttx_path, tables, suffix)
 
diff --git a/Tests/varLib/models_test.py b/Tests/varLib/models_test.py
index c220d3d..ae67e0e 100644
--- a/Tests/varLib/models_test.py
+++ b/Tests/varLib/models_test.py
@@ -1,5 +1,7 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.varLib.models import (
-    normalizeLocation, supportScalar, VariationModel, VariationModelError)
+    normalizeLocation, supportScalar, VariationModel)
 import pytest
 
 
@@ -144,7 +146,7 @@
         assert model.deltaWeights == deltaWeights
 
     def test_init_duplicate_locations(self):
-        with pytest.raises(VariationModelError, match="Locations must be unique."):
+        with pytest.raises(ValueError, match="locations must be unique"):
             VariationModel(
                 [
                     {"foo": 0.0, "bar": 0.0},
diff --git a/Tests/varLib/mutator_test.py b/Tests/varLib/mutator_test.py
index abe5d02..d781d59 100644
--- a/Tests/varLib/mutator_test.py
+++ b/Tests/varLib/mutator_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.ttLib import TTFont
 from fontTools.varLib import build
 from fontTools.varLib.mutator import main as mutator
diff --git a/Tests/varLib/varLib_test.py b/Tests/varLib/varLib_test.py
index b8e7183..ec05d56 100644
--- a/Tests/varLib/varLib_test.py
+++ b/Tests/varLib/varLib_test.py
@@ -1,16 +1,14 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
 from fontTools.ttLib import TTFont, newTable
-from fontTools.varLib import build, load_designspace
-from fontTools.varLib.errors import VarLibValidationError
-import fontTools.varLib.errors as varLibErrors
+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,
 )
-from fontTools.feaLib.builder import addOpenTypeFeaturesFromString
 import difflib
-from io import BytesIO
 import os
 import shutil
 import sys
@@ -23,9 +21,6 @@
     """(De)serialize to get final binary layout."""
     buf = BytesIO()
     font.save(buf)
-    # Close the font to release filesystem resources so that on Windows the tearDown
-    # method can successfully remove the temporary directory created during setUp.
-    font.close()
     buf.seek(0)
     return TTFont(buf)
 
@@ -46,15 +41,10 @@
         if self.tempdir:
             shutil.rmtree(self.tempdir)
 
-    def get_test_input(self, test_file_or_folder, copy=False):
-        parent_dir = os.path.dirname(__file__)
-        path = os.path.join(parent_dir, "data", test_file_or_folder)
-        if copy:
-            copied_path = os.path.join(self.tempdir, test_file_or_folder)
-            shutil.copy2(path, copied_path)
-            return copied_path
-        else:
-            return path
+    @staticmethod
+    def get_test_input(test_file_or_folder):
+        path, _ = os.path.split(__file__)
+        return os.path.join(path, "data", test_file_or_folder)
 
     @staticmethod
     def get_test_output(test_file_or_folder):
@@ -118,8 +108,7 @@
         return font, savepath
 
     def _run_varlib_build_test(self, designspace_name, font_name, tables,
-                               expected_ttx_name, save_before_dump=False,
-                               post_process_master=None):
+                               expected_ttx_name, save_before_dump=False):
         suffix = '.ttf'
         ds_path = self.get_test_input(designspace_name + '.designspace')
         ufo_dir = self.get_test_input('master_ufo')
@@ -128,9 +117,7 @@
         self.temp_dir()
         ttx_paths = self.get_file_list(ttx_dir, '.ttx', font_name + '-')
         for path in ttx_paths:
-            font, savepath = self.compile_font(path, suffix, self.tempdir)
-            if post_process_master is not None:
-                post_process_master(font, savepath)
+            self.compile_font(path, suffix, self.tempdir)
 
         finder = lambda s: s.replace(ufo_dir, self.tempdir).replace('.ufo', suffix)
         varfont, model, _ = build(ds_path, finder)
@@ -227,83 +214,6 @@
             save_before_dump=True,
         )
 
-    def test_varlib_build_feature_variations_custom_tag(self):
-        """Designspace file contains <rules> element, used to build
-        GSUB FeatureVariations table.
-        """
-        self._run_varlib_build_test(
-            designspace_name="FeatureVarsCustomTag",
-            font_name="TestFamily",
-            tables=["fvar", "GSUB"],
-            expected_ttx_name="FeatureVarsCustomTag",
-            save_before_dump=True,
-        )
-
-    def test_varlib_build_feature_variations_whole_range(self):
-        """Designspace file contains <rules> element specifying the entire design
-        space, used to build GSUB FeatureVariations table.
-        """
-        self._run_varlib_build_test(
-            designspace_name="FeatureVarsWholeRange",
-            font_name="TestFamily",
-            tables=["fvar", "GSUB"],
-            expected_ttx_name="FeatureVarsWholeRange",
-            save_before_dump=True,
-        )
-
-    def test_varlib_build_feature_variations_whole_range_empty(self):
-        """Designspace file contains <rules> element without a condition, specifying
-        the entire design space, used to build GSUB FeatureVariations table.
-        """
-        self._run_varlib_build_test(
-            designspace_name="FeatureVarsWholeRangeEmpty",
-            font_name="TestFamily",
-            tables=["fvar", "GSUB"],
-            expected_ttx_name="FeatureVarsWholeRange",
-            save_before_dump=True,
-        )
-
-    def test_varlib_build_feature_variations_with_existing_rclt(self):
-        """Designspace file contains <rules> element, used to build GSUB
-        FeatureVariations table. <rules> is specified to do its OT processing
-        "last", so a 'rclt' feature will be used or created. This test covers
-        the case when a 'rclt' already exists in the masters.
-
-        We dynamically add a 'rclt' feature to an existing set of test
-        masters, to avoid adding more test data.
-
-        The multiple languages are done to verify whether multiple existing
-        'rclt' features are updated correctly.
-        """
-        def add_rclt(font, savepath):
-            features = """
-            languagesystem DFLT dflt;
-            languagesystem latn dflt;
-            languagesystem latn NLD;
-
-            feature rclt {
-                script latn;
-                language NLD;
-                lookup A {
-                    sub uni0041 by uni0061;
-                } A;
-                language dflt;
-                lookup B {
-                    sub uni0041 by uni0061;
-                } B;
-            } rclt;
-            """
-            addOpenTypeFeaturesFromString(font, features)
-            font.save(savepath)
-        self._run_varlib_build_test(
-            designspace_name="FeatureVars",
-            font_name="TestFamily",
-            tables=["fvar", "GSUB"],
-            expected_ttx_name="FeatureVars_rclt",
-            save_before_dump=True,
-            post_process_master=add_rclt,
-        )
-
     def test_varlib_gvar_explicit_delta(self):
         """The variable font contains a composite glyph odieresis which does not
         need a gvar entry, because all its deltas are 0, but it must be added
@@ -320,12 +230,11 @@
         )
 
     def test_varlib_nonmarking_CFF2(self):
-        self.temp_dir()
-
-        ds_path = self.get_test_input('TestNonMarkingCFF2.designspace', copy=True)
+        ds_path = self.get_test_input('TestNonMarkingCFF2.designspace')
         ttx_dir = self.get_test_input("master_non_marking_cff2")
         expected_ttx_path = self.get_test_output("TestNonMarkingCFF2.ttx")
 
+        self.temp_dir()
         for path in self.get_file_list(ttx_dir, '.ttx', 'TestNonMarkingCFF2_'):
             self.compile_font(path, ".otf", self.tempdir)
 
@@ -343,35 +252,11 @@
         self.expect_ttx(varfont, expected_ttx_path, tables)
 
     def test_varlib_build_CFF2(self):
-        self.temp_dir()
-
-        ds_path = self.get_test_input('TestCFF2.designspace', copy=True)
+        ds_path = self.get_test_input('TestCFF2.designspace')
         ttx_dir = self.get_test_input("master_cff2")
         expected_ttx_path = self.get_test_output("BuildTestCFF2.ttx")
 
-        for path in self.get_file_list(ttx_dir, '.ttx', 'TestCFF2_'):
-            self.compile_font(path, ".otf", self.tempdir)
-
-        ds = DesignSpaceDocument.fromfile(ds_path)
-        for source in ds.sources:
-            source.path = os.path.join(
-                self.tempdir, os.path.basename(source.filename).replace(".ufo", ".otf")
-            )
-        ds.updatePaths()
-
-        varfont, _, _ = build(ds)
-        varfont = reload_font(varfont)
-
-        tables = ["fvar", "CFF2"]
-        self.expect_ttx(varfont, expected_ttx_path, tables)
-
-    def test_varlib_build_CFF2_from_CFF2(self):
         self.temp_dir()
-
-        ds_path = self.get_test_input('TestCFF2Input.designspace', copy=True)
-        ttx_dir = self.get_test_input("master_cff2_input")
-        expected_ttx_path = self.get_test_output("BuildTestCFF2.ttx")
-
         for path in self.get_file_list(ttx_dir, '.ttx', 'TestCFF2_'):
             self.compile_font(path, ".otf", self.tempdir)
 
@@ -389,12 +274,11 @@
         self.expect_ttx(varfont, expected_ttx_path, tables)
 
     def test_varlib_build_sparse_CFF2(self):
-        self.temp_dir()
-
-        ds_path = self.get_test_input('TestSparseCFF2VF.designspace', copy=True)
+        ds_path = self.get_test_input('TestSparseCFF2VF.designspace')
         ttx_dir = self.get_test_input("master_sparse_cff2")
         expected_ttx_path = self.get_test_output("TestSparseCFF2VF.ttx")
 
+        self.temp_dir()
         for path in self.get_file_list(ttx_dir, '.ttx', 'MasterSet_Kanji-'):
             self.compile_font(path, ".otf", self.tempdir)
 
@@ -412,12 +296,11 @@
         self.expect_ttx(varfont, expected_ttx_path, tables)
 
     def test_varlib_build_vpal(self):
-        self.temp_dir()
-
-        ds_path = self.get_test_input('test_vpal.designspace', copy=True)
+        ds_path = self.get_test_input('test_vpal.designspace')
         ttx_dir = self.get_test_input("master_vpal_test")
         expected_ttx_path = self.get_test_output("test_vpal.ttx")
 
+        self.temp_dir()
         for path in self.get_file_list(ttx_dir, '.ttx', 'master_vpal_test_'):
             self.compile_font(path, ".otf", self.tempdir)
 
@@ -505,12 +388,11 @@
         self.expect_ttx(varfont, expected_ttx_path, tables)
 
     def test_varlib_build_from_ttf_paths(self):
-        self.temp_dir()
-
-        ds_path = self.get_test_input("Build.designspace", copy=True)
+        ds_path = self.get_test_input("Build.designspace")
         ttx_dir = self.get_test_input("master_ttx_interpolatable_ttf")
         expected_ttx_path = self.get_test_output("BuildMain.ttx")
 
+        self.temp_dir()
         for path in self.get_file_list(ttx_dir, '.ttx', 'TestFamily-'):
             self.compile_font(path, ".ttf", self.tempdir)
 
@@ -552,27 +434,6 @@
         tables = [table_tag for table_tag in varfont.keys() if table_tag != "head"]
         self.expect_ttx(varfont, expected_ttx_path, tables)
 
-    def test_varlib_build_lazy_masters(self):
-        # See https://github.com/fonttools/fonttools/issues/1808
-        ds_path = self.get_test_input("SparseMasters.designspace")
-        expected_ttx_path = self.get_test_output("SparseMasters.ttx")
-
-        def _open_font(master_path, master_finder=lambda s: s):
-            font = TTFont()
-            font.importXML(master_path)
-            buf = BytesIO()
-            font.save(buf, reorderTables=False)
-            buf.seek(0)
-            font = TTFont(buf, lazy=True)  # reopen in lazy mode, to reproduce #1808
-            return font
-
-        ds = DesignSpaceDocument.fromfile(ds_path)
-        ds.loadSourceFonts(_open_font)
-        varfont, _, _ = build(ds)
-        varfont = reload_font(varfont)
-        tables = [table_tag for table_tag in varfont.keys() if table_tag != "head"]
-        self.expect_ttx(varfont, expected_ttx_path, tables)
-
     def test_varlib_build_sparse_masters_MVAR(self):
         import fontTools.varLib.mvar
 
@@ -655,13 +516,12 @@
         assert all(tag in mvar_tags for tag in fontTools.varLib.mvar.MVAR_ENTRIES)
 
     def test_varlib_build_VVAR_CFF2(self):
-        self.temp_dir()
-
-        ds_path = self.get_test_input('TestVVAR.designspace', copy=True)
+        ds_path = self.get_test_input('TestVVAR.designspace')
         ttx_dir = self.get_test_input("master_vvar_cff2")
         expected_ttx_name = 'TestVVAR'
         suffix = '.otf'
 
+        self.temp_dir()
         for path in self.get_file_list(ttx_dir, '.ttx', 'TestVVAR'):
             font, savepath = self.compile_font(path, suffix, self.tempdir)
 
@@ -680,41 +540,6 @@
         self.expect_ttx(varfont, expected_ttx_path, tables)
         self.check_ttx_dump(varfont, expected_ttx_path, tables, suffix)
 
-    def test_varlib_build_BASE(self):
-        self.temp_dir()
-
-        ds_path = self.get_test_input('TestBASE.designspace', copy=True)
-        ttx_dir = self.get_test_input("master_base_test")
-        expected_ttx_name = 'TestBASE'
-        suffix = '.otf'
-
-        for path in self.get_file_list(ttx_dir, '.ttx', 'TestBASE'):
-            font, savepath = self.compile_font(path, suffix, self.tempdir)
-
-        ds = DesignSpaceDocument.fromfile(ds_path)
-        for source in ds.sources:
-            source.path = os.path.join(
-                self.tempdir, os.path.basename(source.filename).replace(".ufo", suffix)
-            )
-        ds.updatePaths()
-
-        varfont, _, _ = build(ds)
-        varfont = reload_font(varfont)
-
-        expected_ttx_path = self.get_test_output(expected_ttx_name + '.ttx')
-        tables = ["BASE"]
-        self.expect_ttx(varfont, expected_ttx_path, tables)
-        self.check_ttx_dump(varfont, expected_ttx_path, tables, suffix)
-
-    def test_varlib_build_single_master(self):
-        self._run_varlib_build_test(
-            designspace_name='SingleMaster',
-            font_name='TestFamily',
-            tables=['GDEF', 'HVAR', 'MVAR', 'STAT', 'fvar', 'cvar', 'gvar', 'name'],
-            expected_ttx_name='SingleMaster',
-            save_before_dump=True,
-        )
-
     def test_kerning_merging(self):
         """Test the correct merging of class-based pair kerning.
 
@@ -807,69 +632,6 @@
             ("B", "D"): 40,
         }
 
-    def test_designspace_fill_in_location(self):
-        ds_path = self.get_test_input("VarLibLocationTest.designspace")
-        ds = DesignSpaceDocument.fromfile(ds_path)
-        ds_loaded = load_designspace(ds)
-
-        assert ds_loaded.instances[0].location == {"weight": 0, "width": 50}
-
-    def test_varlib_build_incompatible_features(self):
-        with pytest.raises(
-            varLibErrors.ShouldBeConstant,
-            match = """
-
-Couldn't merge the fonts, because some values were different, but should have
-been the same. This happened while performing the following operation:
-GPOS.table.FeatureList.FeatureCount
-
-The problem is likely to be in Simple Two Axis Bold:
-
-Incompatible features between masters.
-Expected: kern, mark.
-Got: kern.
-"""):
-
-            self._run_varlib_build_test(
-                designspace_name="IncompatibleFeatures",
-                font_name="IncompatibleFeatures",
-                tables=["GPOS"],
-                expected_ttx_name="IncompatibleFeatures",
-                save_before_dump=True,
-            )
-
-    def test_varlib_build_incompatible_lookup_types(self):
-        with pytest.raises(
-            varLibErrors.MismatchedTypes,
-            match = r"MarkBasePos, instead saw PairPos"
-        ):
-            self._run_varlib_build_test(
-                designspace_name="IncompatibleLookupTypes",
-                font_name="IncompatibleLookupTypes",
-                tables=["GPOS"],
-                expected_ttx_name="IncompatibleLookupTypes",
-                save_before_dump=True,
-            )
-
-    def test_varlib_build_incompatible_arrays(self):
-        with pytest.raises(
-            varLibErrors.ShouldBeConstant,
-            match = """
-
-Couldn't merge the fonts, because some values were different, but should have
-been the same. This happened while performing the following operation:
-GPOS.table.ScriptList.ScriptCount
-
-The problem is likely to be in Simple Two Axis Bold:
-Expected to see .ScriptCount==1, instead saw 0"""
-        ):
-            self._run_varlib_build_test(
-                designspace_name="IncompatibleArrays",
-                font_name="IncompatibleArrays",
-                tables=["GPOS"],
-                expected_ttx_name="IncompatibleArrays",
-                save_before_dump=True,
-            )
 
 def test_load_masters_layerName_without_required_font():
     ds = DesignSpaceDocument()
@@ -879,7 +641,7 @@
     ds.addSource(s)
 
     with pytest.raises(
-        VarLibValidationError,
+        AttributeError,
         match="specified a layer name but lacks the required TTFont object",
     ):
         load_masters(ds)
diff --git a/Tests/voltLib/lexer_test.py b/Tests/voltLib/lexer_test.py
index 2145d07..6041cb8 100644
--- a/Tests/voltLib/lexer_test.py
+++ b/Tests/voltLib/lexer_test.py
@@ -1,3 +1,5 @@
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
 from fontTools.voltLib.error import VoltLibError
 from fontTools.voltLib.lexer import Lexer
 import unittest
diff --git a/Tests/voltLib/parser_test.py b/Tests/voltLib/parser_test.py
index 0e0191f..3bfa17c 100644
--- a/Tests/voltLib/parser_test.py
+++ b/Tests/voltLib/parser_test.py
@@ -1,7 +1,9 @@
+from __future__ import print_function, division, absolute_import
+from __future__ import unicode_literals
+from fontTools.misc.py23 import *
 from fontTools.voltLib import ast
 from fontTools.voltLib.error import VoltLibError
 from fontTools.voltLib.parser import Parser
-from io import StringIO
 import unittest
 
 
@@ -37,7 +39,7 @@
                          ("space", 3, [0x0020], "BASE", None))
 
     def test_def_glyph_base_with_unicodevalues(self):
-        [def_glyph] = self.parse_(
+        [def_glyph] = self.parse(
             'DEF_GLYPH "CR" ID 2 UNICODEVALUES "U+0009" '
             'TYPE BASE END_GLYPH'
         ).statements
@@ -55,7 +57,7 @@
                          ("CR", 2, [0x0009, 0x000D], "BASE", None))
 
     def test_def_glyph_base_with_empty_unicodevalues(self):
-        [def_glyph] = self.parse_(
+        [def_glyph] = self.parse(
             'DEF_GLYPH "i.locl" ID 269 UNICODEVALUES "" '
             'TYPE BASE END_GLYPH'
         ).statements
@@ -106,7 +108,7 @@
     def test_def_glyph_case_sensitive(self):
         def_glyphs = self.parse(
             'DEF_GLYPH "A" ID 3 UNICODE 65 TYPE BASE END_GLYPH\n'
-            'DEF_GLYPH "a" ID 4 UNICODE 97 TYPE BASE END_GLYPH'
+            'DEF_GLYPH "a" ID 4 UNICODE 97 TYPE BASE END_GLYPH\n'
         ).statements
         self.assertEqual((def_glyphs[0].name, def_glyphs[0].id,
                           def_glyphs[0].unicode, def_glyphs[0].type,
@@ -120,10 +122,10 @@
     def test_def_group_glyphs(self):
         [def_group] = self.parse(
             'DEF_GROUP "aaccented"\n'
-            ' ENUM GLYPH "aacute" GLYPH "abreve" GLYPH "acircumflex" '
+            'ENUM GLYPH "aacute" GLYPH "abreve" GLYPH "acircumflex" '
             'GLYPH "adieresis" GLYPH "ae" GLYPH "agrave" GLYPH "amacron" '
             'GLYPH "aogonek" GLYPH "aring" GLYPH "atilde" END_ENUM\n'
-            'END_GROUP'
+            'END_GROUP\n'
         ).statements
         self.assertEqual((def_group.name, def_group.enum.glyphSet()),
                          ("aaccented",
@@ -134,14 +136,14 @@
     def test_def_group_groups(self):
         [group1, group2, test_group] = self.parse(
             'DEF_GROUP "Group1"\n'
-            ' ENUM GLYPH "a" GLYPH "b" GLYPH "c" GLYPH "d" END_ENUM\n'
+            'ENUM GLYPH "a" GLYPH "b" GLYPH "c" GLYPH "d" END_ENUM\n'
             'END_GROUP\n'
             'DEF_GROUP "Group2"\n'
-            ' ENUM GLYPH "e" GLYPH "f" GLYPH "g" GLYPH "h" END_ENUM\n'
+            'ENUM GLYPH "e" GLYPH "f" GLYPH "g" GLYPH "h" END_ENUM\n'
             'END_GROUP\n'
             'DEF_GROUP "TestGroup"\n'
-            ' ENUM GROUP "Group1" GROUP "Group2" END_ENUM\n'
-            'END_GROUP'
+            'ENUM GROUP "Group1" GROUP "Group2" END_ENUM\n'
+            'END_GROUP\n'
         ).statements
         groups = [g.group for g in test_group.enum.enum]
         self.assertEqual((test_group.name, groups),
@@ -151,20 +153,20 @@
         [group1, test_group1, test_group2, test_group3, group2] = \
         self.parse(
             'DEF_GROUP "Group1"\n'
-            ' ENUM GLYPH "a" GLYPH "b" GLYPH "c" GLYPH "d" END_ENUM\n'
+            'ENUM GLYPH "a" GLYPH "b" GLYPH "c" GLYPH "d" END_ENUM\n'
             'END_GROUP\n'
             'DEF_GROUP "TestGroup1"\n'
-            ' ENUM GROUP "Group1" GROUP "Group2" END_ENUM\n'
+            'ENUM GROUP "Group1" GROUP "Group2" END_ENUM\n'
             'END_GROUP\n'
             'DEF_GROUP "TestGroup2"\n'
-            ' ENUM GROUP "Group2" END_ENUM\n'
+            'ENUM GROUP "Group2" END_ENUM\n'
             'END_GROUP\n'
             'DEF_GROUP "TestGroup3"\n'
-            ' ENUM GROUP "Group2" GROUP "Group1" END_ENUM\n'
+            'ENUM GROUP "Group2" GROUP "Group1" END_ENUM\n'
             'END_GROUP\n'
             'DEF_GROUP "Group2"\n'
-            ' ENUM GLYPH "e" GLYPH "f" GLYPH "g" GLYPH "h" END_ENUM\n'
-            'END_GROUP'
+            'ENUM GLYPH "e" GLYPH "f" GLYPH "g" GLYPH "h" END_ENUM\n'
+            'END_GROUP\n'
         ).statements
         groups = [g.group for g in test_group1.enum.enum]
         self.assertEqual(
@@ -195,12 +197,12 @@
     def test_def_group_glyphs_and_group(self):
         [def_group1, def_group2] = self.parse(
             'DEF_GROUP "aaccented"\n'
-            ' ENUM GLYPH "aacute" GLYPH "abreve" GLYPH "acircumflex" '
+            'ENUM GLYPH "aacute" GLYPH "abreve" GLYPH "acircumflex" '
             'GLYPH "adieresis" GLYPH "ae" GLYPH "agrave" GLYPH "amacron" '
             'GLYPH "aogonek" GLYPH "aring" GLYPH "atilde" END_ENUM\n'
             'END_GROUP\n'
             'DEF_GROUP "KERN_lc_a_2ND"\n'
-            ' ENUM GLYPH "a" GROUP "aaccented" END_ENUM\n'
+            'ENUM GLYPH "a" GROUP "aaccented" END_ENUM\n'
             'END_GROUP'
         ).statements
         items = def_group2.enum.enum
@@ -219,7 +221,7 @@
             'DEF_GLYPH "ccedilla" ID 210 UNICODE 231 TYPE BASE END_GLYPH\n'
             'DEF_GLYPH "cdotaccent" ID 210 UNICODE 267 TYPE BASE END_GLYPH\n'
             'DEF_GROUP "KERN_lc_a_2ND"\n'
-            ' ENUM RANGE "a" TO "atilde" GLYPH "b" RANGE "c" TO "cdotaccent" '
+            'ENUM RANGE "a" TO "atilde" GLYPH "b" RANGE "c" TO "cdotaccent" '
             'END_ENUM\n'
             'END_GROUP'
         ).statements[-1]
@@ -238,7 +240,7 @@
                         'END_GROUP\n'
                         'DEF_GROUP "dupe"\n'
                         'ENUM GLYPH "x" END_ENUM\n'
-                        'END_GROUP'
+                        'END_GROUP\n'
         )
 
     def test_group_duplicate_case_insensitive(self):
@@ -251,12 +253,12 @@
                         'END_GROUP\n'
                         'DEF_GROUP "Dupe"\n'
                         'ENUM GLYPH "x" END_ENUM\n'
-                        'END_GROUP'
+                        'END_GROUP\n'
         )
 
     def test_script_without_langsys(self):
         [script] = self.parse(
-            'DEF_SCRIPT NAME "Latin" TAG "latn"\n\n'
+            'DEF_SCRIPT NAME "Latin" TAG "latn"\n'
             'END_SCRIPT'
         ).statements
         self.assertEqual((script.name, script.tag, script.langs),
@@ -264,10 +266,10 @@
 
     def test_langsys_normal(self):
         [def_script] = self.parse(
-            'DEF_SCRIPT NAME "Latin" TAG "latn"\n\n'
-            'DEF_LANGSYS NAME "Romanian" TAG "ROM "\n\n'
+            'DEF_SCRIPT NAME "Latin" TAG "latn"\n'
+            'DEF_LANGSYS NAME "Romanian" TAG "ROM "\n'
             'END_LANGSYS\n'
-            'DEF_LANGSYS NAME "Moldavian" TAG "MOL "\n\n'
+            'DEF_LANGSYS NAME "Moldavian" TAG "MOL "\n'
             'END_LANGSYS\n'
             'END_SCRIPT'
         ).statements
@@ -285,8 +287,8 @@
 
     def test_langsys_no_script_name(self):
         [langsys] = self.parse(
-            'DEF_SCRIPT TAG "latn"\n\n'
-            'DEF_LANGSYS NAME "Default" TAG "dflt"\n\n'
+            'DEF_SCRIPT TAG "latn"\n'
+            'DEF_LANGSYS NAME "Default" TAG "dflt"\n'
             'END_LANGSYS\n'
             'END_SCRIPT'
         ).statements
@@ -303,8 +305,8 @@
                 VoltLibError,
                 r'.*Expected "TAG"'):
             [langsys] = self.parse(
-                'DEF_SCRIPT NAME "Latin"\n\n'
-                'DEF_LANGSYS NAME "Default" TAG "dflt"\n\n'
+                'DEF_SCRIPT NAME "Latin"\n'
+                'DEF_LANGSYS NAME "Default" TAG "dflt"\n'
                 'END_LANGSYS\n'
                 'END_SCRIPT'
             ).statements
@@ -315,12 +317,12 @@
                 'Script "DFLT" already defined, '
                 'script tags are case insensitive'):
             [langsys1, langsys2] = self.parse(
-                'DEF_SCRIPT NAME "Default" TAG "DFLT"\n\n'
-                'DEF_LANGSYS NAME "Default" TAG "dflt"\n\n'
+                'DEF_SCRIPT NAME "Default" TAG "DFLT"\n'
+                'DEF_LANGSYS NAME "Default" TAG "dflt"\n'
                 'END_LANGSYS\n'
                 'END_SCRIPT\n'
-                'DEF_SCRIPT TAG "DFLT"\n\n'
-                'DEF_LANGSYS NAME "Default" TAG "dflt"\n\n'
+                'DEF_SCRIPT TAG "DFLT"\n'
+                'DEF_LANGSYS NAME "Default" TAG "dflt"\n'
                 'END_LANGSYS\n'
                 'END_SCRIPT'
             ).statements
@@ -336,21 +338,21 @@
                 'END_LANGSYS\n'
                 'DEF_LANGSYS NAME "Default" TAG "dflt"\n'
                 'END_LANGSYS\n'
-                'END_SCRIPT'
+                'END_SCRIPT\n'
             ).statements
 
     def test_langsys_lang_in_separate_scripts(self):
         [langsys1, langsys2] = self.parse(
-            'DEF_SCRIPT NAME "Default" TAG "DFLT"\n\n'
-            'DEF_LANGSYS NAME "Default" TAG "dflt"\n\n'
+            'DEF_SCRIPT NAME "Default" TAG "DFLT"\n'
+            'DEF_LANGSYS NAME "Default" TAG "dflt"\n'
             'END_LANGSYS\n'
-            'DEF_LANGSYS NAME "Default" TAG "ROM "\n\n'
+            'DEF_LANGSYS NAME "Default" TAG "ROM "\n'
             'END_LANGSYS\n'
             'END_SCRIPT\n'
-            'DEF_SCRIPT NAME "Latin" TAG "latn"\n\n'
-            'DEF_LANGSYS NAME "Default" TAG "dflt"\n\n'
+            'DEF_SCRIPT NAME "Latin" TAG "latn"\n'
+            'DEF_LANGSYS NAME "Default" TAG "dflt"\n'
             'END_LANGSYS\n'
-            'DEF_LANGSYS NAME "Default" TAG "ROM "\n\n'
+            'DEF_LANGSYS NAME "Default" TAG "ROM "\n'
             'END_LANGSYS\n'
             'END_SCRIPT'
         ).statements
@@ -361,8 +363,8 @@
 
     def test_langsys_no_lang_name(self):
         [langsys] = self.parse(
-            'DEF_SCRIPT NAME "Latin" TAG "latn"\n\n'
-            'DEF_LANGSYS TAG "dflt"\n\n'
+            'DEF_SCRIPT NAME "Latin" TAG "latn"\n'
+            'DEF_LANGSYS TAG "dflt"\n'
             'END_LANGSYS\n'
             'END_SCRIPT'
         ).statements
@@ -379,18 +381,18 @@
                 VoltLibError,
                 r'.*Expected "TAG"'):
             [langsys] = self.parse(
-                'DEF_SCRIPT NAME "Latin" TAG "latn"\n\n'
-                'DEF_LANGSYS NAME "Default"\n\n'
+                'DEF_SCRIPT NAME "Latin" TAG "latn"\n'
+                'DEF_LANGSYS NAME "Default"\n'
                 'END_LANGSYS\n'
                 'END_SCRIPT'
             ).statements
 
     def test_feature(self):
         [def_script] = self.parse(
-            'DEF_SCRIPT NAME "Latin" TAG "latn"\n\n'
-            'DEF_LANGSYS NAME "Romanian" TAG "ROM "\n\n'
+            'DEF_SCRIPT NAME "Latin" TAG "latn"\n'
+            'DEF_LANGSYS NAME "Romanian" TAG "ROM "\n'
             'DEF_FEATURE NAME "Fractions" TAG "frac"\n'
-            ' LOOKUP "fraclookup"\n'
+            'LOOKUP "fraclookup"\n'
             'END_FEATURE\n'
             'END_LANGSYS\n'
             'END_SCRIPT'
@@ -402,10 +404,10 @@
                           "frac",
                           ["fraclookup"]))
         [def_script] = self.parse(
-            'DEF_SCRIPT NAME "Latin" TAG "latn"\n\n'
-            'DEF_LANGSYS NAME "Romanian" TAG "ROM "\n\n'
+            'DEF_SCRIPT NAME "Latin" TAG "latn"\n'
+            'DEF_LANGSYS NAME "Romanian" TAG "ROM "\n'
             'DEF_FEATURE NAME "Kerning" TAG "kern"\n'
-            ' LOOKUP "kern1" LOOKUP "kern2"\n'
+            'LOOKUP "kern1" LOOKUP "kern2"\n'
             'END_FEATURE\n'
             'END_LANGSYS\n'
             'END_SCRIPT'
@@ -473,21 +475,6 @@
                 'END_SUBSTITUTION\n'
             ).statements
 
-    def test_lookup_comments(self):
-        [lookup] = self.parse(
-            'DEF_LOOKUP "test" PROCESS_BASE PROCESS_MARKS ALL DIRECTION LTR\n'
-            'COMMENTS "Hello\\nWorld"\n'
-            'IN_CONTEXT\n'
-            'END_CONTEXT\n'
-            'AS_SUBSTITUTION\n'
-            'SUB GLYPH "a"\n'
-            'WITH GLYPH "b"\n'
-            'END_SUB\n'
-            'END_SUBSTITUTION'
-        ).statements
-        self.assertEqual(lookup.name, "test")
-        self.assertEqual(lookup.comments, "Hello\nWorld")
-
     def test_substitution_empty(self):
         with self.assertRaisesRegex(
                 VoltLibError,
@@ -572,13 +559,12 @@
 
     def test_substitution_single_in_context(self):
         [group, lookup] = self.parse(
-            'DEF_GROUP "Denominators"\n'
-            ' ENUM GLYPH "one.dnom" GLYPH "two.dnom" END_ENUM\n'
-            'END_GROUP\n'
+            'DEF_GROUP "Denominators" ENUM GLYPH "one.dnom" GLYPH "two.dnom" '
+            'END_ENUM END_GROUP\n'
             'DEF_LOOKUP "fracdnom" PROCESS_BASE PROCESS_MARKS ALL '
             'DIRECTION LTR\n'
-            'IN_CONTEXT\n'
-            ' LEFT ENUM GROUP "Denominators" GLYPH "fraction" END_ENUM\n'
+            'IN_CONTEXT LEFT ENUM GROUP "Denominators" GLYPH "fraction" '
+            'END_ENUM\n'
             'END_CONTEXT\n'
             'AS_SUBSTITUTION\n'
             'SUB GLYPH "one"\n'
@@ -604,18 +590,17 @@
 
     def test_substitution_single_in_contexts(self):
         [group, lookup] = self.parse(
-            'DEF_GROUP "Hebrew"\n'
-            ' ENUM GLYPH "uni05D0" GLYPH "uni05D1" END_ENUM\n'
-            'END_GROUP\n'
+            'DEF_GROUP "Hebrew" ENUM GLYPH "uni05D0" GLYPH "uni05D1" '
+            'END_ENUM END_GROUP\n'
             'DEF_LOOKUP "HebrewCurrency" PROCESS_BASE PROCESS_MARKS ALL '
             'DIRECTION LTR\n'
             'IN_CONTEXT\n'
-            ' RIGHT GROUP "Hebrew"\n'
-            ' RIGHT GLYPH "one.Hebr"\n'
+            'RIGHT GROUP "Hebrew"\n'
+            'RIGHT GLYPH "one.Hebr"\n'
             'END_CONTEXT\n'
             'IN_CONTEXT\n'
-            ' LEFT GROUP "Hebrew"\n'
-            ' LEFT GLYPH "one.Hebr"\n'
+            'LEFT GROUP "Hebrew"\n'
+            'LEFT GLYPH "one.Hebr"\n'
             'END_CONTEXT\n'
             'AS_SUBSTITUTION\n'
             'SUB GLYPH "dollar"\n'
@@ -646,9 +631,8 @@
 
     def test_substitution_skip_base(self):
         [group, lookup] = self.parse(
-            'DEF_GROUP "SomeMarks"\n'
-            ' ENUM GLYPH "marka" GLYPH "markb" END_ENUM\n'
-            'END_GROUP\n'
+            'DEF_GROUP "SomeMarks" ENUM GLYPH "marka" GLYPH "markb" '
+            'END_ENUM END_GROUP\n'
             'DEF_LOOKUP "SomeSub" SKIP_BASE PROCESS_MARKS ALL '
             'DIRECTION LTR\n'
             'IN_CONTEXT\n'
@@ -665,9 +649,8 @@
 
     def test_substitution_process_base(self):
         [group, lookup] = self.parse(
-            'DEF_GROUP "SomeMarks"\n'
-            ' ENUM GLYPH "marka" GLYPH "markb" END_ENUM\n'
-            'END_GROUP\n'
+            'DEF_GROUP "SomeMarks" ENUM GLYPH "marka" GLYPH "markb" '
+            'END_ENUM END_GROUP\n'
             'DEF_LOOKUP "SomeSub" PROCESS_BASE PROCESS_MARKS ALL '
             'DIRECTION LTR\n'
             'IN_CONTEXT\n'
@@ -682,74 +665,12 @@
             (lookup.name, lookup.process_base),
             ("SomeSub", True))
 
-    def test_substitution_process_marks(self):
-        [group, lookup] = self.parse(
-            'DEF_GROUP "SomeMarks"\n'
-            ' ENUM GLYPH "marka" GLYPH "markb" END_ENUM\n'
-            'END_GROUP\n'
-            'DEF_LOOKUP "SomeSub" PROCESS_BASE PROCESS_MARKS "SomeMarks"\n'
-            'IN_CONTEXT\n'
-            'END_CONTEXT\n'
-            'AS_SUBSTITUTION\n'
-            'SUB GLYPH "A"\n'
-            'WITH GLYPH "A.c2sc"\n'
-            'END_SUB\n'
-            'END_SUBSTITUTION'
-        ).statements
-        self.assertEqual(
-            (lookup.name, lookup.process_marks),
-            ("SomeSub", 'SomeMarks'))
-
-    def test_substitution_process_marks_all(self):
-        [lookup] = self.parse(
-            'DEF_LOOKUP "SomeSub" PROCESS_BASE PROCESS_MARKS ALL\n'
-            'IN_CONTEXT\n'
-            'END_CONTEXT\n'
-            'AS_SUBSTITUTION\n'
-            'SUB GLYPH "A"\n'
-            'WITH GLYPH "A.c2sc"\n'
-            'END_SUB\n'
-            'END_SUBSTITUTION'
-        ).statements
-        self.assertEqual(
-            (lookup.name, lookup.process_marks),
-            ("SomeSub", True))
-
-    def test_substitution_process_marks_none(self):
-        [lookup] = self.parse_(
-            'DEF_LOOKUP "SomeSub" PROCESS_BASE PROCESS_MARKS "NONE"\n'
-            'IN_CONTEXT\n'
-            'END_CONTEXT\n'
-            'AS_SUBSTITUTION\n'
-            'SUB GLYPH "A"\n'
-            'WITH GLYPH "A.c2sc"\n'
-            'END_SUB\n'
-            'END_SUBSTITUTION'
-        ).statements
-        self.assertEqual(
-            (lookup.name, lookup.process_marks),
-            ("SomeSub", False))
-
-    def test_substitution_process_marks_bad(self):
-        with self.assertRaisesRegex(
-                VoltLibError,
-                'Expected ALL, NONE, MARK_GLYPH_SET or an ID'):
-            self.parse(
-                'DEF_GROUP "SomeMarks" ENUM GLYPH "marka" GLYPH "markb" '
-                'END_ENUM END_GROUP\n'
-                'DEF_LOOKUP "SomeSub" PROCESS_BASE PROCESS_MARKS SomeMarks '
-                'AS_SUBSTITUTION\n'
-                'SUB GLYPH "A" WITH GLYPH "A.c2sc"\n'
-                'END_SUB\n'
-                'END_SUBSTITUTION'
-            )
-
     def test_substitution_skip_marks(self):
         [group, lookup] = self.parse(
-            'DEF_GROUP "SomeMarks"\n'
-            ' ENUM GLYPH "marka" GLYPH "markb" END_ENUM\n'
-            'END_GROUP\n'
-            'DEF_LOOKUP "SomeSub" PROCESS_BASE SKIP_MARKS DIRECTION LTR\n'
+            'DEF_GROUP "SomeMarks" ENUM GLYPH "marka" GLYPH "markb" '
+            'END_ENUM END_GROUP\n'
+            'DEF_LOOKUP "SomeSub" PROCESS_BASE SKIP_MARKS '
+            'DIRECTION LTR\n'
             'IN_CONTEXT\n'
             'END_CONTEXT\n'
             'AS_SUBSTITUTION\n'
@@ -764,13 +685,11 @@
 
     def test_substitution_mark_attachment(self):
         [group, lookup] = self.parse(
-            'DEF_GROUP "SomeMarks"\n'
-            ' ENUM GLYPH "acutecmb" GLYPH "gravecmb" END_ENUM\n'
-            'END_GROUP\n'
+            'DEF_GROUP "SomeMarks" ENUM GLYPH "acutecmb" GLYPH "gravecmb" '
+            'END_ENUM END_GROUP\n'
             'DEF_LOOKUP "SomeSub" PROCESS_BASE '
-            'PROCESS_MARKS "SomeMarks" DIRECTION RTL\n'
-            'IN_CONTEXT\n'
-            'END_CONTEXT\n'
+            'PROCESS_MARKS "SomeMarks" \n'
+            'DIRECTION RTL\n'
             'AS_SUBSTITUTION\n'
             'SUB GLYPH "A"\n'
             'WITH GLYPH "A.c2sc"\n'
@@ -783,13 +702,11 @@
 
     def test_substitution_mark_glyph_set(self):
         [group, lookup] = self.parse(
-            'DEF_GROUP "SomeMarks"\n'
-            ' ENUM GLYPH "acutecmb" GLYPH "gravecmb" END_ENUM\n'
-            'END_GROUP\n'
+            'DEF_GROUP "SomeMarks" ENUM GLYPH "acutecmb" GLYPH "gravecmb" '
+            'END_ENUM END_GROUP\n'
             'DEF_LOOKUP "SomeSub" PROCESS_BASE '
-            'PROCESS_MARKS MARK_GLYPH_SET "SomeMarks" DIRECTION RTL\n'
-            'IN_CONTEXT\n'
-            'END_CONTEXT\n'
+            'PROCESS_MARKS MARK_GLYPH_SET "SomeMarks" \n'
+            'DIRECTION RTL\n'
             'AS_SUBSTITUTION\n'
             'SUB GLYPH "A"\n'
             'WITH GLYPH "A.c2sc"\n'
@@ -802,13 +719,11 @@
 
     def test_substitution_process_all_marks(self):
         [group, lookup] = self.parse(
-            'DEF_GROUP "SomeMarks"\n'
-            ' ENUM GLYPH "acutecmb" GLYPH "gravecmb" END_ENUM\n'
-            'END_GROUP\n'
-            'DEF_LOOKUP "SomeSub" PROCESS_BASE PROCESS_MARKS ALL '
+            'DEF_GROUP "SomeMarks" ENUM GLYPH "acutecmb" GLYPH "gravecmb" '
+            'END_ENUM END_GROUP\n'
+            'DEF_LOOKUP "SomeSub" PROCESS_BASE '
+            'PROCESS_MARKS ALL \n'
             'DIRECTION RTL\n'
-            'IN_CONTEXT\n'
-            'END_CONTEXT\n'
             'AS_SUBSTITUTION\n'
             'SUB GLYPH "A"\n'
             'WITH GLYPH "A.c2sc"\n'
@@ -825,7 +740,7 @@
             'DEF_LOOKUP "Lookup" PROCESS_BASE PROCESS_MARKS ALL '
             'DIRECTION LTR\n'
             'IN_CONTEXT\n'
-            ' RIGHT ENUM GLYPH "a" GLYPH "b" END_ENUM\n'
+            'RIGHT ENUM GLYPH "a" GLYPH "b" END_ENUM\n'
             'END_CONTEXT\n'
             'AS_SUBSTITUTION\n'
             'SUB GLYPH "a"\n'
@@ -841,15 +756,15 @@
     def test_substitution_reversal(self):
         lookup = self.parse(
             'DEF_GROUP "DFLT_Num_standardFigures"\n'
-            ' ENUM GLYPH "zero" GLYPH "one" GLYPH "two" END_ENUM\n'
+            'ENUM GLYPH "zero" GLYPH "one" GLYPH "two" END_ENUM\n'
             'END_GROUP\n'
             'DEF_GROUP "DFLT_Num_numerators"\n'
-            ' ENUM GLYPH "zero.numr" GLYPH "one.numr" GLYPH "two.numr" END_ENUM\n'
+            'ENUM GLYPH "zero.numr" GLYPH "one.numr" GLYPH "two.numr" END_ENUM\n'
             'END_GROUP\n'
             'DEF_LOOKUP "RevLookup" PROCESS_BASE PROCESS_MARKS ALL '
             'DIRECTION LTR REVERSAL\n'
             'IN_CONTEXT\n'
-            ' RIGHT ENUM GLYPH "a" GLYPH "b" END_ENUM\n'
+            'RIGHT ENUM GLYPH "a" GLYPH "b" END_ENUM\n'
             'END_CONTEXT\n'
             'AS_SUBSTITUTION\n'
             'SUB GROUP "DFLT_Num_standardFigures"\n'
@@ -905,7 +820,7 @@
             'DEF_LOOKUP "numr" PROCESS_BASE PROCESS_MARKS ALL '
             'DIRECTION LTR REVERSAL\n'
             'IN_CONTEXT\n'
-            ' RIGHT ENUM '
+            'RIGHT ENUM '
             'GLYPH "fraction" '
             'RANGE "zero.numr" TO "nine.numr" '
             'END_ENUM\n'
@@ -946,7 +861,7 @@
                 'DEF_LOOKUP "empty_position" PROCESS_BASE PROCESS_MARKS ALL '
                 'DIRECTION LTR\n'
                 'EXCEPT_CONTEXT\n'
-                ' LEFT GLYPH "glyph"\n'
+                'LEFT GLYPH "glyph"\n'
                 'END_CONTEXT\n'
                 'AS_POSITION\n'
                 'END_POSITION'
@@ -965,13 +880,13 @@
             'END_ATTACH\n'
             'END_POSITION\n'
             'DEF_ANCHOR "MARK_top" ON 120 GLYPH acutecomb COMPONENT 1 '
-            'AT  POS DX 0 DY 450 END_POS END_ANCHOR\n'
+            'AT POS DX 0 DY 450 END_POS END_ANCHOR\n'
             'DEF_ANCHOR "MARK_top" ON 121 GLYPH gravecomb COMPONENT 1 '
-            'AT  POS DX 0 DY 450 END_POS END_ANCHOR\n'
+            'AT POS DX 0 DY 450 END_POS END_ANCHOR\n'
             'DEF_ANCHOR "top" ON 31 GLYPH a COMPONENT 1 '
-            'AT  POS DX 210 DY 450 END_POS END_ANCHOR\n'
+            'AT POS DX 210 DY 450 END_POS END_ANCHOR\n'
             'DEF_ANCHOR "top" ON 35 GLYPH e COMPONENT 1 '
-            'AT  POS DX 215 DY 450 END_POS END_ANCHOR'
+            'AT POS DX 215 DY 450 END_POS END_ANCHOR\n'
         ).statements
         pos = lookup.pos
         coverage = [g.glyph for g in pos.coverage]
@@ -1011,9 +926,9 @@
             'IN_CONTEXT\n'
             'END_CONTEXT\n'
             'AS_POSITION\n'
-            'ATTACH_CURSIVE\nEXIT  GLYPH "a" GLYPH "b"\nENTER  GLYPH "c"\n'
+            'ATTACH_CURSIVE EXIT GLYPH "a" GLYPH "b" ENTER GLYPH "c"\n'
             'END_ATTACH\n'
-            'END_POSITION'
+            'END_POSITION\n'
         ).statements
         exit = [[g.glyph for g in v] for v in lookup.pos.coverages_exit]
         enter = [[g.glyph for g in v] for v in lookup.pos.coverages_enter]
@@ -1030,12 +945,12 @@
             'END_CONTEXT\n'
             'AS_POSITION\n'
             'ADJUST_PAIR\n'
-            ' FIRST  GLYPH "A"\n'
-            ' SECOND  GLYPH "V"\n'
+            ' FIRST GLYPH "A"\n'
+            ' SECOND GLYPH "V"\n'
             ' 1 2 BY POS ADV -30 END_POS POS END_POS\n'
-            ' 2 1 BY POS ADV -30 END_POS POS END_POS\n\n'
+            ' 2 1 BY POS ADV -30 END_POS POS END_POS\n'
             'END_ADJUST\n'
-            'END_POSITION'
+            'END_POSITION\n'
         ).statements
         coverages_1 = [[g.glyph for g in v] for v in lookup.pos.coverages_1]
         coverages_2 = [[g.glyph for g in v] for v in lookup.pos.coverages_2]
@@ -1054,15 +969,15 @@
             'DEF_LOOKUP "TestLookup" PROCESS_BASE PROCESS_MARKS ALL '
             'DIRECTION LTR\n'
             'IN_CONTEXT\n'
-            # ' LEFT GLYPH "leftGlyph"\n'
-            # ' RIGHT GLYPH "rightGlyph"\n'
+            # 'LEFT GLYPH "leftGlyph"\n'
+            # 'RIGHT GLYPH "rightGlyph"\n'
             'END_CONTEXT\n'
             'AS_POSITION\n'
             'ADJUST_SINGLE'
-            ' GLYPH "glyph1" BY POS ADV 0 DX 123 END_POS'
+            ' GLYPH "glyph1" BY POS ADV 0 DX 123 END_POS\n'
             ' GLYPH "glyph2" BY POS ADV 0 DX 456 END_POS\n'
             'END_ADJUST\n'
-            'END_POSITION'
+            'END_POSITION\n'
         ).statements
         pos = lookup.pos
         adjust = [[[g.glyph for g in a], b] for (a, b) in pos.adjust_single]
@@ -1076,11 +991,11 @@
     def test_def_anchor(self):
         [anchor1, anchor2, anchor3] = self.parse(
             'DEF_ANCHOR "top" ON 120 GLYPH a '
-            'COMPONENT 1 AT  POS DX 250 DY 450 END_POS END_ANCHOR\n'
+            'COMPONENT 1 AT POS DX 250 DY 450 END_POS END_ANCHOR\n'
             'DEF_ANCHOR "MARK_top" ON 120 GLYPH acutecomb '
-            'COMPONENT 1 AT  POS DX 0 DY 450 END_POS END_ANCHOR\n'
+            'COMPONENT 1 AT POS DX 0 DY 450 END_POS END_ANCHOR\n'
             'DEF_ANCHOR "bottom" ON 120 GLYPH a '
-            'COMPONENT 1 AT  POS DX 250 DY 0 END_POS END_ANCHOR'
+            'COMPONENT 1 AT POS DX 250 DY 0 END_POS END_ANCHOR\n'
         ).statements
         self.assertEqual(
             (anchor1.name, anchor1.gid, anchor1.glyph_name, anchor1.component,
@@ -1104,9 +1019,9 @@
     def test_def_anchor_multi_component(self):
         [anchor1, anchor2] = self.parse(
             'DEF_ANCHOR "top" ON 120 GLYPH a '
-            'COMPONENT 1 AT  POS DX 250 DY 450 END_POS END_ANCHOR\n'
+            'COMPONENT 1 AT POS DX 250 DY 450 END_POS END_ANCHOR\n'
             'DEF_ANCHOR "top" ON 120 GLYPH a '
-            'COMPONENT 2 AT  POS DX 250 DY 450 END_POS END_ANCHOR'
+            'COMPONENT 2 AT POS DX 250 DY 450 END_POS END_ANCHOR\n'
         ).statements
         self.assertEqual(
             (anchor1.name, anchor1.gid, anchor1.glyph_name, anchor1.component),
@@ -1124,15 +1039,15 @@
             'anchor names are case insensitive',
             self.parse,
             'DEF_ANCHOR "dupe" ON 120 GLYPH a '
-            'COMPONENT 1 AT  POS DX 250 DY 450 END_POS END_ANCHOR\n'
+            'COMPONENT 1 AT POS DX 250 DY 450 END_POS END_ANCHOR\n'
             'DEF_ANCHOR "dupe" ON 120 GLYPH a '
-            'COMPONENT 1 AT  POS DX 250 DY 450 END_POS END_ANCHOR'
+            'COMPONENT 1 AT POS DX 250 DY 450 END_POS END_ANCHOR\n'
         )
 
     def test_def_anchor_locked(self):
         [anchor] = self.parse(
             'DEF_ANCHOR "top" ON 120 GLYPH a '
-            'COMPONENT 1 LOCKED AT  POS DX 250 DY 450 END_POS END_ANCHOR'
+            'COMPONENT 1 LOCKED AT POS DX 250 DY 450 END_POS END_ANCHOR\n'
         ).statements
         self.assertEqual(
             (anchor.name, anchor.gid, anchor.glyph_name, anchor.component,
@@ -1144,7 +1059,7 @@
     def test_anchor_adjust_device(self):
         [anchor] = self.parse(
             'DEF_ANCHOR "MARK_top" ON 123 GLYPH diacglyph '
-            'COMPONENT 1 AT  POS DX 0 DY 456 ADJUST_BY 12 AT 34 '
+            'COMPONENT 1 AT POS DX 0 DY 456 ADJUST_BY 12 AT 34 '
             'ADJUST_BY 56 AT 78 END_POS END_ANCHOR'
         ).statements
         self.assertEqual(
@@ -1156,7 +1071,7 @@
         [grid_ppem, pres_ppem, ppos_ppem] = self.parse(
             'GRID_PPEM 20\n'
             'PRESENTATION_PPEM 72\n'
-            'PPOSITIONING_PPEM 144'
+            'PPOSITIONING_PPEM 144\n'
         ).statements
         self.assertEqual(
             ((grid_ppem.name, grid_ppem.value),
@@ -1169,7 +1084,7 @@
     def test_compiler_flags(self):
         [setting1, setting2] = self.parse(
             'COMPILER_USEEXTENSIONLOOKUPS\n'
-            'COMPILER_USEPAIRPOSFORMAT2'
+            'COMPILER_USEPAIRPOSFORMAT2\n'
         ).statements
         self.assertEqual(
             ((setting1.name, setting1.value),
@@ -1182,7 +1097,7 @@
         [cmap_format1, cmap_format2, cmap_format3] = self.parse(
             'CMAP_FORMAT 0 3 4\n'
             'CMAP_FORMAT 1 0 6\n'
-            'CMAP_FORMAT 3 1 4'
+            'CMAP_FORMAT 3 1 4\n'
         ).statements
         self.assertEqual(
             ((cmap_format1.name, cmap_format1.value),
@@ -1193,42 +1108,16 @@
              ("CMAP_FORMAT", (3, 1, 4)))
         )
 
-    def test_do_not_touch_cmap(self):
-        [option1, option2, option3, option4] = self.parse(
-            'DO_NOT_TOUCH_CMAP\n'
-            'CMAP_FORMAT 0 3 4\n'
-            'CMAP_FORMAT 1 0 6\n'
-            'CMAP_FORMAT 3 1 4'
-        ).statements
-        self.assertEqual(
-            ((option1.name, option1.value),
-             (option2.name, option2.value),
-             (option3.name, option3.value),
-             (option4.name, option4.value)),
-            (("DO_NOT_TOUCH_CMAP", True),
-             ("CMAP_FORMAT", (0, 3, 4)),
-             ("CMAP_FORMAT", (1, 0, 6)),
-             ("CMAP_FORMAT", (3, 1, 4)))
-        )
-
     def test_stop_at_end(self):
-        doc = self.parse_(
+        [def_glyph] = self.parse(
             'DEF_GLYPH ".notdef" ID 0 TYPE BASE END_GLYPH END\0\0\0\0'
-        )
-        [def_glyph] = doc.statements
+        ).statements
         self.assertEqual((def_glyph.name, def_glyph.id, def_glyph.unicode,
                           def_glyph.type, def_glyph.components),
                          (".notdef", 0, None, "BASE", None))
-        self.assertEqual(str(doc),
-            '\nDEF_GLYPH ".notdef" ID 0 TYPE BASE END_GLYPH END\n')
-
-    def parse_(self, text):
-        return Parser(StringIO(text)).parse()
 
     def parse(self, text):
-        doc = self.parse_(text)
-        self.assertEqual('\n'.join(str(s) for s in doc.statements), text)
-        return Parser(StringIO(text)).parse()
+        return Parser(UnicodeIO(text)).parse()
 
 if __name__ == "__main__":
     import sys
diff --git a/dev-requirements.txt b/dev-requirements.txt
index 73eae68..a34deb2 100644
--- a/dev-requirements.txt
+++ b/dev-requirements.txt
@@ -2,4 +2,3 @@
 tox>=2.5
 bump2version>=0.5.6
 sphinx>=1.5.5
-mypy>=0.782
diff --git a/fonttools b/fonttools
index 90bc63f..92b390e 100755
--- a/fonttools
+++ b/fonttools
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function, division, absolute_import
 import sys
 import os.path
 
diff --git a/mypy.ini b/mypy.ini
deleted file mode 100644
index 7e37b03..0000000
--- a/mypy.ini
+++ /dev/null
@@ -1,21 +0,0 @@
-[mypy]
-python_version = 3.6
-files = Lib/fontTools/misc/plistlib
-follow_imports = silent
-ignore_missing_imports = True
-warn_redundant_casts = True
-warn_unused_configs = True
-warn_unused_ignores = True
-
-[mypy-fontTools.misc.plistlib]
-check_untyped_defs = True
-disallow_any_generics = True
-disallow_incomplete_defs = True
-disallow_subclassing_any = True
-disallow_untyped_decorators = True
-disallow_untyped_calls = False
-disallow_untyped_defs = True
-no_implicit_optional = True
-no_implicit_reexport = True
-strict_equality = True
-warn_return_any = True
diff --git a/requirements.txt b/requirements.txt
index 680ffbb..ee665b6 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,13 +1,15 @@
 # we use the official Brotli module on CPython and the CFFI-based
 # extension 'brotlipy' on PyPy
-brotli==1.0.9; platform_python_implementation != "PyPy"
+brotli==1.0.7; platform_python_implementation != "PyPy"
 brotlipy==0.7.0; platform_python_implementation == "PyPy"
-unicodedata2==13.0.0.post2; python_version < '3.9' and platform_python_implementation != "PyPy"
-scipy==1.5.4; platform_python_implementation != "PyPy"
-munkres==1.1.4; platform_python_implementation == "PyPy"
+unicodedata2==12.0.0; python_version < '3.8' and platform_python_implementation != "PyPy"
+scipy==1.2.1; platform_python_implementation != "PyPy" and python_version < '3.5'  # pyup: ignore
+scipy==1.3.0; platform_python_implementation != "PyPy" and python_version >= '3.5'
+munkres==1.0.12; platform_python_implementation == "PyPy" and python_version < '3.5'  # pyup: ignore
+munkres==1.1.2; platform_python_implementation == "PyPy" and python_version >= '3.5'
 zopfli==0.1.6
-fs==2.4.11
-skia-pathops==0.5.1.post1; platform_python_implementation != "PyPy"
-# this is only required to run Tests/cu2qu/{ufo,cli}_test.py
-ufoLib2==0.6.2
-pyobjc==6.2.2; sys_platform == "darwin"
+fs==2.4.9
+# lxml 4.4.0 breaks OrderedDict attributes in python < 3.6 so we pin to previous version
+# https://bugs.launchpad.net/lxml/+bug/1838252
+lxml==4.3.5; python_version < '3.6'  # pyup: ignore
+lxml==4.4.0; python_version >= '3.6'
diff --git a/run-tests.sh b/run-tests.sh
new file mode 100755
index 0000000..f10c1b0
--- /dev/null
+++ b/run-tests.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+# exit if any subcommand return non-zero status
+set -e
+
+# Choose python version
+if test "x$1" = x-3; then
+	PYTHON=py3
+	shift
+elif test "x$1" = x-2; then
+	PYTHON=py2
+	shift
+fi
+test "x$PYTHON" = x && PYTHON=py
+
+# Find tests
+FILTERS=
+for arg in "$@"; do
+	test "x$FILTERS" != x && FILTERS="$FILTERS or "
+	FILTERS="$FILTERS$arg"
+done
+
+# Run tests
+if [ -z "$FILTERS" ]; then
+	tox --develop -e $PYTHON
+else
+	tox --develop -e $PYTHON -- -k "$FILTERS"
+fi
diff --git a/setup.cfg b/setup.cfg
index 230175c..e8f4864 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 4.22.0
+current_version = 3.44.0
 commit = True
 tag = False
 tag_name = {new_version}
@@ -24,6 +24,9 @@
 search = version="{current_version}"
 replace = version="{new_version}"
 
+[wheel]
+universal = 1
+
 [sdist]
 formats = zip
 
@@ -34,7 +37,6 @@
 minversion = 3.0
 testpaths = 
 	Tests
-	fontTools
 python_files = 
 	*_test.py
 python_classes = 
@@ -48,7 +50,14 @@
 	ALLOW_UNICODE
 	ELLIPSIS
 filterwarnings = 
+	ignore:tostring:DeprecationWarning
+	ignore:fromstring:DeprecationWarning
 	ignore:readPlist:DeprecationWarning:plistlib_test
 	ignore:writePlist:DeprecationWarning:plistlib_test
 	ignore:some_function:DeprecationWarning:fontTools.ufoLib.utils
 	ignore::DeprecationWarning:fontTools.varLib.designspace
+
+[egg_info]
+tag_build = 
+tag_date = 0
+
diff --git a/setup.py b/setup.py
index d1c5a4f..c259cfd 100755
--- a/setup.py
+++ b/setup.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python3
+#! /usr/bin/env python
 
 from __future__ import print_function
 import io
@@ -6,8 +6,7 @@
 import os
 from os.path import isfile, join as pjoin
 from glob import glob
-from setuptools import setup, find_packages, Command, Extension
-from setuptools.command.build_ext import build_ext as _build_ext
+from setuptools import setup, find_packages, Command
 from distutils import log
 from distutils.util import convert_path
 import subprocess as sp
@@ -24,66 +23,33 @@
 
 py_compile.compile = doraise_py_compile
 
-setup_requires = []
-
-if {'bdist_wheel'}.intersection(sys.argv):
-	setup_requires.append('wheel')
-
-if {'release'}.intersection(sys.argv):
-	setup_requires.append('bump2version')
-
-try:
-	__import__("cython")
-except ImportError:
-	has_cython = False
-else:
-	has_cython = True
-
-env_with_cython = os.environ.get("FONTTOOLS_WITH_CYTHON")
-with_cython = (
-	True if env_with_cython in {"1", "true", "yes"}
-	else False if env_with_cython in {"0", "false", "no"}
-	else None
-)
-# --with-cython/--without-cython options override environment variables
-opt_with_cython = {'--with-cython'}.intersection(sys.argv)
-opt_without_cython = {'--without-cython'}.intersection(sys.argv)
-if opt_with_cython and opt_without_cython:
-	sys.exit(
-		"error: the options '--with-cython' and '--without-cython' are "
-		"mutually exclusive"
-	)
-elif opt_with_cython:
-	sys.argv.remove("--with-cython")
-	with_cython = True
-elif opt_without_cython:
-	sys.argv.remove("--without-cython")
-	with_cython = False
-
-if with_cython and not has_cython:
-	setup_requires.append("cython")
-
-ext_modules = []
-if with_cython is True or (with_cython is None and has_cython):
-	ext_modules.append(
-		Extension("fontTools.cu2qu.cu2qu", ["Lib/fontTools/cu2qu/cu2qu.py"]),
-	)
+needs_wheel = {'bdist_wheel'}.intersection(sys.argv)
+wheel = ['wheel'] if needs_wheel else []
+needs_bumpversion = {'release'}.intersection(sys.argv)
+bumpversion = ['bump2version'] if needs_bumpversion else []
 
 extras_require = {
 	# for fontTools.ufoLib: to read/write UFO fonts
 	"ufo": [
 		"fs >= 2.2.0, < 3",
+		"enum34 >= 1.1.6; python_version < '3.4'",
 	],
 	# for fontTools.misc.etree and fontTools.misc.plistlib: use lxml to
 	# read/write XML files (faster/safer than built-in ElementTree)
 	"lxml": [
 		"lxml >= 4.0, < 5",
+		"singledispatch >= 3.4.0.3; python_version < '3.4'",
+		# typing >= 3.6.4 is required when using ABC collections with the
+		# singledispatch backport, see:
+		# https://github.com/fonttools/fonttools/issues/1423
+		# https://github.com/python/typing/issues/484
+		"typing >= 3.6.4; python_version < '3.4'",
 	],
 	# for fontTools.sfnt and fontTools.woff2: to compress/uncompress
 	# WOFF 1.0 and WOFF 2.0 webfonts.
 	"woff": [
-		"brotli >= 1.0.1; platform_python_implementation == 'CPython'",
-		"brotlicffi >= 0.8.0; platform_python_implementation != 'CPython'",
+		"brotli >= 1.0.1; platform_python_implementation != 'PyPy'",
+		"brotlipy >= 0.7.0; platform_python_implementation == 'PyPy'",
 		"zopfli >= 0.1.4",
 	],
 	# for fontTools.unicode and fontTools.unicodedata: to use the latest version
@@ -91,10 +57,10 @@
 	# which varies between python versions and may be outdated.
 	"unicode": [
 		# the unicodedata2 extension module doesn't work on PyPy.
-		# Python 3.9 already has Unicode 13.0, so the backport is not needed.
+		# Python 3.8 already has Unicode 12, so the backport is not needed.
 		(
-			"unicodedata2 >= 13.0.0; "
-			"python_version < '3.9' and platform_python_implementation != 'PyPy'"
+			"unicodedata2 >= 12.0.0; "
+			"python_version < '3.8' and platform_python_implementation != 'PyPy'"
 		),
 	],
 	# for graphite type tables in ttLib/tables (Silf, Glat, Gloc)
@@ -122,10 +88,6 @@
 	"type1": [
 		"xattr; sys_platform == 'darwin'",
 	],
-	# for fontTools.ttLib.removeOverlaps, to remove overlaps in TTF fonts
-	"pathops": [
-		"skia-pathops >= 0.5.0",
-	],
 }
 # use a special 'all' key as shorthand to includes all the extra dependencies
 extras_require["all"] = sum(extras_require.values(), [])
@@ -299,7 +261,7 @@
 		""" Run bumpversion.main() with the specified arguments, and return the
 		new computed version string (cf. 'bumpversion --help' for more info)
 		"""
-		import bumpversion.cli
+		import bumpversion
 
 		args = (
 			(['--verbose'] if self.verbose > 1 else []) +
@@ -312,7 +274,7 @@
 		log.debug("$ bumpversion %s" % " ".join(a.replace(" ", "\\ ") for a in args))
 
 		with capture_logger("bumpversion.list") as out:
-			bumpversion.cli.main(args)
+			bumpversion.main(args)
 
 		last_line = out.getvalue().splitlines()[-1]
 		new_version = last_line.replace("new_version=", "")
@@ -388,60 +350,9 @@
 	return data_files
 
 
-class cython_build_ext(_build_ext):
-	"""Compile *.pyx source files to *.c using cythonize if Cython is
-	installed and there is a working C compiler, else fall back to pure python dist.
-	"""
-
-	def finalize_options(self):
-		from Cython.Build import cythonize
-
-		# optionally enable line tracing for test coverage support
-		linetrace = os.environ.get("CYTHON_TRACE") == "1"
-
-		self.distribution.ext_modules[:] = cythonize(
-			self.distribution.ext_modules,
-			force=linetrace or self.force,
-			annotate=os.environ.get("CYTHON_ANNOTATE") == "1",
-			quiet=not self.verbose,
-			compiler_directives={
-				"linetrace": linetrace,
-				"language_level": 3,
-				"embedsignature": True,
-			},
-		)
-
-		_build_ext.finalize_options(self)
-
-	def build_extensions(self):
-		try:
-			_build_ext.build_extensions(self)
-		except Exception as e:
-			if with_cython:
-				raise
-			from distutils.errors import DistutilsModuleError
-
-			# optional compilation failed: we delete 'ext_modules' and make sure
-			# the generated wheel is 'pure'
-			del self.distribution.ext_modules[:]
-			try:
-				bdist_wheel = self.get_finalized_command("bdist_wheel")
-			except DistutilsModuleError:
-				# 'bdist_wheel' command not available as wheel is not installed
-				pass
-			else:
-				bdist_wheel.root_is_pure = True
-			log.error('error: building extensions failed: %s' % e)
-
-cmdclass = {"release": release}
-
-if ext_modules:
-    cmdclass["build_ext"] = cython_build_ext
-
-
-setup_params = dict(
+setup(
 	name="fonttools",
-	version="4.22.0",
+	version="3.44.0",
 	description="Tools to manipulate font files",
 	author="Just van Rossum",
 	author_email="just@letterror.com",
@@ -450,14 +361,12 @@
 	url="http://github.com/fonttools/fonttools",
 	license="MIT",
 	platforms=["Any"],
-	python_requires=">=3.6",
 	long_description=long_description,
 	package_dir={'': 'Lib'},
 	packages=find_packages("Lib"),
 	include_package_data=True,
 	data_files=find_data_files(),
-	ext_modules=ext_modules,
-	setup_requires=setup_requires,
+	setup_requires=wheel + bumpversion,
 	extras_require=extras_require,
 	entry_points={
 		'console_scripts': [
@@ -467,10 +376,8 @@
 			"pyftmerge = fontTools.merge:main",
 		]
 	},
-	cmdclass=cmdclass,
+	cmdclass={
+		"release": release,
+	},
 	**classifiers
 )
-
-
-if __name__ == "__main__":
-	setup(**setup_params)
diff --git a/tox.ini b/tox.ini
index bcbeeed..6a01501 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,22 +1,13 @@
 [tox]
 minversion = 3.0
-envlist = mypy, py3{6,7,8,9}-cov, htmlcov
-skip_missing_interpreters=true
+envlist = py{27,37}-cov, htmlcov
 
 [testenv]
-setenv =
-    cy: FONTTOOLS_WITH_CYTHON=1
-# use 'download = true' to have tox install the latest pip inside the virtualenv.
-# We need this to be able to install skia-pathops on Linux, which uses a
-# relatively recent 'manylinux2014' platform tag.
-# https://github.com/tox-dev/tox/issues/791#issuecomment-518713438
-download = true
 deps =
     cov: coverage>=4.3
     pytest
     pytest-randomly
     -rrequirements.txt
-    !nolxml: lxml==4.6.1
 extras =
     ufo
     woff
@@ -24,10 +15,8 @@
     interpolatable
     !nolxml: lxml
 commands =
-    cy: python -c "from fontTools.cu2qu.cu2qu import COMPILED; assert COMPILED"
-    !cy: python -c "from fontTools.cu2qu.cu2qu import COMPILED; assert not COMPILED"
     # test with or without coverage, passing extra positonal args to pytest
-    cov: coverage run --parallel-mode -m pytest {posargs}
+    cov: coverage run --parallel-mode -m pytest {posargs:Tests fontTools}
     !cov: pytest {posargs:Tests fontTools}
 
 [testenv:htmlcov]
@@ -38,13 +27,6 @@
     coverage combine
     coverage html
 
-[testenv:mypy]
-deps =
-    -r dev-requirements.txt
-skip_install = true
-commands =
-    mypy
-
 [testenv:codecov]
 passenv = *
 deps =