There is no longer a requirement that all the masters have exactly the same base color glyphs as the default masters. Similarly, it's no longer required that all masters' LayerLists have the same total count of layers. It is sufficient that, for a base color glyph in the default master, a non-default master may (or may not) contain one with the same name and same effective number of layers (which in turn can be laid out differently in the respective LayerLists).
This provides greater flexibility when working with variable font project with sparse glyph sets.
previously we only reused the VarIndexBase of a previously seen variable table when the current's varIdxes were _fully_ equal to one of the previous; now we also try to find a match anywhere in the accummulated list of self.varIdxes, including a partial match at the tail of the list.
When multiple variable tables refer to the same delta-sets they can now share the same VarIndexBase so the resulting DeltaSetIndexMap is a bit smaller.
For simplicity, we only reuse VarIndexBase when variable tables fully share (ie. same, and same number of) varIdxes; potentially we could reuse subsets of varIdxes (e.g. a VarColoStop.Alpha has a +0.5 delta, and later on elsewhere a PaintVarSolid.Alpha has a similar +0.5 delta; the latter could have a VarIndexBase that reuses an existing DeltaSetIndexMap entry for the former), but for now this I think is good enough.
though we still emit the empty <Map index=.../> elements; they help identify chunks of delta-set indices, and define the length of the array upon loading from XML
This does two things:
Fixes forced-set computation, which was wrong in multiple ways.
Debugged it. Is solid now... Famous last words.
Speeds up DP time by limiting DP lookback length. For Noto Sans,
IUP time drops from 23s down to 9s, with only a slight size increase
in the final font. This basically turns the algorithm from O(n^3) into
O(n).
we tell GzipFile to write the MTIME field to zero so that the compressed output is reproducible and doesn't change depending on when the data is compressed.
Using svg.draw(pen) and parse_path() from svgLib threw exception
ValueError: could not convert string to float: 'a'
on a SVG <path> string generated by Inkscape. Altering the path
string might object to other string bits like 'Z' or 'v', or
give even stranger exceptions.
Finally tracked it down to the path containing particular valid
numbers like "-4e-5" or "1e-4". Changing these to "-4.0e-5" or
"1.0e-4" would stop the exceptions. The parse_path() was not
accepting valid SVG real numbers.
The specification for real number formats is a bit of a mess in
CSS land right now, but the reassuringly concrete spec is:
https://www.w3.org/TR/css-syntax-3/#number-token-diagram
which allows a real number having an exponent but without having
a fractional part, such as the number "1e3".
This change updates an RE to make fractional parts optional,
and adds a test for this valid SVG number format.
Missed this test in previous commit.
Test is testing that parsing extraction of individual parameters
works as specified when spaces are omitted. Such as signaled when
a new number is specified with a leading sign +/-
Test previously used
"M1-2A3-4-1.0 01.5.7",
where the first arc radius value was '3' and the second was '-4'.
Now that we are forcing radius values to be non-negative using abs()
the value returned in the test is not
("arcTo", (3.0, -4.0, -1.0, False, True, (0.5, 0.7))),
but rather
("arcTo", (3.0, 4.0, -1.0, False, True, (0.5, 0.7))),
Changed to expect the positive value, nicely the test continues to
test omitting spaces, but now also tests that negative radius values
are forced non-negative.
if explicitly enabled, it will raise ImportError if uharfbuzz is not found, and will propagate the uharfbuzz error instead of silently falling back to the pure-python serializer