Skip to content

Commit c77a459

Browse files
committed
Use one font descriptor for each Type-1 font
The old optimization where the same font file and descriptor could be shared by multiple differently-encoded fonts is wrong in the presence of subsetting, unless we also take the exact glyph subset into account. It is very unlikely for the exact same subset to be used by different encodings, so just remove the optimization. Rearrange _embedTeXFont in neater blocks.
1 parent 53355ca commit c77a459

File tree

1 file changed

+11
-21
lines changed

1 file changed

+11
-21
lines changed

lib/matplotlib/backends/backend_pdf.py

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -722,8 +722,6 @@ def __init__(self, filename, metadata=None):
722722
self._internal_font_seq = (Name(f'F{i}') for i in itertools.count(1))
723723
self._fontNames = {} # maps filenames to internal font names
724724
self._dviFontInfo = {} # maps dvi font names to embedding information
725-
# differently encoded Type-1 fonts may share the same descriptor
726-
self._type1Descriptors = {}
727725
self._character_tracker = _backend_pdf_ps.CharacterTracker()
728726

729727
self.alphaStates = {} # maps alpha values to graphics state objects
@@ -767,8 +765,6 @@ def __init__(self, filename, metadata=None):
767765

768766
fontNames = _api.deprecated("3.11")(property(lambda self: self._fontNames))
769767
dviFontInfo = _api.deprecated("3.11")(property(lambda self: self._dviFontInfo))
770-
type1Descriptors = _api.deprecated("3.11")(
771-
property(lambda self: self._type1Descriptors))
772768

773769
def newPage(self, width, height):
774770
self.endStream()
@@ -1005,48 +1001,42 @@ def _embedTeXFont(self, fontinfo):
10051001
_log.debug('Embedding TeX font %s - fontinfo=%s',
10061002
fontinfo.dvifont.texname, fontinfo.__dict__)
10071003

1008-
# Font dictionary
1004+
# The font dictionary is the top-level object describing a font
10091005
fontdictObject = self.reserveObject('font dictionary')
10101006
fontdict = {
10111007
'Type': Name('Font'),
10121008
'Subtype': Name('Type1'),
10131009
}
10141010

1015-
# We have a font file to embed - read it in and apply any effects
1011+
# Read the font file and apply any encoding changes and effects
10161012
t1font = _type1font.Type1Font(fontinfo.fontfile)
10171013
if fontinfo.encodingfile is not None:
10181014
t1font = t1font.with_encoding(
10191015
{i: c for i, c in enumerate(dviread._parse_enc(fontinfo.encodingfile))}
10201016
)
1021-
10221017
if fontinfo.effects:
10231018
t1font = t1font.transform(fontinfo.effects)
1019+
1020+
# Reduce the font to only the glyphs used in the document, get the encoding
1021+
# for that subset, and compute various properties based on the encoding.
10241022
chars = frozenset(self._character_tracker.used[fontinfo.dvifont.fname])
10251023
t1font = t1font.subset(chars, self._get_subset_prefix(chars))
10261024
fontdict['BaseFont'] = Name(t1font.prop['FontName'])
1025+
# createType1Descriptor writes the font data as a side effect
1026+
fontdict['FontDescriptor'] = self.createType1Descriptor(t1font)
10271027
encoding = t1font.prop['Encoding']
1028+
fontdict['Encoding'] = self._generate_encoding(encoding)
10281029
fc = fontdict['FirstChar'] = min(encoding.keys(), default=0)
10291030
lc = fontdict['LastChar'] = max(encoding.keys(), default=255)
1030-
fontdict['Encoding'] = self._generate_encoding(encoding)
1031-
# Font descriptors may be shared between differently encoded
1032-
# Type-1 fonts, so only create a new descriptor if there is no
1033-
# existing descriptor for this font.
1034-
effects = (fontinfo.effects.get('slant', 0.0),
1035-
fontinfo.effects.get('extend', 1.0))
1036-
fontdesc = self._type1Descriptors.get((fontinfo.fontfile, effects))
1037-
if fontdesc is None:
1038-
fontdesc = self.createType1Descriptor(t1font)
1039-
self._type1Descriptors[(fontinfo.fontfile, effects)] = fontdesc
1040-
fontdict['FontDescriptor'] = fontdesc
1041-
1042-
# Use TeX Font Metrics file to get glyph widths (TeX uses its 12.20 fixed point
1043-
# representation and we want 1/1000 text space units)
1031+
1032+
# Convert glyph widths from TeX 12.20 fixed point to 1/1000 text space units
10441033
tfm = fontinfo.dvifont._tfm
10451034
widths = [(1000 * metrics.tex_width) >> 20
10461035
if (metrics := tfm.get_metrics(char)) else 0
10471036
for char in range(fc, lc + 1)]
10481037
fontdict['Widths'] = widthsObject = self.reserveObject('glyph widths')
10491038
self.writeObject(widthsObject, widths)
1039+
10501040
self.writeObject(fontdictObject, fontdict)
10511041
return fontdictObject
10521042

0 commit comments

Comments
 (0)