90 Commits

Author SHA1 Message Date
ReadRoberts
77f72bc62b Convert OTF font files in test data to ttx files.
This required a fix to fontTools/cffLib. When reading a CFF2 variable font (VF) from XML, the VF state in FontDict and PrivateDict does not get set. I made a temporary fix by adding a loop to set PrivateDict.vstore for all the PrivateDict objects after the XML file has been read. This should not be necessary, and in the near future I will revisit both this issue, and the related use of isCFF2 when compiling/decompiling.
2019-05-01 16:01:43 -07:00
Read Roberts
5b3db36670
Sparse cff2vf support (#1591)
* Added getter (in the form of a property decorator) for T2Charstring.vsindex. Fixes endless compile loop in some circumstances.

Fixed bug in mutator: need to remove vsindex from snapshotted charstrings, plus formatting clean up

* Fix for subsetting HVAR tables that have an AdvanceWidthMap when the --retain-gid option is used. Needed to make subset_test.py::test_retain_gids_cff2 tests pass.

* in varLib/cffLib.py, add support for sparse sources, and sources with more than one model, and hence more than one VarData element in the VarStore.

CFF2 source fonts with multiple FontDicts in the FDArray need some extra work. With sparse fonts, some of the source fonts may have a fewer FontDicts than the default font. The getfd_map function() builds a map from the FontDict indices in the default font to those in each region font. This is needed when building up the blend value lists in the master font FontDict PrivateDicts, in order to fetch PrivateDict values from the correct FontDict in each region font.

In specializer.py, add support for CFF2 CharStrings with blend operators. 1) In generalizeCommands, convert a blend op to a list of args that are blend lists for the following regular operator. A blend list as a default font value, followed by the delta tuple. 2) In specializeCommands(), convert these back to blend ops, combining as many successive blend lists as allowed by the stack limit.

Add test case for sparse CFF2 sources.
The test font has 55 glyphs. 2 glyphs use only 2 sources (weight = 0 and 100). The rest use 4 source fonts: the two end points of the weight axis, and two intermediate masters. The intermediate masters are only 1 design space unit apart, and are used to change glyph design at the point in design space. For the rest, at most 2 glyphs use the same set of source fonts. There are 12 source fonts.

Add test case for specializer programToCommands() and commandsToProgram by converting each CharString.program in the font to a command list, and back again, and comparing original and final versions.
2019-04-26 09:33:52 -07:00
Miguel Sousa
ddff29cb5d Fix DeprecationWarning: invalid escape sequence 2019-04-01 14:04:14 -07:00
Cosimo Lupo
8e8da97a4c [cffLib]: add clear() method to Index class to empty in-place 2019-02-07 01:58:22 +01:00
Nikolaus Waxweiler
a8d4bfc42d Replace PrivateDict.__getattr__ with property
The dunder method doesn't seem to be doing anything other than providing
an `in_cff2` attribute. Do that with a property instead of bending
__getattr__.

This one confused me when I was working on
https://github.com/fonttools/fonttools/pull/1488.
2019-02-06 10:15:38 +00:00
Cosimo Lupo
649dc49dba [cffLib] Fix RecursionError in BaseDict.__getattr__ when unpickling
We need to raise AttributeError for non-existing dunder methods like
'__deepcopy__' or '__getstate__', because deepcopy() and pickle.load()
test for these on the instance using getattr() and treat the resulting
AttributeError as a signal that the object doesn't implement these custom
hooks. If we don't do that, we enter an infinite recursion as we attempt
to look up the missing dunder methods in the 'rawDict' dictionary,
because 'rawDict' is set inside __init__, but __init__ is not invoked
while unpickling (only __new__ is); thus self.rawDict is also missing
and __getattr__ is invoked with argument 'rawDict' again and again until
it crashes with RecursionError. Phew.

Fixes https://github.com/fonttools/fonttools/pull/1488
2019-02-06 01:05:11 +01:00
justvanrossum
612992f266 fixing #1426 2019-01-02 17:29:48 +01:00
ReadRoberts
0586c06199 [varLib subset CFF2] Set PrivateDict nominal and default WidthX to None
@bedhad
Address issues raised in #1403

