otfautohint
contains a Python port of the “Automatic Coloring” code
originally written in C by Bill Paxton. That code was most recently distributed
as “psautohint” in a PyPI package of the same name.
Changes Summary:
Most of the algorithms are unchanged but not all. Some notable differences are:
bez
charstring
interchange format. CharStrings are now directly unpacked into glyphData
objects. These are capable of representing any (decompiled) CharString with
the caveats that the particular spline operator (e.g. rCurveTo
vs
curveTo
) is not recorded.hintState
objects, one per
glyph, rather than in globals.glyphData/pt
2-tuple object has
special a
and o
value accessors and a class-level switch as part of
this unification. (a
is meant to suggest “aligned” and o
is meant to
suggest “opposite”, referring to the relation between the value and the
chosen alignment; a
is x
and o
is y
when horizontal alignment is
chosen, and vice-versa when vertical alignment is chosen.) Some bug fixes
and improvements that were only added to one dimension in the past now work
in both.There are also some features that are not (yet) ported:
moveTo
operators
and warn about duplicate subpaths or unusually large glyphs. It is now more
appropriate to check for these characteristics using sanitizers at earlier
stages in the development process.allow-changes
option was active. The primary reason for
doing so was when a single spline “wanted” conflicting hints at its start
and end points. This is a relatively rare circumstance and the Adobe
maintainers are evaluating what, if anything, should be done in this case.Most functions are now documented in-line. Adapter code in autohint.py
calls
hint()
on glyphHinter
in hinter.py
, which in turn calls into the
dimension-specific hhinter
and vhinter
objects in the same file.
The Python code is slower when hinting individual glyphs, often 5 or more times
as slow or more compared with the C code on the same machine. It also uses more
memory. However, by default glyphs are now hinted in parallel using the Python
multiprocessing
module when multiple CPU cores are available. As part of this
change the glyphs are also unpacked just before hinting and updated right after
hinting in order to lower the total memory used by the process at a given time.
As a result the overall hinting process is often slightly faster on
contemporary machines.
The initial CFF2 specification, and all revisions at the time of writing, require that stems are defined in increasing order by their (lower) starting locations and then, if two stems start at the same place, their ending locations (which are higher except in the case of ghost hints). Duplicate stems are disallowed. Stems that would be specified out of order in a particular master (relative to the default master ordering) must therefore be removed.
As long as a design space is defined by interpolation only (rather than extrapolation) the extremes of stem ordering are represented by the (sorted) orders in the individual masters. Consider the bottom edge of stem i in a variable glyph with n masters. It’s location at some point in design space can be represented as
c1*si1 + c2*si2 + … + cn*sin
where sik is the position of the edge in that glyph in master k
and each c
value is some interpolation coefficient, so that c1 +
c2 + … + cn == 1 and 0 <= ck <= 1
The signed distance between the bottom edges of two stems i and j is accordingly
c1*si1 + c2*si2 + … + cn*sin - c1*sj1 + c2*sj2 + … + cn*sjn
or
c1*(si1 - sj1) + c2*(si2 - sj2) + … + cn*(sin - sjn)
The minimum/maximum distance in the space will therefore be sik
Suppose that stems i and j are in the same order across all masters with stem i before stem j (so either sik < sjk or (sik == sjk and eik < ejk)). Whether i overlaps with j in a given master k is defined by whether sjk - eik < Om (the overlap margin). Therefore, by reasoning analogous to the above, the question of whether two consistently ordered stems overlap in design space is equivalent to whether they overlap in at least one master.
Any two stems that change order between two masters overlap at some point in design space interpolated between those masters. The question of whether two stems overlap in the general is therefore equivalent to: