When a subroutine contains no explicit hint stem operators (has_hint=False),
but it contains a hintmask operator which, in the context of the calling
charstring, would be understood as implying a vstemhm, then we need to set
has_hint=True on the subroutine, and update the last_hint index.
Otherwise, the drop_hints function leaves behind the arguments of the implicit
vstemhm operator.
This case is exemplified in the test font Tests/subset/data/Lobster.subset.ttx,
for charstrings "B" and "B.salt", and subroutine index="2".
--- /Users/cosimolupo/Documents/Github/fonttools/Tests/subset/data/expect_no_hinting_CFF.ttx
+++ /var/folders/jb/rjz76yw92w7144mwqg119jnm0000gn/T/tmpO_XOWh/tmp3.ttx
@@ -47,7 +47,7 @@
107 return
</CharString>
<CharString index="2">
- 230 636 rmoveto
+ 119 230 636 rmoveto
-136 -636 rlineto
144 hlineto
return
@@ -94,7 +94,7 @@
endchar
</CharString>
<CharString name="B">
- 187 -105 callsubr
+ 187 6 93 362 139 -119 101 -101 -105 callsubr
82 383 rlineto
2 18 20 1 8 hhcurveto
73 22 -57 -70 hvcurveto
@@ -109,7 +109,7 @@
endchar
</CharString>
<CharString name="B.salt">
- 185 -105 callsubr
+ 185 6 93 350 149 -119 105 -105 -105 callsubr
6 30 rlineto
-41 39 41 -17 39 hhcurveto
125 110 175 136 72 -32 62 -82 15 hvcurveto
_DehintingT2Decompiler now inherits from T2WidthExtractor, so we can save
the charstring width and insert it back after we dropp the hints.
This avoids the need to do an extra .draw() just for the sake of
extracting the width.
This is the same patch as PR #606
Quoting myself:
```
It seems that the horizontal advance of hinted charstrings gets lost when the CFF hinting is stripped with '--no-hinting' option...
T2CharString objects only get assigned a 'witdh' attribute after their 'draw' method is called.
The subsetter's drop_hints function attempts to insert the width back at the beginning of the de-hinted charstring's program, but can do that only if the charstring does have a 'width' attribute:
c63fea0f8f/Lib/fontTools/subset/__init__.py (L1928)
Hence, we must 'draw' the charstring (with a NullPen) before stripping the hints.
```
Now this method fixes the issue (advances are kept) when doing _both_ --no-hinting and --desubroutinize (the test_no_hinting_desubroutinize should now pass, while it was failing before).
However, when one only does does --no-hinting, this method raises an error:
AttributeError: 'NoneType' object has no attribute 'nominalWidthX'
Lib/fontTools/misc/psCharStrings.py:282: AttributeError
(this is reflected in the failing `test_no_hinting_CFF`)
We should probably use cliTools.makeOutputFileName here for consistency with ttx,
but I know some prefer the approach taken by pyftsubset so I don't want force this.
Howver, I find it a bit annoying that when one is too lazy (like me) to specify
the --output-file=, the subsetter outputs a file ending with an invalid ".subset" extension, which Finder or Windows Explorer don't recongize as a font, and so one has to rename it anyway.
This makes the '.subset' string is inserted between the file name and its original extension (if any).
The code in main() assumes that the first of the args which are not consumed by Options.parse_opts(args) is the positional argument (ie. does not start with '--') for the input font file, and that is what the usage() says too.
However I find it myself writing --options=... first, and then at the end the positional arguments, as is the convention for many other Unix tools.
This patch makes this possible, while also keeping the current behavior.
The convention is that sys.exit(...) is called only if a module is run as a script,
and that main() entry points use return statements to report exit codes: 0 (or None)
for successful execution, or any non-zero integer for errors.
E.g. see the console scripts generated when installing with pip.
If a module is run as script, as in `python module.py` or when using
`runpy.run_module()`, then __name__ == "__main__".
So when we instantiate modules' loggers with `logging.getLogger(__name__)`,
those loggers' name may become "__main__" when run as scripts, and hence
fall outside of the "fontTools" logging namespace.
fontTools.configureLogger() by default only configures the "fontTools"
library loggers, anything outside of it (e.g. logger called "__main__")
is not attached a handler.
So here I name loggers explicitly instead of relying on __name__, but
only for modules which can be run as "__main__".
Fixes#801
API Change:
This will change XML output for GSUB/GPOS/GDEF/MATH/BASE/JSTF/...
Scripts that set the Version for those to 1.0 or other float values
also need fixing. A warning is emitted when code or XML needs fix.
Fixed encoding error in subset tool in Windows which system default codepage isn't 65001.
For Example:
When windows default codepage is 936, the command like 'pyftsubset myfont.ttf --text-file=mytextfile.txt' will throw an exception.
'canonical_order' default value was set to False in the subsetter. However,
the meaning of the related 'reorderTables' argument in TTFont.save method has changed
with commit 6ba67ab699d62962690a7a523c286ebf0c8b0ae4.
When the latter is set to False, the original input font's table order is "kept": which
still means doing some sort of reordering. If one wishes to avoid any kind of reordering,
reorderTables needs to be set to None.
The Subsetter class now uses a module-level 'log', and no longer uses
its own custom Logger. This has been removed, and its features replaced
by equivalents.
log.lapse() are replaced with Timer context manager/decorator (these should make clearer where the elapsed time starts/stops);
log.glyphs() is kept for convenience: it is bound dynamically to the logger instance instead of subclassing logging.Logger, as it's only
useful in here.
log.font() is replaced by `font.saveXML(sys.stdout)`.
A distinct sub-logger is configured for timing messages, to allow --timing option to be enabled independently from --verbose
As needed in my Monotype OpenType format parser. I'm not using the object
directly from subset module, but pushing back my changes here, in the hope
that we move this object to ttLib proper soon.
Add support for subsetting COLR table.
The CPAL table does not need subsetting, but unused palettes should be
pruned, this is not implemented however as it depends on COLR table,
which in turn will not be updated after pruning CPAL.