I do think setting the dummy CFF2 PrivateDict nominalWidthX and defaultWidthX to None, which leads to the charstring.width also being None,  is a good idea. I originally set them to 0, which produces a charstring width of 0, in order to avoid problems with logic that assumes that the field is good for math. However, I now think that it is better to find errors around charstring type assumptions earlier than later.

 "drop_hints()" is actually not wrong - I did look at this when making the changes. For CFF2 charstrings, self.width is always equal to self.private.defaultWidthX, so the width is never inserted. This is because in psCharstrings.py::T2WidthExtractor.popallWidth(), the test "evenOdd ^ (len(args) % 2)" is alway False.  Left to myself, I would not change this code. If the CFF2 charstring is correct, there is not a problem. if the CFF2 charstring is not correct, then both in drop_hints() and in T2WidthExtractor.popallWidth(), the logic will stack dump. I did add asserts, but am not totally sure it is worth the extra calls.
2018-12-06 11:55:48 -08:00
Behdad Esfahbod
93633a85ef [CFF] Move variations-specific CFF code to varLib.cff module 2018-12-04 19:22:02 -08:00
ReadRoberts
1f2600ff65 [cff2] Add subset.cff functions for CFF/CFF2 class:
desubroutinize
remove_hints
remove_unused_subroutines

Fix issue in cff2mergePen.py because of  removing CFFS2Subrs class in prior commit.
2018-12-04 18:34:22 -08:00
ReadRoberts
61c213d0ff [cffLib] clean up isCFF2 in psCharStrings
Removed check_program functions. Supporting these requires knowledge of CFF vs CFF2 state, whci is leads to wide-spread diffuse changes. Also, not needed - the endchar/return opcodes are removed when compiling for CFF2.

Removed CFF2Subr class. This was used for CFF2 CharStrings, and allowed avoiding referencing the width fields. I worked around this by providing dummy values for the Private.nominalWidthX and defaultWidthX.

Added a public method PrivateDict.in_cff2.
2018-12-04 15:31:55 -08:00
Behdad Esfahbod
31019eac8e [CFF] Whitespace 2018-11-30 21:46:16 -05:00
ReadRoberts
ad8130e1a4 [varlib] Remove path compatiblization logic from CFF2CharStringMergePen
Agreed that paths glyphs form source fonts shoudl be fully compatible before varLib.build is called.

Updated test files
2018-11-29 15:07:08 -08:00
ReadRoberts
c5def97cd8 varLib. replace slower pointsDiffer() with models.AllEqual() 2018-11-19 17:38:52 -08:00
ReadRoberts
c118bd205e varLib. Move CFF2CharStringMergePen-specific logic out of specializer.py
- restore specializer.py:commandsToProgram to original simple code
- handle blend arguments in command list with CFF2CharStringMergePen method.
2018-11-19 17:30:53 -08:00
ReadRoberts
a460eee80b varLib. Add support for building CFF2 variable font
Fix syntax error reported by build system: can't mix string string types when doing literal concatenation

Fix local import reference - doesn't work in Python3.

Addressed issues raised by @msousa for PR 1345 yesterday.

Will change cff2_merge_funcs.py and cff2mergePen.py from tab to space indentations after the current comments are resolved.

Add various improvements from comments:
- do not edit the post table under varLib.build(). Setting post table format 2 or 3 is now expected to be managed by whatever calls varLib.build().
- In the t2CharStringPen module, rename closure _round() nested in makeRoundFunc to an exportable function, and use it in cff2mergePen.
- remove TypeSupply copyright from cff2mergePen.
- use modulo function to convert float to int when it is meant to be 0 in cff2mergePen.

cff2_merge_funcs.py:merge_PrivateDicts() should only be blending the hint related fields in the PrivateDict. This oversight that was surfaced by @madig reporting an error building his Cantrell font. The bug appeared when the font was subroutinized, as the pen draw method then has to interpret the Subr field in order to access T2Charstring subroutines.

Fix expected ttx output file. When I removed the logic to add glyph names to the post table, glyph names in the ttx file changed.

