Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f24a241

Browse filesBrowse files
committed
Rework mapping of dvi glyph indices to freetype indices.
In 89a7e19, an API for converting "dvi glyph indices" (as stored in a dvi file) to FreeType-compatible keys (either "indices into the native charmap" or "glyph names") was introduced. It was intended that end users (i.e., backends) would check the type of `text.glyph_name_or_index` ((A) int or (B) str) and load the glyph accordingly ((A) `FT_Set_Charmap(native_cmap); FT_Load_Char(index);` or (B) `FT_Load_Glyph(FT_Get_Name_Index(name));`); however, with the future introduction of {xe,lua}tex support, this kind of type checking becomes inconvenient, because {xe,lua}tex's "dvi glyph indices", which are directly equal to FreeType glyph indices (i.e. they would be loaded with `FT_Load_Glyph(index);`), would normally also be converted to ints. This PR introduces a new API (`_index_dvi_to_freetype`) to perform this mapping, always mapping to FreeType glyph indices (i.e. one can always just call `FT_Load_Glyph` on the result). To do so, in case (A) it loads itself the native charmap (something the end user needed to do by themselves previously) and performs the cmap-to-index conversion (`FT_Get_Char_Index`) previously implicit in `FT_Load_Char`; in case (B) it performs itself the name-to-index conversion (`FT_Get_Name_Index`). When {xe,lua}tex support is introduced in the future, `_index_dvi_to_freetype` will just return the index as is. Note that this API is intentionally kept private for now (even though it is used by textpath) and the old APIs are not deprecated yet; I intend to wait until {xe,lua}tex support is actually merged to do so, to avoid possible future back-and-forth changes on the public APIs.
1 parent b7e7663 commit f24a241
Copy full SHA for f24a241

File tree

2 files changed

+37
-21
lines changed
Filter options

2 files changed

+37
-21
lines changed

‎lib/matplotlib/dviread.py

Copy file name to clipboardExpand all lines: lib/matplotlib/dviread.py
+35-10Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232
import numpy as np
3333

34-
from matplotlib import _api, cbook
34+
from matplotlib import _api, cbook, font_manager
3535

3636
_log = logging.getLogger(__name__)
3737

@@ -579,7 +579,7 @@ class DviFont:
579579
Size of the font in Adobe points, converted from the slightly
580580
smaller TeX points.
581581
"""
582-
__slots__ = ('texname', 'size', '_scale', '_vf', '_tfm')
582+
__slots__ = ('texname', 'size', '_scale', '_vf', '_tfm', '_encoding')
583583

584584
def __init__(self, scale, tfm, texname, vf):
585585
_api.check_isinstance(bytes, texname=texname)
@@ -588,6 +588,7 @@ def __init__(self, scale, tfm, texname, vf):
588588
self.texname = texname
589589
self._vf = vf
590590
self.size = scale * (72.0 / (72.27 * 2**16))
591+
self._encoding = None
591592

592593
widths = _api.deprecated("3.11")(property(lambda self: [
593594
(1000 * self._tfm.width.get(char, 0)) >> 20
@@ -630,6 +631,35 @@ def _height_depth_of(self, char):
630631
hd[-1] = 0
631632
return hd
632633

634+
# TODO: Make this public when {xe,lua}tex support is merged; simultaneously
635+
# deprecate Text.glyph_name_or_index.
636+
def _index_dvi_to_freetype(self, idx):
637+
"""Convert dvi glyph indices to FreeType ones."""
638+
# Glyphs indices stored in the dvi file map to FreeType glyph indices
639+
# (i.e., which can be passed to FT_Load_Glyph) in various ways:
640+
# - if pdftex.map specifies an ".enc" file for the font, that file maps
641+
# dvi indices to Adobe glyph names, which can then be converted to
642+
# FreeType glyph indices with FT_Get_Name_Index.
643+
# - if no ".enc" file is specified, then the font must be a Type 1
644+
# font, and dvi indices directly index into the font's CharStrings
645+
# vector.
646+
# - (xetex & luatex, currently unsupported, can also declare "native
647+
# fonts", for which dvi indices are equal to FreeType indices.)
648+
if self._encoding is None:
649+
psfont = PsfontsMap(find_tex_file("pdftex.map"))[self.texname]
650+
if psfont.filename is None:
651+
raise ValueError("No usable font file found for {} ({}); "
652+
"the font may lack a Type-1 version"
653+
.format(psfont.psname.decode("ascii"),
654+
psfont.texname.decode("ascii")))
655+
face = font_manager.get_font(psfont.filename)
656+
if psfont.encoding:
657+
self._encoding = [face.get_name_index(name)
658+
for name in _parse_enc(psfont.encoding)]
659+
else:
660+
self._encoding = face._get_type1_encoding_vector()
661+
return self._encoding[idx]
662+
633663

634664
class Vf(Dvi):
635665
r"""
@@ -1023,8 +1053,7 @@ def _parse_enc(path):
10231053
Returns
10241054
-------
10251055
list
1026-
The nth entry of the list is the PostScript glyph name of the nth
1027-
glyph.
1056+
The nth list item is the PostScript glyph name of the nth glyph.
10281057
"""
10291058
no_comments = re.sub("%.*", "", Path(path).read_text(encoding="ascii"))
10301059
array = re.search(r"(?s)\[(.*)\]", no_comments).group(1)
@@ -1156,12 +1185,8 @@ def _print_fields(*args):
11561185
face = FT2Font(fontpath)
11571186
_print_fields("x", "y", "glyph", "chr", "w")
11581187
for text in group:
1159-
if psfont.encoding:
1160-
glyph_name = _parse_enc(psfont.encoding)[text.glyph]
1161-
else:
1162-
encoding_vector = face._get_type1_encoding_vector()
1163-
glyph_name = face.get_glyph_name(encoding_vector[text.glyph])
1164-
glyph_str = fontTools.agl.toUnicode(glyph_name)
1188+
glyph_str = fontTools.agl.toUnicode(
1189+
face.get_glyph_name(font._index_dvi_to_freetype(text.glyph)))
11651190
_print_fields(text.x, text.y, text.glyph, glyph_str, text.width)
11661191
if page.boxes:
11671192
print("--- BOXES ---")

‎lib/matplotlib/textpath.py

Copy file name to clipboardExpand all lines: lib/matplotlib/textpath.py
+2-11Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -239,17 +239,8 @@ def get_glyphs_tex(self, prop, s, glyph_map=None,
239239
if char_id not in glyph_map:
240240
font.clear()
241241
font.set_size(self.FONT_SCALE, self.DPI)
242-
glyph_name_or_index = text.glyph_name_or_index
243-
if isinstance(glyph_name_or_index, str):
244-
index = font.get_name_index(glyph_name_or_index)
245-
elif isinstance(glyph_name_or_index, int):
246-
if font not in t1_encodings:
247-
t1_encodings[font] = font._get_type1_encoding_vector()
248-
index = t1_encodings[font][glyph_name_or_index]
249-
else: # Should not occur.
250-
raise TypeError(f"Glyph spec of unexpected type: "
251-
f"{glyph_name_or_index!r}")
252-
font.load_glyph(index, flags=LoadFlags.TARGET_LIGHT)
242+
idx = text.font._index_dvi_to_freetype(text.glyph)
243+
font.load_glyph(idx, flags=LoadFlags.TARGET_LIGHT)
253244
glyph_map_new[char_id] = font.get_path()
254245

255246
glyph_ids.append(char_id)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.