├── test-requirements.txt
├── requirements.txt
├── .codecov.yml
├── Lib
└── cu2qu
│ ├── __main__.py
│ ├── __init__.py
│ ├── errors.py
│ └── cli.py
├── .pyup.yml
├── tests
├── data
│ ├── RobotoSubset-Regular.ufo
│ │ ├── glyphs
│ │ │ ├── space.glif
│ │ │ ├── I_.glif
│ │ │ ├── l.glif
│ │ │ ├── L_.glif
│ │ │ ├── T_.glif
│ │ │ ├── Y_.glif
│ │ │ ├── N_.glif
│ │ │ ├── v.glif
│ │ │ ├── V_.glif
│ │ │ ├── x.glif
│ │ │ ├── X_.glif
│ │ │ ├── F_.glif
│ │ │ ├── H_.glif
│ │ │ ├── J_.glif
│ │ │ ├── i.glif
│ │ │ ├── z.glif
│ │ │ ├── K_.glif
│ │ │ ├── k.glif
│ │ │ ├── A_.glif
│ │ │ ├── Z_.glif
│ │ │ ├── U_.glif
│ │ │ ├── r.glif
│ │ │ ├── P_.glif
│ │ │ ├── E_.glif
│ │ │ ├── M_.glif
│ │ │ ├── t.glif
│ │ │ ├── f.glif
│ │ │ ├── h.glif
│ │ │ ├── u.glif
│ │ │ ├── n.glif
│ │ │ ├── y.glif
│ │ │ ├── D_.glif
│ │ │ ├── w.glif
│ │ │ ├── W_.glif
│ │ │ ├── c.glif
│ │ │ ├── o.glif
│ │ │ ├── C_.glif
│ │ │ ├── R_.glif
│ │ │ ├── O_.glif
│ │ │ ├── j.glif
│ │ │ ├── e.glif
│ │ │ ├── G_.glif
│ │ │ ├── Q_.glif
│ │ │ ├── d.glif
│ │ │ ├── b.glif
│ │ │ ├── q.glif
│ │ │ ├── p.glif
│ │ │ ├── S_.glif
│ │ │ ├── s.glif
│ │ │ ├── m.glif
│ │ │ ├── B_.glif
│ │ │ ├── a.glif
│ │ │ ├── g.glif
│ │ │ └── contents.plist
│ │ ├── layercontents.plist
│ │ ├── metainfo.plist
│ │ ├── lib.plist
│ │ └── fontinfo.plist
│ ├── cubic
│ │ ├── A_acute.glif
│ │ ├── acute.glif
│ │ ├── contents.plist
│ │ ├── A_.glif
│ │ ├── E_acute.glif
│ │ └── a.glif
│ ├── RobotoSubset-Bold.ufo
│ │ ├── layercontents.plist
│ │ ├── metainfo.plist
│ │ ├── glyphs
│ │ │ ├── I_.glif
│ │ │ ├── l.glif
│ │ │ ├── L_.glif
│ │ │ ├── T_.glif
│ │ │ ├── Y_.glif
│ │ │ ├── N_.glif
│ │ │ ├── V_.glif
│ │ │ ├── v.glif
│ │ │ ├── X_.glif
│ │ │ ├── x.glif
│ │ │ ├── H_.glif
│ │ │ ├── F_.glif
│ │ │ ├── J_.glif
│ │ │ ├── z.glif
│ │ │ ├── K_.glif
│ │ │ ├── k.glif
│ │ │ ├── A_.glif
│ │ │ ├── Z_.glif
│ │ │ ├── space.glif
│ │ │ ├── i.glif
│ │ │ ├── U_.glif
│ │ │ ├── r.glif
│ │ │ ├── P_.glif
│ │ │ ├── E_.glif
│ │ │ ├── M_.glif
│ │ │ ├── t.glif
│ │ │ ├── f.glif
│ │ │ ├── h.glif
│ │ │ ├── n.glif
│ │ │ ├── u.glif
│ │ │ ├── y.glif
│ │ │ ├── D_.glif
│ │ │ ├── w.glif
│ │ │ ├── W_.glif
│ │ │ ├── c.glif
│ │ │ ├── C_.glif
│ │ │ ├── o.glif
│ │ │ ├── R_.glif
│ │ │ ├── O_.glif
│ │ │ ├── j.glif
│ │ │ ├── G_.glif
│ │ │ ├── e.glif
│ │ │ ├── Q_.glif
│ │ │ ├── d.glif
│ │ │ ├── b.glif
│ │ │ ├── q.glif
│ │ │ ├── p.glif
│ │ │ ├── s.glif
│ │ │ ├── S_.glif
│ │ │ ├── m.glif
│ │ │ ├── B_.glif
│ │ │ ├── a.glif
│ │ │ ├── g.glif
│ │ │ └── contents.plist
│ │ ├── lib.plist
│ │ └── fontinfo.plist
│ └── quadratic
│ │ ├── acute.glif
│ │ ├── contents.plist
│ │ ├── E_acute.glif
│ │ ├── A_.glif
│ │ └── a.glif
├── __init__.py
├── cli_test.py
└── cu2qu_test.py
├── README.rst
├── pyproject.toml
├── MANIFEST.in
├── setup.cfg
├── .gitignore
├── tools
├── update_cython_shadow.py
├── ufo_benchmark.py
└── benchmark.py
├── .coveragerc
├── CONTRIBUTING.md
├── tox.ini
├── .github
└── workflows
│ └── ci.yml
└── setup.py
/test-requirements.txt:
--------------------------------------------------------------------------------
1 | coverage
2 | pytest
3 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | fonttools[ufo]==3.32.0
2 | defcon==0.6.0
3 |
--------------------------------------------------------------------------------
/.codecov.yml:
--------------------------------------------------------------------------------
1 | comment: false
2 | coverage:
3 | status:
4 | project: off
5 | patch: off
6 |
--------------------------------------------------------------------------------
/Lib/cu2qu/__main__.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from cu2qu.cli import main
3 |
4 |
5 | if __name__ == "__main__":
6 | sys.exit(main())
7 |
--------------------------------------------------------------------------------
/.pyup.yml:
--------------------------------------------------------------------------------
1 | # controls the frequency of updates (undocumented beta feature)
2 | schedule: every week
3 |
4 | # do not pin dependencies unless they have explicit version specifiers
5 | pin: False
6 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/space.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/tests/data/cubic/A_acute.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | cu2qu
2 | =====
3 |
4 | This library provides functions which take in UFO objects (Defcon Fonts
5 | or Robofab RFonts) and converts any cubic curves to quadratic. The most
6 | useful function is probably ``fonts_to_quadratic``.
7 |
8 | This library is now maintained as part of https://github.com/fonttools/fonttools
9 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = [
3 | "setuptools",
4 | "wheel",
5 | "setuptools_scm",
6 | "cython",
7 | ]
8 | build-backend = "setuptools.build_meta"
9 |
10 | [tool.cibuildwheel]
11 | test-requires = "pytest"
12 | before-test = "pip install -r requirements.txt"
13 | test-command = "pytest {project}/tests"
14 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/layercontents.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | public.default
7 | glyphs
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/layercontents.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | public.default
7 | glyphs
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/metainfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | creator
6 | org.robofab.ufoLib
7 | formatVersion
8 | 3
9 |
10 |
11 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/metainfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | creator
6 | org.robofab.ufoLib
7 | formatVersion
8 | 3
9 |
10 |
11 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include LICENSE
2 | include README.rst
3 | include CONTRIBUTING.md
4 | include requirements.txt
5 | include test-requirements.txt
6 | include tox.ini
7 | include .coveragerc
8 | recursive-include tests *.py
9 | recursive-include tests/data *.json
10 | recursive-include tests/data */*.glif
11 | recursive-include tests/data */*.plist */*/*.glif */*/*.plist
12 | recursive-include tools *.py
13 |
--------------------------------------------------------------------------------
/tests/data/cubic/acute.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/tests/data/quadratic/acute.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/I_.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/l.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/I_.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/l.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/tests/data/quadratic/contents.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | A
6 | A_.glif
7 | Eacute
8 | E_acute.glif
9 | a
10 | a.glif
11 | acute
12 | acute.glif
13 |
14 |
15 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [bdist_wheel]
2 | universal = 1
3 |
4 | [sdist]
5 | formats = zip
6 |
7 | [aliases]
8 | test = pytest
9 |
10 | [metadata]
11 | license_file = LICENSE
12 |
13 | [tool:pytest]
14 | minversion = 3.0
15 | testpaths =
16 | tests
17 | python_files =
18 | *_test.py
19 | python_classes =
20 | *Test
21 | addopts =
22 | -s
23 | -v
24 | -r a
25 | --doctest-modules
26 | --doctest-ignore-import-errors
27 | filterwarnings:
28 | ignore:.*bytes:DeprecationWarning:fs.base
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled and optimized files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 | *.so
6 |
7 | # cython generated C/HTML files
8 | Lib/cu2qu/*.c
9 | Lib/cu2qu/*.html
10 |
11 | # Packaging
12 | *.egg-info
13 | *.eggs
14 | build
15 | dist
16 |
17 | # Unit test and coverage files
18 | .cache
19 | .coverage
20 | .coverage.*
21 | .tox
22 | htmlcov
23 | .pytest_cache/
24 |
25 | # OS X Finder
26 | .DS_Store
27 |
28 | # auto-generated version file
29 | Lib/cu2qu/_version.py
30 |
--------------------------------------------------------------------------------
/tests/data/cubic/contents.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | A
6 | A_.glif
7 | Aacute
8 | A_acute.glif
9 | Eacute
10 | E_acute.glif
11 | a
12 | a.glif
13 | acute
14 | acute.glif
15 |
16 |
17 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | import os
2 | from fontTools.ufoLib.glifLib import GlyphSet
3 | import pkg_resources
4 |
5 | DATADIR = os.path.join(os.path.dirname(__file__), 'data')
6 | CUBIC_GLYPHS = GlyphSet(os.path.join(DATADIR, 'cubic'))
7 | QUAD_GLYPHS = GlyphSet(os.path.join(DATADIR, 'quadratic'))
8 |
9 | import unittest
10 | # Python 3 renamed 'assertRaisesRegexp' to 'assertRaisesRegex', and fires
11 | # deprecation warnings if a program uses the old name.
12 | if not hasattr(unittest.TestCase, 'assertRaisesRegex'):
13 | unittest.TestCase.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp
14 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/L_.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/T_.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/L_.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/T_.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/Y_.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/Y_.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/N_.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/N_.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/V_.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/v.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/v.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/V_.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/X_.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/x.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/x.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/X_.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/H_.glif:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/F_.glif:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/F_.glif:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/H_.glif:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/J_.glif:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/J_.glif:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/tools/update_cython_shadow.py:
--------------------------------------------------------------------------------
1 | """ Update the embedded Lib/cu2qu/cython.py module with the contents of
2 | the latest cython repository.
3 |
4 | Usage:
5 | $ python tools/update_cython_shadow.py 0.28.5
6 | """
7 |
8 | import requests
9 | import sys
10 |
11 |
12 | header = b'''\
13 | """ This module is copied verbatim from the "Cython.Shadow" module:
14 | https://github.com/cython/cython/blob/master/Cython/Shadow.py
15 |
16 | Cython is licensed under the Apache 2.0 Software License.
17 | """
18 | '''
19 |
20 | try:
21 | version = sys.argv[1]
22 | except IndexError:
23 | version = "master"
24 |
25 | CYTHON_SHADOW_URL = (
26 | "https://raw.githubusercontent.com/cython/cython/%s/Cython/Shadow.py"
27 | ) % version
28 |
29 | r = requests.get(CYTHON_SHADOW_URL, allow_redirects=True)
30 | with open("Lib/cu2qu/cython.py", "wb") as f:
31 | f.write(header)
32 | f.write(r.content)
33 |
--------------------------------------------------------------------------------
/Lib/cu2qu/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015 Google Inc. All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | from __future__ import print_function, division, absolute_import
17 |
18 | try:
19 | from ._version import version as __version__
20 | except ImportError:
21 | __version__ = "0.0.0+unknown"
22 |
23 | from .cu2qu import *
24 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/i.glif:
--------------------------------------------------------------------------------
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 |
28 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/z.glif:
--------------------------------------------------------------------------------
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 |
28 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/K_.glif:
--------------------------------------------------------------------------------
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 |
28 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/k.glif:
--------------------------------------------------------------------------------
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 |
28 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/z.glif:
--------------------------------------------------------------------------------
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 |
28 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/A_.glif:
--------------------------------------------------------------------------------
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 |
28 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/Z_.glif:
--------------------------------------------------------------------------------
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 |
28 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/K_.glif:
--------------------------------------------------------------------------------
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 |
28 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/k.glif:
--------------------------------------------------------------------------------
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 |
28 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/A_.glif:
--------------------------------------------------------------------------------
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 |
28 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/Z_.glif:
--------------------------------------------------------------------------------
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 |
28 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/space.glif:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | com.typemytype.robofont.guides
10 |
11 |
12 | angle
13 | 0
14 | isGlobal
15 |
16 | magnetic
17 | 5
18 | x
19 | 0
20 | y
21 | 901
22 |
23 |
24 | angle
25 | 0
26 | isGlobal
27 |
28 | magnetic
29 | 5
30 | x
31 | 0
32 | y
33 | 555
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/i.glif:
--------------------------------------------------------------------------------
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 |
28 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/U_.glif:
--------------------------------------------------------------------------------
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 |
28 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/U_.glif:
--------------------------------------------------------------------------------
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 |
28 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/r.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/r.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/P_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/P_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/E_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/E_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/.coveragerc:
--------------------------------------------------------------------------------
1 | [run]
2 | # measure 'branch' coverage in addition to 'statement' coverage
3 | # See: http://coverage.readthedocs.org/en/coverage-4.0.3/branch.html#branch
4 | branch = True
5 |
6 | # list of directories or packages to measure
7 | source = cu2qu
8 |
9 | # this is simply vendored, no need to include in coverage report
10 | omit =
11 | */cu2qu/cython.py
12 |
13 | # these are treated as equivalent when combining data
14 | [paths]
15 | source =
16 | Lib/cu2qu
17 | .tox/*/lib/python*/site-packages/cu2qu
18 | .tox/pypy*/site-packages/cu2qu
19 |
20 | [report]
21 | # Regexes for lines to exclude from consideration
22 | exclude_lines =
23 | # keywords to use in inline comments to skip coverage
24 | pragma: no cover
25 |
26 | # don't complain if tests don't hit defensive assertion code
27 | raise AssertionError
28 | raise NotImplementedError
29 |
30 | # don't complain if non-runnable code isn't run
31 | if 0:
32 | if __name__ == .__main__.:
33 |
34 | # ignore source code that can’t be found
35 | ignore_errors = True
36 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/M_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/M_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/t.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/t.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/f.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/f.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/h.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/h.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/n.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/u.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/u.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/n.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/y.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/y.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/D_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/D_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/w.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/W_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/w.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/W_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/c.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/c.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/tools/ufo_benchmark.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Google Inc. All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | from __future__ import print_function, division, absolute_import
17 |
18 | import os
19 | import random
20 |
21 | from benchmark import run_benchmark
22 |
23 | MAX_ERR_EM = 0.002
24 | DATADIR = os.path.join(
25 | os.path.dirname(__file__), os.path.pardir, 'tests', 'data')
26 |
27 |
28 | def setup_fonts_to_quadratic_defcon():
29 | from defcon import Font
30 | return [[Font(os.path.join(DATADIR, 'RobotoSubset-Regular.ufo'))],
31 | MAX_ERR_EM]
32 |
33 |
34 | def main():
35 | run_benchmark(
36 | 'ufo_benchmark', 'cu2qu.ufo', 'fonts_to_quadratic',
37 | setup_suffix='defcon', repeat=10)
38 |
39 |
40 | if __name__ == '__main__':
41 | random.seed(1)
42 | main()
43 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/C_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/o.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/o.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/C_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/R_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/R_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/O_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/j.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/O_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/j.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Want to contribute? Great! First, read this page (including the small print
2 | at the end).
3 |
4 | ### Before you contribute
5 | Before we can use your code, you must sign the
6 | [Google Individual Contributor License
7 | Agreement](https://cla.developers.google.com/about/google-individual)
8 | (CLA), which you can do online. The CLA is necessary mainly because you own the
9 | copyright to your changes, even after your contribution becomes part of our
10 | codebase, so we need your permission to use and distribute your code. We also
11 | need to be sure of various other things—for instance that you'll tell us if you
12 | know that your code infringes on other people's patents. You don't have to sign
13 | the CLA until after you've submitted your code for review and a member has
14 | approved it, but you must do it before we can put your code into our codebase.
15 | Before you start working on a larger contribution, you should get in touch with
16 | us first through the issue tracker with your idea so that we can help out and
17 | possibly guide you. Coordinating up front makes it much easier to avoid
18 | frustration later on.
19 |
20 | ### Code reviews
21 | All submissions, including submissions by project members, require review. We
22 | use Github pull requests for this purpose.
23 |
24 | ### The small print
25 | Contributions made by corporations are covered by a different agreement than
26 | the one above, the
27 | [Software Grant and Corporate Contributor License
28 | Agreement](https://cla.developers.google.com/about/google-corporate).
29 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/e.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/G_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/G_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/e.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/Q_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/Q_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/d.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/b.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/q.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/p.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/d.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/b.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/q.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/p.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/lib.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | public.glyphOrder
6 |
7 | space
8 | A
9 | B
10 | C
11 | D
12 | E
13 | F
14 | G
15 | H
16 | I
17 | J
18 | K
19 | L
20 | M
21 | N
22 | O
23 | P
24 | Q
25 | R
26 | S
27 | T
28 | U
29 | V
30 | W
31 | X
32 | Y
33 | Z
34 | a
35 | b
36 | c
37 | d
38 | e
39 | f
40 | g
41 | h
42 | i
43 | j
44 | k
45 | l
46 | m
47 | n
48 | o
49 | p
50 | q
51 | r
52 | s
53 | t
54 | u
55 | v
56 | w
57 | x
58 | y
59 | z
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/lib.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | public.glyphOrder
6 |
7 | space
8 | A
9 | B
10 | C
11 | D
12 | E
13 | F
14 | G
15 | H
16 | I
17 | J
18 | K
19 | L
20 | M
21 | N
22 | O
23 | P
24 | Q
25 | R
26 | S
27 | T
28 | U
29 | V
30 | W
31 | X
32 | Y
33 | Z
34 | a
35 | b
36 | c
37 | d
38 | e
39 | f
40 | g
41 | h
42 | i
43 | j
44 | k
45 | l
46 | m
47 | n
48 | o
49 | p
50 | q
51 | r
52 | s
53 | t
54 | u
55 | v
56 | w
57 | x
58 | y
59 | z
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/s.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/S_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/s.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/S_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/m.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/m.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/B_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/B_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/tests/data/cubic/A_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/a.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/a.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/tests/data/cubic/E_acute.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/g.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/g.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/Lib/cu2qu/errors.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function, absolute_import, division
2 |
3 |
4 | class Error(Exception):
5 | """Base Cu2Qu exception class for all other errors."""
6 |
7 |
8 | class ApproxNotFoundError(Error):
9 | def __init__(self, curve):
10 | message = "no approximation found: %s" % curve
11 | super(Error, self).__init__(message)
12 | self.curve = curve
13 |
14 |
15 | class UnequalZipLengthsError(Error):
16 | pass
17 |
18 |
19 | class IncompatibleGlyphsError(Error):
20 | def __init__(self, glyphs):
21 | assert len(glyphs) > 1
22 | self.glyphs = glyphs
23 | names = set(repr(g.name) for g in glyphs)
24 | if len(names) > 1:
25 | self.combined_name = "{%s}" % ", ".join(sorted(names))
26 | else:
27 | self.combined_name = names.pop()
28 |
29 | def __repr__(self):
30 | return "<%s %s>" % (type(self).__name__, self.combined_name)
31 |
32 |
33 | class IncompatibleSegmentNumberError(IncompatibleGlyphsError):
34 | def __str__(self):
35 | return "Glyphs named %s have different number of segments" % (
36 | self.combined_name
37 | )
38 |
39 |
40 | class IncompatibleSegmentTypesError(IncompatibleGlyphsError):
41 | def __init__(self, glyphs, segments):
42 | IncompatibleGlyphsError.__init__(self, glyphs)
43 | self.segments = segments
44 |
45 | def __str__(self):
46 | lines = []
47 | ndigits = len(str(max(self.segments)))
48 | for i, tags in sorted(self.segments.items()):
49 | lines.append(
50 | "%s: (%s)" % (str(i).rjust(ndigits), ", ".join(repr(t) for t in tags))
51 | )
52 | return "Glyphs named %s have incompatible segment types:\n %s" % (
53 | self.combined_name,
54 | "\n ".join(lines),
55 | )
56 |
57 |
58 | class IncompatibleFontsError(Error):
59 | def __init__(self, glyph_errors):
60 | self.glyph_errors = glyph_errors
61 |
62 | def __str__(self):
63 | return "fonts contains incompatible glyphs: %s" % (
64 | ", ".join(repr(g) for g in sorted(self.glyph_errors.keys()))
65 | )
66 |
--------------------------------------------------------------------------------
/tools/benchmark.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015 Google Inc. All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | from __future__ import print_function, division, absolute_import
17 |
18 | import random
19 | import timeit
20 |
21 | MAX_ERR = 5
22 |
23 | SETUP_CODE = '''
24 | from %(module)s import %(function)s
25 | from %(benchmark_module)s import %(setup_function)s
26 | args = %(setup_function)s()
27 | '''
28 |
29 |
30 | def generate_curve():
31 | return [
32 | tuple(float(random.randint(0, 2048)) for coord in range(2))
33 | for point in range(4)]
34 |
35 |
36 | def setup_curve_to_quadratic():
37 | return generate_curve(), MAX_ERR
38 |
39 |
40 | def setup_curves_to_quadratic():
41 | num_curves = 3
42 | return (
43 | [generate_curve() for curve in range(num_curves)],
44 | [MAX_ERR] * num_curves)
45 |
46 |
47 | def run_benchmark(
48 | benchmark_module, module, function, setup_suffix='', repeat=1000):
49 | setup_func = 'setup_' + function
50 | if setup_suffix:
51 | print('%s with %s:' % (function, setup_suffix), end='')
52 | setup_func += '_' + setup_suffix
53 | else:
54 | print('%s:' % function, end='')
55 | results = timeit.repeat(
56 | '%s(*args)' % function,
57 | setup=(SETUP_CODE % {
58 | 'benchmark_module': benchmark_module, 'setup_function': setup_func,
59 | 'module': module, 'function': function}),
60 | repeat=repeat, number=1)
61 | print('\tavg=%dus' % (sum(results) / len(results) * 1000000.),
62 | '\tmin=%dus' % (min(results) * 1000000.))
63 |
64 |
65 | def main():
66 | run_benchmark('benchmark', 'cu2qu', 'curve_to_quadratic')
67 | run_benchmark('benchmark', 'cu2qu', 'curves_to_quadratic')
68 |
69 |
70 | if __name__ == '__main__':
71 | random.seed(1)
72 | main()
73 |
--------------------------------------------------------------------------------
/tests/data/quadratic/E_acute.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/tests/data/cubic/a.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | envlist = py{27,37}-{cy,nocy}, htmlcov
3 | package_name = cu2qu
4 | ; we skip tox's own sdist generation as we need to pass different environment
5 | ; variables for testing buiding with and without cython
6 | skipsdist = true
7 |
8 | [testenv]
9 | setenv =
10 | nocy: CU2QU_WITH_CYTHON=0
11 | cy: CU2QU_WITH_CYTHON=1
12 | cy: CYTHON_TRACE=1
13 | cy: CYTHON_ANNOTATE=1
14 | ; download the latest pip, setuptools and wheel when creating the venv
15 | download = true
16 | deps =
17 | -rtest-requirements.txt
18 | -rrequirements.txt
19 | cy: cython
20 | changedir = {toxinidir}
21 | commands =
22 | # create source distribution in a temp dir
23 | python setup.py --quiet sdist --dist-dir {envtmpdir}
24 |
25 | # install from sdist
26 | python -m pip install --no-build-isolation --ignore-installed --pre --no-deps --no-cache-dir --find-links {envtmpdir} {[tox]package_name}
27 |
28 | # ensure we are running the requested cu2qu version (compiled vs interpreted)
29 | nocy: python -c "import sys, cu2qu.cu2qu; cu2qu.cu2qu.COMPILED and sys.exit(1)"
30 | cy: python -c "import sys, cu2qu.cu2qu; cu2qu.cu2qu.COMPILED or sys.exit(1)"
31 |
32 | # run tests with code coverage enabled
33 | coverage run --parallel-mode -m pytest {posargs}
34 |
35 | [testenv:htmlcov]
36 | deps =
37 | coverage
38 | changedir = {toxinidir}
39 | commands =
40 | coverage combine
41 | coverage report
42 | coverage html
43 |
44 | [testenv:codecov]
45 | passenv = *
46 | deps =
47 | coverage
48 | codecov
49 | ignore_outcome = true
50 | changedir = {toxinidir}
51 | commands =
52 | coverage combine
53 | codecov --env TRAVIS_PYTHON_VERSION
54 |
55 | [testenv:update-cython]
56 | deps = requests
57 | changedir = {toxinidir}
58 | commands =
59 | python tools/update_cython_shadow.py {posargs}
60 |
61 | [testenv:sdist]
62 | deps =
63 | setuptools
64 | cython
65 | changedir = {toxinidir}
66 | commands =
67 | python -c 'import shutil; shutil.rmtree("dist", ignore_errors=True)'
68 | python setup.py --with-cython sdist --dist-dir dist
69 |
70 | [testenv:pure-wheel]
71 | deps =
72 | {[testenv:sdist]deps}
73 | pip
74 | wheel
75 | setenv = CU2QU_WITH_CYTHON=0
76 | changedir = {toxinidir}
77 | commands =
78 | {[testenv:sdist]commands}
79 | pip wheel --pre --no-deps --no-cache-dir --wheel-dir dist --find-links dist \
80 | --no-binary {[tox]package_name} {[tox]package_name}
81 |
82 | [testenv:native-wheel]
83 | deps = {[testenv:pure-wheel]deps}
84 | setenv = CU2QU_WITH_CYTHON=1
85 | changedir = {toxinidir}
86 | commands = {[testenv:pure-wheel]commands}
87 |
88 | ; we only upload the source distribution to PyPI (for now)
89 | [testenv:pypi]
90 | deps =
91 | {[testenv:sdist]deps}
92 | twine
93 | passenv = TWINE_USERNAME TWINE_PASSWORD
94 | changedir = {toxinidir}
95 | commands =
96 | {[testenv:sdist]commands}
97 | twine upload dist/*.zip
98 |
--------------------------------------------------------------------------------
/tests/cli_test.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function, division, absolute_import
2 |
3 | import defcon
4 |
5 | from . import DATADIR
6 | import pytest
7 | import py
8 |
9 | from cu2qu.ufo import CURVE_TYPE_LIB_KEY
10 | from cu2qu.cli import main
11 |
12 |
13 | TEST_UFOS = [
14 | py.path.local(DATADIR).join("RobotoSubset-Regular.ufo"),
15 | py.path.local(DATADIR).join("RobotoSubset-Bold.ufo"),
16 | ]
17 |
18 |
19 | @pytest.fixture
20 | def test_paths(tmpdir):
21 | result = []
22 | for path in TEST_UFOS:
23 | new_path = tmpdir / path.basename
24 | path.copy(new_path)
25 | result.append(new_path)
26 | return result
27 |
28 |
29 | class MainTest(object):
30 |
31 | @staticmethod
32 | def run_main(*args):
33 | main([str(p) for p in args if p])
34 |
35 | def test_single_input_no_output(self, test_paths):
36 | ufo_path = test_paths[0]
37 |
38 | self.run_main(ufo_path)
39 |
40 | font = defcon.Font(str(ufo_path))
41 | assert font.lib[CURVE_TYPE_LIB_KEY] == "quadratic"
42 |
43 | def test_single_input_output_file(self, tmpdir):
44 | input_path = TEST_UFOS[0]
45 | output_path = tmpdir / input_path.basename
46 | self.run_main('-o', output_path, input_path)
47 |
48 | assert output_path.check(dir=1)
49 |
50 | def test_multiple_inputs_output_dir(self, tmpdir):
51 | output_dir = tmpdir / "output_dir"
52 | self.run_main('-d', output_dir, *TEST_UFOS)
53 |
54 | assert output_dir.check(dir=1)
55 | outputs = set(p.basename for p in output_dir.listdir())
56 | assert "RobotoSubset-Regular.ufo" in outputs
57 | assert "RobotoSubset-Bold.ufo" in outputs
58 |
59 | def test_interpolatable_inplace(self, test_paths):
60 | self.run_main('-i', *test_paths)
61 | self.run_main('-i', *test_paths) # idempotent
62 |
63 | @pytest.mark.parametrize(
64 | "mode", ["", "-i"], ids=["normal", "interpolatable"])
65 | def test_copytree(self, mode, tmpdir):
66 | output_dir = tmpdir / "output_dir"
67 | self.run_main(mode, '-d', output_dir, *TEST_UFOS)
68 |
69 | output_dir_2 = tmpdir / "output_dir_2"
70 | # no conversion when curves are already quadratic, just copy
71 | self.run_main(mode, '-d', output_dir_2, *output_dir.listdir())
72 | # running again overwrites existing with the copy
73 | self.run_main(mode, '-d', output_dir_2, *output_dir.listdir())
74 |
75 | def test_multiprocessing(self, tmpdir, test_paths):
76 | self.run_main(*(test_paths + ["-j"]))
77 |
78 | def test_keep_direction(self, test_paths):
79 | self.run_main('--keep-direction', *test_paths)
80 |
81 | def test_conversion_error(self, test_paths):
82 | self.run_main('--conversion-error', 0.002, *test_paths)
83 |
84 | def test_conversion_error_short(self, test_paths):
85 | self.run_main('-e', 0.003, test_paths[0])
86 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/glyphs/contents.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | A
6 | A_.glif
7 | B
8 | B_.glif
9 | C
10 | C_.glif
11 | D
12 | D_.glif
13 | E
14 | E_.glif
15 | F
16 | F_.glif
17 | G
18 | G_.glif
19 | H
20 | H_.glif
21 | I
22 | I_.glif
23 | J
24 | J_.glif
25 | K
26 | K_.glif
27 | L
28 | L_.glif
29 | M
30 | M_.glif
31 | N
32 | N_.glif
33 | O
34 | O_.glif
35 | P
36 | P_.glif
37 | Q
38 | Q_.glif
39 | R
40 | R_.glif
41 | S
42 | S_.glif
43 | T
44 | T_.glif
45 | U
46 | U_.glif
47 | V
48 | V_.glif
49 | W
50 | W_.glif
51 | X
52 | X_.glif
53 | Y
54 | Y_.glif
55 | Z
56 | Z_.glif
57 | a
58 | a.glif
59 | b
60 | b.glif
61 | c
62 | c.glif
63 | d
64 | d.glif
65 | e
66 | e.glif
67 | f
68 | f.glif
69 | g
70 | g.glif
71 | h
72 | h.glif
73 | i
74 | i.glif
75 | j
76 | j.glif
77 | k
78 | k.glif
79 | l
80 | l.glif
81 | m
82 | m.glif
83 | n
84 | n.glif
85 | o
86 | o.glif
87 | p
88 | p.glif
89 | q
90 | q.glif
91 | r
92 | r.glif
93 | s
94 | s.glif
95 | space
96 | space.glif
97 | t
98 | t.glif
99 | u
100 | u.glif
101 | v
102 | v.glif
103 | w
104 | w.glif
105 | x
106 | x.glif
107 | y
108 | y.glif
109 | z
110 | z.glif
111 |
112 |
113 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/glyphs/contents.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | A
6 | A_.glif
7 | B
8 | B_.glif
9 | C
10 | C_.glif
11 | D
12 | D_.glif
13 | E
14 | E_.glif
15 | F
16 | F_.glif
17 | G
18 | G_.glif
19 | H
20 | H_.glif
21 | I
22 | I_.glif
23 | J
24 | J_.glif
25 | K
26 | K_.glif
27 | L
28 | L_.glif
29 | M
30 | M_.glif
31 | N
32 | N_.glif
33 | O
34 | O_.glif
35 | P
36 | P_.glif
37 | Q
38 | Q_.glif
39 | R
40 | R_.glif
41 | S
42 | S_.glif
43 | T
44 | T_.glif
45 | U
46 | U_.glif
47 | V
48 | V_.glif
49 | W
50 | W_.glif
51 | X
52 | X_.glif
53 | Y
54 | Y_.glif
55 | Z
56 | Z_.glif
57 | a
58 | a.glif
59 | b
60 | b.glif
61 | c
62 | c.glif
63 | d
64 | d.glif
65 | e
66 | e.glif
67 | f
68 | f.glif
69 | g
70 | g.glif
71 | h
72 | h.glif
73 | i
74 | i.glif
75 | j
76 | j.glif
77 | k
78 | k.glif
79 | l
80 | l.glif
81 | m
82 | m.glif
83 | n
84 | n.glif
85 | o
86 | o.glif
87 | p
88 | p.glif
89 | q
90 | q.glif
91 | r
92 | r.glif
93 | s
94 | s.glif
95 | space
96 | space.glif
97 | t
98 | t.glif
99 | u
100 | u.glif
101 | v
102 | v.glif
103 | w
104 | w.glif
105 | x
106 | x.glif
107 | y
108 | y.glif
109 | z
110 | z.glif
111 |
112 |
113 |
--------------------------------------------------------------------------------
/tests/data/quadratic/A_.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/tests/data/quadratic/a.glif:
--------------------------------------------------------------------------------
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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Wheels
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | tags: ["v*.*.*"]
7 | pull_request:
8 | branches: [main]
9 |
10 |
11 | jobs:
12 | build-binaries:
13 | name: Build wheel ${{ matrix.os }}
14 | runs-on: ${{ matrix.os }}
15 | strategy:
16 | fail-fast: false
17 | matrix:
18 | os: [ "ubuntu-latest", "windows-latest", "macos-latest" ]
19 | env:
20 | CIBW_ARCHS: auto64
21 | # macOS: Explicitly list ARM variants here for cross-compilation.
22 | CIBW_ARCHS_MACOS: "x86_64 universal2 arm64"
23 | CIBW_SKIP: pp*
24 | CIBW_ENVIRONMENT: CU2QU_WITH_CYTHON="true"
25 | steps:
26 | - uses: actions/checkout@v2
27 | with:
28 | submodules: recursive
29 | fetch-depth: 0
30 | - uses: actions/setup-python@v2
31 | with:
32 | python-version: "3.x"
33 | - name: Install cibuildwheel
34 | run: python -m pip install -U pip cibuildwheel
35 | - name: Build wheels
36 | run: python -m cibuildwheel --output-dir dist
37 | - uses: actions/upload-artifact@v2
38 | with:
39 | name: wheels-${{ matrix.os }}
40 | path: dist/*.whl
41 |
42 | build-pure:
43 | name: Build sdist and pure wheel
44 | runs-on: "ubuntu-latest"
45 | steps:
46 | - uses: actions/checkout@v2
47 | with:
48 | submodules: recursive
49 | fetch-depth: 0
50 | # Use PyPy just so we can test the package on it.
51 | - uses: actions/setup-python@v2
52 | with:
53 | python-version: 'pypy-3.9'
54 | - name: Install packaging tooling
55 | run: python -m pip install -U pip setuptools wheel
56 | - name: Build sdist and pure wheel
57 | run: python setup.py sdist bdist_wheel
58 | - name: Prepare for testing
59 | run: python -m pip install pytest -r requirements.txt dist/*.whl
60 | - name: Test
61 | run: pytest
62 | - uses: actions/upload-artifact@v2
63 | with:
64 | name: wheels-pure
65 | path: |
66 | dist/*.whl
67 | dist/*.zip
68 |
69 | deploy:
70 | # only run if the commit is tagged...
71 | if: startsWith(github.ref, 'refs/tags/v')
72 | # ... and all build jobs completed successfully
73 | needs: [build-binaries, build-pure]
74 | runs-on: ubuntu-latest
75 | steps:
76 | - uses: actions/checkout@v2
77 | with:
78 | submodules: recursive
79 | - name: Set up Python
80 | uses: actions/setup-python@v2
81 | with:
82 | python-version: "3.x"
83 | - name: Install dependencies
84 | run: |
85 | python -m pip install --upgrade pip
86 | pip install --upgrade setuptools wheel twine cython
87 | - name: Download artifacts from build jobs
88 | uses: actions/download-artifact@v2
89 | with:
90 | path: dist
91 | - name: Extract release notes from annotated tag message
92 | id: release_notes
93 | env:
94 | # e.g. v0.1.0a1, v1.2.0b2 or v2.3.0rc3, but not v1.0.0
95 | PRERELEASE_TAG_PATTERN: "v[[:digit:]]+\\.[[:digit:]]+\\.[[:digit:]]+([ab]|rc)[[:digit:]]+"
96 | run: |
97 | # GH checkout action doesn't preserve tag annotations, we must fetch them
98 | # https://github.com/actions/checkout/issues/290
99 | git fetch --tags --force
100 | # strip leading 'refs/tags/' to get the tag name
101 | TAG_NAME="${GITHUB_REF##*/}"
102 | # Dump tag message to temporary .md file (excluding the PGP signature at the bottom)
103 | TAG_MESSAGE=$(git tag -l --format='%(contents)' $TAG_NAME | sed -n '/-----BEGIN PGP SIGNATURE-----/q;p')
104 | echo "$TAG_MESSAGE" > "${{ runner.temp }}/release_notes.md"
105 | # if the tag has a pre-release suffix mark the Github Release accordingly
106 | if egrep -q "$PRERELEASE_TAG_PATTERN" <<< "$TAG_NAME"; then
107 | echo "Tag contains a pre-release suffix"
108 | echo "IS_PRERELEASE=true" >> "$GITHUB_ENV"
109 | else
110 | echo "Tag does not contain pre-release suffix"
111 | echo "IS_PRERELEASE=false" >> "$GITHUB_ENV"
112 | fi
113 | - name: Create GitHub release
114 | id: create_release
115 | uses: actions/create-release@v1
116 | env:
117 | # This token is provided by Actions, you do not need to create your own token
118 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
119 | with:
120 | tag_name: ${{ github.ref }}
121 | release_name: ${{ github.ref }}
122 | body_path: "${{ runner.temp }}/release_notes.md"
123 | draft: false
124 | prerelease: ${{ env.IS_PRERELEASE }}
125 | - name: Build and publish
126 | env:
127 | TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
128 | TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
129 | run: |
130 | if [ "$IS_PRERELEASE" == true ]; then
131 | echo "DEBUG: This is a pre-release"
132 | else
133 | echo "DEBUG: This is a final release"
134 | fi
135 | twine upload dist/wheels-*/*.whl dist/wheels-*/*.zip
136 |
--------------------------------------------------------------------------------
/Lib/cu2qu/cli.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function, division, absolute_import
2 | import os
3 | import argparse
4 | import logging
5 | import shutil
6 | import multiprocessing as mp
7 | from contextlib import closing
8 | from functools import partial
9 |
10 | import cu2qu
11 | from cu2qu.ufo import font_to_quadratic, fonts_to_quadratic
12 |
13 | import defcon
14 |
15 | logger = logging.getLogger("cu2qu")
16 |
17 |
18 | def _cpu_count():
19 | try:
20 | return mp.cpu_count()
21 | except NotImplementedError: # pragma: no cover
22 | return 1
23 |
24 |
25 | def _font_to_quadratic(zipped_paths, **kwargs):
26 | input_path, output_path = zipped_paths
27 | ufo = defcon.Font(input_path)
28 | logger.info('Converting curves for %s', input_path)
29 | if font_to_quadratic(ufo, **kwargs):
30 | logger.info("Saving %s", output_path)
31 | ufo.save(output_path)
32 | else:
33 | _copytree(input_path, output_path)
34 |
35 |
36 | def _samepath(path1, path2):
37 | # TODO on python3+, there's os.path.samefile
38 | path1 = os.path.normcase(os.path.abspath(os.path.realpath(path1)))
39 | path2 = os.path.normcase(os.path.abspath(os.path.realpath(path2)))
40 | return path1 == path2
41 |
42 |
43 | def _copytree(input_path, output_path):
44 | if _samepath(input_path, output_path):
45 | logger.debug("input and output paths are the same file; skipped copy")
46 | return
47 | if os.path.exists(output_path):
48 | shutil.rmtree(output_path)
49 | shutil.copytree(input_path, output_path)
50 |
51 |
52 | def main(args=None):
53 | parser = argparse.ArgumentParser(prog="cu2qu")
54 | parser.add_argument(
55 | "--version", action="version", version=cu2qu.__version__)
56 | parser.add_argument(
57 | "infiles",
58 | nargs="+",
59 | metavar="INPUT",
60 | help="one or more input UFO source file(s).")
61 | parser.add_argument("-v", "--verbose", action="count", default=0)
62 | parser.add_argument(
63 | "-e",
64 | "--conversion-error",
65 | type=float,
66 | metavar="ERROR",
67 | default=None,
68 | help="maxiumum approximation error measured in EM (default: 0.001)")
69 | parser.add_argument(
70 | "--keep-direction",
71 | dest="reverse_direction",
72 | action="store_false",
73 | help="do not reverse the contour direction")
74 |
75 | mode_parser = parser.add_mutually_exclusive_group()
76 | mode_parser.add_argument(
77 | "-i",
78 | "--interpolatable",
79 | action="store_true",
80 | help="whether curve conversion should keep interpolation compatibility"
81 | )
82 | mode_parser.add_argument(
83 | "-j",
84 | "--jobs",
85 | type=int,
86 | nargs="?",
87 | default=1,
88 | const=_cpu_count(),
89 | metavar="N",
90 | help="Convert using N multiple processes (default: %(default)s)")
91 |
92 | output_parser = parser.add_mutually_exclusive_group()
93 | output_parser.add_argument(
94 | "-o",
95 | "--output-file",
96 | default=None,
97 | metavar="OUTPUT",
98 | help=("output filename for the converted UFO. By default fonts are "
99 | "modified in place. This only works with a single input."))
100 | output_parser.add_argument(
101 | "-d",
102 | "--output-dir",
103 | default=None,
104 | metavar="DIRECTORY",
105 | help="output directory where to save converted UFOs")
106 |
107 | options = parser.parse_args(args)
108 |
109 | if not options.verbose:
110 | level = "WARNING"
111 | elif options.verbose == 1:
112 | level = "INFO"
113 | else:
114 | level = "DEBUG"
115 | logging.basicConfig(level=level)
116 |
117 | if len(options.infiles) > 1 and options.output_file:
118 | parser.error("-o/--output-file can't be used with multile inputs")
119 |
120 | if options.output_dir:
121 | output_dir = options.output_dir
122 | if not os.path.exists(output_dir):
123 | os.mkdir(output_dir)
124 | elif not os.path.isdir(output_dir):
125 | parser.error("'%s' is not a directory" % output_dir)
126 | output_paths = [
127 | os.path.join(output_dir, os.path.basename(p))
128 | for p in options.infiles
129 | ]
130 | elif options.output_file:
131 | output_paths = [options.output_file]
132 | else:
133 | # save in-place
134 | output_paths = list(options.infiles)
135 |
136 | kwargs = dict(dump_stats=options.verbose > 0,
137 | max_err_em=options.conversion_error,
138 | reverse_direction=options.reverse_direction)
139 |
140 | if options.interpolatable:
141 | logger.info('Converting curves compatibly')
142 | ufos = [defcon.Font(infile) for infile in options.infiles]
143 | if fonts_to_quadratic(ufos, **kwargs):
144 | for ufo, output_path in zip(ufos, output_paths):
145 | logger.info("Saving %s", output_path)
146 | ufo.save(output_path)
147 | else:
148 | for input_path, output_path in zip(options.infiles, output_paths):
149 | _copytree(input_path, output_path)
150 | else:
151 | jobs = min(len(options.infiles),
152 | options.jobs) if options.jobs > 1 else 1
153 | if jobs > 1:
154 | func = partial(_font_to_quadratic, **kwargs)
155 | logger.info('Running %d parallel processes', jobs)
156 | with closing(mp.Pool(jobs)) as pool:
157 | # can't use Pool.starmap as it's 3.3+ only
158 | pool.map(func, zip(options.infiles, output_paths))
159 | else:
160 | for paths in zip(options.infiles, output_paths):
161 | _font_to_quadratic(paths, **kwargs)
162 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Bold.ufo/fontinfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ascender
6 | 2146
7 | capHeight
8 | 1456
9 | copyright
10 | Copyright 2011 Google Inc. All Rights Reserved.
11 | descender
12 | -555
13 | familyName
14 | RobotoSubset
15 | italicAngle
16 | 0
17 | openTypeHeadCreated
18 | 2008/09/12 12:29:34
19 | openTypeHeadFlags
20 |
21 | 0
22 | 1
23 | 3
24 | 4
25 |
26 | openTypeHeadLowestRecPPEM
27 | 9
28 | openTypeHheaAscender
29 | 1900
30 | openTypeHheaDescender
31 | -500
32 | openTypeHheaLineGap
33 | 0
34 | openTypeNameDescription
35 |
36 | openTypeNameDesigner
37 |
38 | openTypeNameDesignerURL
39 |
40 | openTypeNameLicense
41 |
42 | openTypeNameLicenseURL
43 |
44 | openTypeNameManufacturer
45 |
46 | openTypeNameManufacturerURL
47 |
48 | openTypeNameSampleText
49 |
50 | openTypeOS2CodePageRanges
51 |
52 | 0
53 | 1
54 | 2
55 | 3
56 | 4
57 | 7
58 | 8
59 | 29
60 |
61 | openTypeOS2FamilyClass
62 |
63 | 0
64 | 0
65 |
66 | openTypeOS2Panose
67 |
68 | 0
69 | 0
70 | 0
71 | 0
72 | 0
73 | 0
74 | 0
75 | 0
76 | 0
77 | 0
78 |
79 | openTypeOS2Selection
80 |
81 |
82 | openTypeOS2StrikeoutPosition
83 | 512
84 | openTypeOS2StrikeoutSize
85 | 102
86 | openTypeOS2SubscriptXOffset
87 | 0
88 | openTypeOS2SubscriptXSize
89 | 1434
90 | openTypeOS2SubscriptYOffset
91 | 287
92 | openTypeOS2SubscriptYSize
93 | 1331
94 | openTypeOS2SuperscriptXOffset
95 | 0
96 | openTypeOS2SuperscriptXSize
97 | 1434
98 | openTypeOS2SuperscriptYOffset
99 | 977
100 | openTypeOS2SuperscriptYSize
101 | 1331
102 | openTypeOS2Type
103 |
104 |
105 | openTypeOS2TypoAscender
106 | 2146
107 | openTypeOS2TypoDescender
108 | -555
109 | openTypeOS2TypoLineGap
110 | 0
111 | openTypeOS2UnicodeRanges
112 |
113 | 0
114 | 1
115 | 2
116 | 3
117 | 4
118 | 5
119 | 6
120 | 7
121 | 9
122 | 11
123 | 29
124 | 30
125 | 31
126 | 32
127 | 33
128 | 34
129 | 35
130 | 36
131 | 37
132 | 38
133 | 40
134 | 45
135 | 60
136 | 62
137 | 64
138 | 69
139 |
140 | openTypeOS2VendorID
141 | GOOG
142 | openTypeOS2WeightClass
143 | 700
144 | openTypeOS2WidthClass
145 | 5
146 | openTypeOS2WinAscent
147 | 2146
148 | openTypeOS2WinDescent
149 | 555
150 | postscriptBlueFuzz
151 | 1
152 | postscriptBlueScale
153 | 0.039625
154 | postscriptBlueShift
155 | 7
156 | postscriptBlueValues
157 |
158 | -20
159 | 0
160 | 1082
161 | 1102
162 | 1456
163 | 1476
164 |
165 | postscriptDefaultCharacter
166 | space
167 | postscriptForceBold
168 |
169 | postscriptIsFixedPitch
170 |
171 | postscriptOtherBlues
172 |
173 | -436
174 | -416
175 |
176 | postscriptStemSnapH
177 |
178 | 250
179 |
180 | postscriptStemSnapV
181 |
182 | 316
183 |
184 | postscriptUnderlinePosition
185 | -150
186 | postscriptUnderlineThickness
187 | 100
188 | postscriptUniqueID
189 | -1
190 | styleName
191 | Bold
192 | trademark
193 |
194 | unitsPerEm
195 | 2048
196 | versionMajor
197 | 1
198 | versionMinor
199 | 0
200 | xHeight
201 | 1082
202 | year
203 | 2017
204 |
205 |
206 |
--------------------------------------------------------------------------------
/tests/data/RobotoSubset-Regular.ufo/fontinfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ascender
6 | 2146
7 | capHeight
8 | 1456
9 | copyright
10 | Copyright 2011 Google Inc. All Rights Reserved.
11 | descender
12 | -555
13 | familyName
14 | RobotoSubset
15 | guidelines
16 |
17 |
18 | italicAngle
19 | 0
20 | openTypeHeadCreated
21 | 2008/09/12 12:29:34
22 | openTypeHeadFlags
23 |
24 | 0
25 | 1
26 | 3
27 | 4
28 |
29 | openTypeHeadLowestRecPPEM
30 | 9
31 | openTypeHheaAscender
32 | 1900
33 | openTypeHheaDescender
34 | -500
35 | openTypeHheaLineGap
36 | 0
37 | openTypeNameDescription
38 |
39 | openTypeNameDesigner
40 |
41 | openTypeNameDesignerURL
42 |
43 | openTypeNameLicense
44 |
45 | openTypeNameLicenseURL
46 |
47 | openTypeNameManufacturer
48 |
49 | openTypeNameManufacturerURL
50 |
51 | openTypeNameSampleText
52 |
53 | openTypeOS2CodePageRanges
54 |
55 | 0
56 | 1
57 | 2
58 | 3
59 | 4
60 | 7
61 | 8
62 | 29
63 |
64 | openTypeOS2FamilyClass
65 |
66 | 0
67 | 0
68 |
69 | openTypeOS2Panose
70 |
71 | 2
72 | 0
73 | 0
74 | 0
75 | 0
76 | 0
77 | 0
78 | 0
79 | 0
80 | 0
81 |
82 | openTypeOS2Selection
83 |
84 |
85 | openTypeOS2StrikeoutPosition
86 | 512
87 | openTypeOS2StrikeoutSize
88 | 102
89 | openTypeOS2SubscriptXOffset
90 | 0
91 | openTypeOS2SubscriptXSize
92 | 1434
93 | openTypeOS2SubscriptYOffset
94 | 287
95 | openTypeOS2SubscriptYSize
96 | 1331
97 | openTypeOS2SuperscriptXOffset
98 | 0
99 | openTypeOS2SuperscriptXSize
100 | 1434
101 | openTypeOS2SuperscriptYOffset
102 | 977
103 | openTypeOS2SuperscriptYSize
104 | 1331
105 | openTypeOS2Type
106 |
107 |
108 | openTypeOS2TypoAscender
109 | 2146
110 | openTypeOS2TypoDescender
111 | -555
112 | openTypeOS2TypoLineGap
113 | 0
114 | openTypeOS2UnicodeRanges
115 |
116 | 0
117 | 1
118 | 2
119 | 3
120 | 4
121 | 5
122 | 6
123 | 7
124 | 9
125 | 11
126 | 29
127 | 30
128 | 31
129 | 32
130 | 33
131 | 34
132 | 35
133 | 36
134 | 37
135 | 38
136 | 40
137 | 45
138 | 60
139 | 62
140 | 64
141 | 69
142 |
143 | openTypeOS2VendorID
144 | GOOG
145 | openTypeOS2WeightClass
146 | 400
147 | openTypeOS2WidthClass
148 | 5
149 | openTypeOS2WinAscent
150 | 2146
151 | openTypeOS2WinDescent
152 | 555
153 | postscriptBlueFuzz
154 | 1
155 | postscriptBlueScale
156 | 0.039625
157 | postscriptBlueShift
158 | 7
159 | postscriptBlueValues
160 |
161 | -20
162 | 0
163 | 1082
164 | 1102
165 | 1456
166 | 1476
167 |
168 | postscriptDefaultCharacter
169 | space
170 | postscriptFamilyBlues
171 |
172 |
173 | postscriptFamilyOtherBlues
174 |
175 |
176 | postscriptForceBold
177 |
178 | postscriptIsFixedPitch
179 |
180 | postscriptOtherBlues
181 |
182 | -436
183 | -416
184 |
185 | postscriptStemSnapH
186 |
187 | 154
188 |
189 | postscriptStemSnapV
190 |
191 | 196
192 |
193 | postscriptUnderlinePosition
194 | -150
195 | postscriptUnderlineThickness
196 | 100
197 | postscriptUniqueID
198 | -1
199 | styleName
200 | Regular
201 | trademark
202 |
203 | unitsPerEm
204 | 2048
205 | versionMajor
206 | 1
207 | versionMinor
208 | 0
209 | xHeight
210 | 1082
211 | year
212 | 2017
213 |
214 |
215 |
--------------------------------------------------------------------------------
/tests/cu2qu_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Google Inc. All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | from __future__ import print_function, division, absolute_import
17 |
18 | import collections
19 | import math
20 | import unittest
21 | import os
22 | import json
23 |
24 | from cu2qu import curve_to_quadratic, curves_to_quadratic
25 | from . import DATADIR
26 |
27 |
28 | MAX_ERR = 5
29 |
30 |
31 | class CurveToQuadraticTest(unittest.TestCase):
32 |
33 | @classmethod
34 | def setUpClass(cls):
35 | """Do the curve conversion ahead of time, and run tests on results."""
36 | with open(os.path.join(DATADIR, "curves.json"), "r") as fp:
37 | curves = json.load(fp)
38 |
39 | cls.single_splines = [
40 | curve_to_quadratic(c, MAX_ERR) for c in curves]
41 | cls.single_errors = [
42 | cls.curve_spline_dist(c, s)
43 | for c, s in zip(curves, cls.single_splines)]
44 |
45 | curve_groups = [curves[i:i + 3] for i in range(0, 300, 3)]
46 | cls.compat_splines = [
47 | curves_to_quadratic(c, [MAX_ERR] * 3) for c in curve_groups]
48 | cls.compat_errors = [
49 | [cls.curve_spline_dist(c, s) for c, s in zip(curve_group, splines)]
50 | for curve_group, splines in zip(curve_groups, cls.compat_splines)]
51 |
52 | cls.results = []
53 |
54 | @classmethod
55 | def tearDownClass(cls):
56 | """Print stats from conversion, as determined during tests."""
57 |
58 | for tag, results in cls.results:
59 | print('\n%s\n%s' % (
60 | tag, '\n'.join(
61 | '%s: %s (%d)' % (k, '#' * (v // 10 + 1), v)
62 | for k, v in sorted(results.items()))))
63 |
64 | def test_results_unchanged(self):
65 | """Tests that the results of conversion haven't changed since the time
66 | of this test's writing. Useful as a quick check whenever one modifies
67 | the conversion algorithm.
68 | """
69 |
70 | expected = {
71 | 2: 6,
72 | 3: 26,
73 | 4: 82,
74 | 5: 232,
75 | 6: 360,
76 | 7: 266,
77 | 8: 28}
78 |
79 | results = collections.defaultdict(int)
80 | for spline in self.single_splines:
81 | n = len(spline) - 2
82 | results[n] += 1
83 | self.assertEqual(results, expected)
84 | self.results.append(('single spline lengths', results))
85 |
86 | def test_results_unchanged_multiple(self):
87 | """Test that conversion results are unchanged for multiple curves."""
88 |
89 | expected = {
90 | 5: 11,
91 | 6: 35,
92 | 7: 49,
93 | 8: 5}
94 |
95 | results = collections.defaultdict(int)
96 | for splines in self.compat_splines:
97 | n = len(splines[0]) - 2
98 | for spline in splines[1:]:
99 | self.assertEqual(len(spline) - 2, n,
100 | 'Got incompatible conversion results')
101 | results[n] += 1
102 | self.assertEqual(results, expected)
103 | self.results.append(('compatible spline lengths', results))
104 |
105 | def test_does_not_exceed_tolerance(self):
106 | """Test that conversion results do not exceed given error tolerance."""
107 |
108 | results = collections.defaultdict(int)
109 | for error in self.single_errors:
110 | results[round(error, 1)] += 1
111 | self.assertLessEqual(error, MAX_ERR)
112 | self.results.append(('single errors', results))
113 |
114 | def test_does_not_exceed_tolerance_multiple(self):
115 | """Test that error tolerance isn't exceeded for multiple curves."""
116 |
117 | results = collections.defaultdict(int)
118 | for errors in self.compat_errors:
119 | for error in errors:
120 | results[round(error, 1)] += 1
121 | self.assertLessEqual(error, MAX_ERR)
122 | self.results.append(('compatible errors', results))
123 |
124 | @classmethod
125 | def curve_spline_dist(cls, bezier, spline, total_steps=20):
126 | """Max distance between a bezier and quadratic spline at sampled points."""
127 |
128 | error = 0
129 | n = len(spline) - 2
130 | steps = total_steps // n
131 | for i in range(0, n - 1):
132 | p1 = spline[0] if i == 0 else p3
133 | p2 = spline[i + 1]
134 | if i < n - 1:
135 | p3 = cls.lerp(spline[i + 1], spline[i + 2], 0.5)
136 | else:
137 | p3 = spline[n + 2]
138 | segment = p1, p2, p3
139 | for j in range(steps):
140 | error = max(error, cls.dist(
141 | cls.cubic_bezier_at(bezier, (j / steps + i) / n),
142 | cls.quadratic_bezier_at(segment, j / steps)))
143 | return error
144 |
145 | @classmethod
146 | def lerp(cls, p1, p2, t):
147 | (x1, y1), (x2, y2) = p1, p2
148 | return x1 + (x2 - x1) * t, y1 + (y2 - y1) * t
149 |
150 | @classmethod
151 | def dist(cls, p1, p2):
152 | (x1, y1), (x2, y2) = p1, p2
153 | return math.hypot(x1 - x2, y1 - y2)
154 |
155 | @classmethod
156 | def quadratic_bezier_at(cls, b, t):
157 | (x1, y1), (x2, y2), (x3, y3) = b
158 | _t = 1 - t
159 | t2 = t * t
160 | _t2 = _t * _t
161 | _2_t_t = 2 * t * _t
162 | return (_t2 * x1 + _2_t_t * x2 + t2 * x3,
163 | _t2 * y1 + _2_t_t * y2 + t2 * y3)
164 |
165 | @classmethod
166 | def cubic_bezier_at(cls, b, t):
167 | (x1, y1), (x2, y2), (x3, y3), (x4, y4) = b
168 | _t = 1 - t
169 | t2 = t * t
170 | _t2 = _t * _t
171 | t3 = t * t2
172 | _t3 = _t * _t2
173 | _3_t2_t = 3 * t2 * _t
174 | _3_t_t2 = 3 * t * _t2
175 | return (_t3 * x1 + _3_t_t2 * x2 + _3_t2_t * x3 + t3 * x4,
176 | _t3 * y1 + _3_t_t2 * y2 + _3_t2_t * y3 + t3 * y4)
177 |
178 |
179 | if __name__ == '__main__':
180 | unittest.main()
181 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015 Google Inc. All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | from setuptools import setup, find_packages, Extension
17 | from setuptools.command.build_ext import build_ext as _build_ext
18 | from setuptools.command.sdist import sdist as _sdist
19 | import pkg_resources
20 | from distutils import log
21 | import sys
22 | import os
23 | import re
24 | from io import open
25 |
26 |
27 | needs_pytest = {'pytest', 'test'}.intersection(sys.argv)
28 | pytest_runner = ['pytest_runner'] if needs_pytest else []
29 | needs_wheel = {'bdist_wheel'}.intersection(sys.argv)
30 | wheel = ['wheel'] if needs_wheel else []
31 |
32 | # Check if minimum required Cython is available.
33 | # For consistency, we require the same as our vendored Cython.Shadow module
34 | cymod = "Lib/cu2qu/cython.py"
35 | cython_version_re = re.compile('__version__ = ["\']([0-9][0-9\w\.]+)["\']')
36 | with open(cymod, "r", encoding="utf-8") as fp:
37 | for line in fp:
38 | m = cython_version_re.match(line)
39 | if m:
40 | cython_min_version = m.group(1)
41 | break
42 | else:
43 | sys.exit("error: failed to parse cython version in '%s'" % cymod)
44 |
45 | required_cython = "cython >= %s" % cython_min_version
46 | try:
47 | pkg_resources.require(required_cython)
48 | except pkg_resources.ResolutionError:
49 | has_cython = False
50 | else:
51 | has_cython = True
52 |
53 | # First, check if the CU2QU_WITH_CYTHON environment variable is set.
54 | # Values "1", "true" or "yes" mean that Cython is required and will be used
55 | # to regenerate the *.c sources from which the native extension is built;
56 | # "0", "false" or "no" mean that Cython is not required and no extension
57 | # module will be compiled (i.e. the wheel is pure-python and universal).
58 | # If the variable is not set, then the pre-generated *.c sources that
59 | # are included in the sdist package will be used to try build the extension.
60 | # However, if any error occurs during compilation (e.g. the host
61 | # machine doesn't have the required compiler toolchain installed), the
62 | # installation proceeds without the compiled extensions, but will only have
63 | # the pure-python module.
64 | env_with_cython = os.environ.get("CU2QU_WITH_CYTHON")
65 | with_cython = (
66 | True if env_with_cython in {"1", "true", "yes"}
67 | else False if env_with_cython in {"0", "false", "no"}
68 | else None
69 | )
70 |
71 | # command line options --with-cython and --without-cython are also supported.
72 | # They override the environment variable
73 | opt_with_cython = {'--with-cython'}.intersection(sys.argv)
74 | opt_without_cython = {'--without-cython'}.intersection(sys.argv)
75 | if opt_with_cython and opt_without_cython:
76 | sys.exit(
77 | "error: the options '--with-cython' and '--without-cython' are "
78 | "mutually exclusive"
79 | )
80 | elif opt_with_cython:
81 | sys.argv.remove("--with-cython")
82 | with_cython = True
83 | elif opt_without_cython:
84 | sys.argv.remove("--without-cython")
85 | with_cython = False
86 |
87 |
88 | class cython_build_ext(_build_ext):
89 | """Compile *.pyx source files to *.c using cythonize if Cython is
90 | installed, else use the pre-generated *.c sources.
91 | """
92 |
93 | def finalize_options(self):
94 | if with_cython:
95 | if not has_cython:
96 | from distutils.errors import DistutilsSetupError
97 |
98 | raise DistutilsSetupError(
99 | "%s is required when using --with-cython" % required_cython
100 | )
101 |
102 | from Cython.Build import cythonize
103 |
104 | # optionally enable line tracing for test coverage support
105 | linetrace = os.environ.get("CYTHON_TRACE") == "1"
106 |
107 | self.distribution.ext_modules[:] = cythonize(
108 | self.distribution.ext_modules,
109 | force=linetrace or self.force,
110 | annotate=os.environ.get("CYTHON_ANNOTATE") == "1",
111 | quiet=not self.verbose,
112 | compiler_directives={
113 | "linetrace": linetrace,
114 | "language_level": 3,
115 | "embedsignature": True,
116 | },
117 | )
118 | else:
119 | # replace *.py/.pyx sources with their pre-generated *.c versions
120 | for ext in self.distribution.ext_modules:
121 | ext.sources = [re.sub("\.pyx?$", ".c", n) for n in ext.sources]
122 |
123 | _build_ext.finalize_options(self)
124 |
125 | def build_extensions(self):
126 | if not has_cython:
127 | log.info(
128 | "%s is not installed. Pre-generated *.c sources will be "
129 | "will be used to build the extensions." % required_cython
130 | )
131 |
132 | try:
133 | _build_ext.build_extensions(self)
134 | except Exception as e:
135 | if with_cython:
136 | raise
137 | from distutils.errors import DistutilsModuleError
138 |
139 | # optional compilation failed: we delete 'ext_modules' and make sure
140 | # the generated wheel is 'pure'
141 | del self.distribution.ext_modules[:]
142 | try:
143 | bdist_wheel = self.get_finalized_command("bdist_wheel")
144 | except DistutilsModuleError:
145 | # 'bdist_wheel' command not available as wheel is not installed
146 | pass
147 | else:
148 | bdist_wheel.root_is_pure = True
149 | log.error('error: building extensions failed: %s' % e)
150 |
151 | def get_source_files(self):
152 | filenames = _build_ext.get_source_files(self)
153 |
154 | # include pre-generated *.c sources inside sdist, but only if cython is
155 | # installed (and hence they will be updated upon making the sdist)
156 | if has_cython:
157 | for ext in self.extensions:
158 | filenames.extend(
159 | [re.sub("\.pyx?$", ".c", n) for n in ext.sources]
160 | )
161 | return filenames
162 |
163 |
164 | class cython_sdist(_sdist):
165 | """ Run 'cythonize' on *.pyx sources to ensure the *.c files included
166 | in the source distribution are up-to-date.
167 | """
168 |
169 | def run(self):
170 | if with_cython and not has_cython:
171 | from distutils.errors import DistutilsSetupError
172 |
173 | raise DistutilsSetupError(
174 | "%s is required when creating sdist --with-cython"
175 | % required_cython
176 | )
177 |
178 | if has_cython:
179 | from Cython.Build import cythonize
180 |
181 | cythonize(
182 | self.distribution.ext_modules,
183 | force=True, # always regenerate *.c sources
184 | quiet=not self.verbose,
185 | compiler_directives={
186 | "language_level": 3,
187 | "embedsignature": True
188 | },
189 | )
190 |
191 | _sdist.run(self)
192 |
193 |
194 | # don't build extensions if user explicitly requested --without-cython or we're
195 | # building for PyPy.
196 | is_pypy = hasattr(sys, "pypy_version_info")
197 | if with_cython is False or (with_cython is None and is_pypy):
198 | extensions = []
199 | else:
200 | extensions = [
201 | Extension("cu2qu.cu2qu", ["Lib/cu2qu/cu2qu.py"]),
202 | ]
203 |
204 | with open('README.rst', 'r') as f:
205 | long_description = f.read()
206 |
207 | setup(
208 | name='cu2qu',
209 | use_scm_version={"write_to": "Lib/cu2qu/_version.py"},
210 | description='Cubic-to-quadratic bezier curve conversion',
211 | author="James Godfrey-Kittle, Behdad Esfahbod",
212 | author_email="jamesgk@google.com",
213 | url="https://github.com/googlefonts",
214 | license="Apache License, Version 2.0",
215 | long_description=long_description,
216 | packages=find_packages('Lib'),
217 | package_dir={'': 'Lib'},
218 | ext_modules=extensions,
219 | include_package_data=True,
220 | setup_requires=pytest_runner + wheel + ["setuptools_scm"],
221 | tests_require=[
222 | 'pytest>=2.8',
223 | ],
224 | install_requires=[
225 | "fonttools[ufo] >= 3.32.0",
226 | ],
227 | extras_require={"cli": ["defcon >= 0.6.0"]},
228 | entry_points={"console_scripts": ["cu2qu = cu2qu.cli:main [cli]"]},
229 | classifiers=[
230 | 'Development Status :: 4 - Beta',
231 | 'Intended Audience :: Developers',
232 | 'License :: OSI Approved :: Apache Software License',
233 | 'Operating System :: OS Independent',
234 | 'Programming Language :: Python',
235 | 'Programming Language :: Python :: 2',
236 | 'Programming Language :: Python :: 3',
237 | 'Topic :: Scientific/Engineering :: Mathematics',
238 | 'Topic :: Multimedia :: Graphics :: Graphics Conversion',
239 | 'Topic :: Multimedia :: Graphics :: Editors :: Vector-Based',
240 | 'Topic :: Software Development :: Libraries :: Python Modules',
241 | ],
242 | cmdclass={"build_ext": cython_build_ext, "sdist": cython_sdist},
243 | )
244 |
--------------------------------------------------------------------------------