Miguel prefers a simple list for readability in cff2_merge_funs.py:138.
2018-11-12 11:38:18 -08:00
ReadRoberts
5a32da5ee6 varLib. Add support for building CFF2 variable font with a call to varLib.build().
Fix specializer.py:commandToProgram(); I had made the required args incompatible with the prior version.
2018-11-12 11:38:04 -08:00
ReadRoberts
9626cfe15b varLib. Add support for building CFF2 variable font with a call to varLib.build().
Add support functions for merging CFF tables into a CFF2 table.
2018-11-12 11:37:47 -08:00
ReadRoberts
08aef71458 varLib. Add support for building CFF2 variable font with a call to varLib.build().
Add support for the blend operator and arguments in commandsToProgram, and specializeCommands().
2018-11-12 11:37:40 -08:00
Cosimo Lupo
3734b6c036
cffLib/specializer: minor; use < instead of <= maxstack - 1 2018-07-25 11:56:32 +01:00
Kunihiko Sakamoto
41a21cce27 [cffLib.specializer] Leave 1 stack free area for subroutinizer use 2018-07-25 17:29:27 +09:00
ReadRoberts
c239d1a03d
[cffLib] Fix bug in cffLib.py.CFFFontSet.convertCFFToCFF2() that broke converting name-keyed fonts.
Also clean up setting FontDict to support CFF2.
2018-06-11 12:09:00 +01:00
ReadRoberts
528bc8ff17
[cffLib] Use std operator delattr() instead of exec ("del ...") 2018-06-11 12:09:00 +01:00
ReadRoberts
942a7610fd
[cffLib] Fix bugs in converting CFF to CFF2 when the font has an FDArray.
The FontDict as well as the PrivateDict needs to have fields removed when these are deprecated in CFF2.
2018-06-11 12:09:00 +01:00
ReadRoberts
21bbb15cd0
[cffLib] Fix bugs in compiling a CFF2 font with an FDArray.
A FontDict in CFF2 is permitted only a subset of the fields supported by CFF 1.0.
2018-06-11 12:09:00 +01:00
derwind
66be456e62 [cffLib] restore try... finally... block 2018-02-23 02:22:57 +09:00
derwind
e5985ab63e [cffLib] reimplement SimpleConverter which is ready for lazy-loads and now all Converters are derived from it. 2018-02-23 02:01:35 +09:00
derwind
b9eb1b235f [cffLib] another implementation: prevent *Converter.read from changing file positions 2018-02-23 01:03:37 +09:00
derwind
91fc3c5c41 [cffLib] prevent *Converter.read from changing file positions 2018-02-22 22:46:46 +09:00
derwind
d0b4c4b360 [cffLib] save file position against lazy-load of charset 2018-02-22 02:00:09 +09:00
Behdad Esfahbod
a07a6f85f7 [cffLib.specializer] Try keeping type of args
41445b8449 (commitcomment-22260340)
2018-02-18 11:48:22 -08:00
Behdad Esfahbod
948361f981 [cffLib.width] Fix for py3 2018-02-10 16:27:25 -06:00
Behdad Esfahbod
0394016ba9 [CFF] Fixups for width module 2018-02-08 22:15:03 -06:00
Behdad Esfahbod
a70bca61fe [cff] Add module to calculate optimal CFF default and nominal glyph widths
Fixes https://github.com/typesupply/ufo2fdk/issues/34
2018-02-08 21:50:57 -06:00
Behdad Esfahbod
4fec016862 [cff] Fix calcBound when seac-like components happen in endchar
I'm also unimpressed by the copy-pasted bounds logic in hhea and vhea,
and the fact that that's coded in there instead of calling a function
on CFF / glyf tables respectively.
2018-01-26 17:41:53 -08:00
Behdad Esfahbod
f82128f25d Kill progress argument
Fixes https://github.com/fonttools/fonttools/issues/1008

Doesn't touch xmlReader / xmlWriter modules.
2018-01-25 17:30:23 -08:00
ReadRoberts
83379be568 CFF2 Subr items can have values on the stack after the last operator. These were not getting written to XML. Added new class CFFSubr so that we can make an assertion error in this case if the item is not a CFF2 Subr, and otherwise write the last values on the stack to the XML file 2017-11-02 11:36:10 -07:00
ReadRoberts
8b02b5a294 Fixed issue with reading/writing PrivateDict BlueValues to ttx file. To date, BlueValue arguments have been written as absolute coordinate values, reflecting the history of the CFF ttx table format. However, Behdad Esfahbod pointed out that it is not always possible to roundtrip between the absolute values in the ttx file and the CFF2 default font value and the delta list. This update changes the ttx format so that in PrivateDict BlueValues, the default font values are written as absolute coordinates, preserving continuity with how CFF tables are written, but the region values are written as the deltas from the VariationStore delta list.
This also fixes fonttools/fonttools/issues/1030.

Although the roundtrip is generally possible when a VariationStore is built from source font data using the Superpolator model, it is possible to  build  region definitions that do not follow this model. Behdad cited the Skia "Q" example, where the tail of the Q is affected by two regions defined as:
min=0 peak=0.5 max=0.51 delta=+10
min=0.49 peak=0.5 max=0.51 delta=-10
2017-11-02 11:31:47 -07:00
Masaya Nakamura
3708f2c8d3 Don't cache charString bounds
https://github.com/fonttools/fonttools/pull/970#discussion_r117903692
2017-08-01 10:54:47 +09:00
Masaya Nakamura
22dfcd94a1 [cffLib] Use None instead of initialBounds
https://github.com/fonttools/fonttools/pull/970#discussion_r117621101
2017-08-01 10:53:29 +09:00
Masaya Nakamura
b22b59f730 [cffLib] Use intRect() for FontBBox rounding
AFDKO seems to calculate bounds and side bearings in this manner.
2017-08-01 10:51:47 +09:00
Masaya Nakamura
b84ee6744d [cffLib] Recalc CFF's FontBBox when compiling 2017-08-01 10:51:47 +09:00
Cosimo Lupo
dca96c9c55 [cffLib] get TopDict by index as well as by name
There can only be one TopDict in an OpenType font, whether CFF or CFF2;
plus in the latter, TopDict INDEX and Names INDEX are gone, just the
one TopDict is left. Most of the time, one simple wants to get to
that single TopDict instance.

So instead of doing this:

topDict = font['CFF '].cff.values()[0]

one can alternatively do this now:

topDict = font['CFF '].cff[0]
2017-07-26 18:53:42 +01:00
Cosimo Lupo
72baa5a7d5 [cffLib/psCharStrings] remove cffCtx, pass down isCFF2
* Removed `CFFContext`
* Added `isCFF2` argument to CFFFontSet.decompile/compile, used from
  respective ttLib classes
* Index classes get a `isCFF2` argument in constructor (used for
  decompiling); must be True/False if `file` argument is not None;
  it is stored as self._isCFF2 to support lazy loading
* Removed `TopDictData` class; reuse same `TopDictIndexCompiler` for
  both CFF and CFF2
* `CFFWriter` and all `*Compiler` classes get an `isCFF2` argument;
  defaults to the parent compiler's `isCFF2` attribute
* Removed `size` argument from `produceItem` method as unused and
  useless (`len(data)` is the same)
* psCharStrings: removed useless ByteCodeBase class
* A reference to the TopDict's VarStoreData is passed down to all
  the FontDicts' PrivateDict, so it can be used to get the number of
  regions while decompiling blend and vsindex operators

See dicussion:
https://github.com/fonttools/fonttools/pull/968#issuecomment-309920007
2017-07-19 18:18:58 +01:00
Cosimo Lupo
93e19e36bf cffLib: whitespace, removed unused variables, and other PEP8 fixes 2017-07-10 10:47:20 +01:00
Cosimo Lupo
83d983545f cffLib: use @property getter/setter for isCFF2 2017-07-10 10:47:20 +01:00
ReadRoberts
1a6c2fe191 Delete recursive setting of self.cffCtx.isCFF2; this is not needed, since this field is now gets its value from self.major, which is already set. 2017-06-20 16:23:52 -07:00
ReadRoberts
133fe84012 Fix bug in compiling FDSelect: wasn’t passing cffCtx to class initializer. 2017-06-20 16:23:52 -07:00
ReadRoberts
af23a781e4 Removed global state from cffLib.py; introduced instance-specific context class instead. Also deprecated maxstack operator, per OpenType spec update 1.8.1, as this simplified some of the context passing logic. Still not thoroughly tested; convertCFFToCFF2() function has not yet been updated to work with new logic. 2017-06-20 16:23:52 -07:00
ReadRoberts
8e723e48db Eliminated duplicate or unused functions from TopDictIndex 2017-06-20 16:23:52 -07:00