diff --git a/lib/matplotlib/_afm.py b/lib/matplotlib/_afm.py index 3d7f7a44baca..af607b0374fc 100644 --- a/lib/matplotlib/_afm.py +++ b/lib/matplotlib/_afm.py @@ -478,10 +478,18 @@ def get_angle(self) -> float: """Return the fontangle as float.""" return self._header['ItalicAngle'] + def get_ascender(self) -> float: + """Return the ascent as float.""" + return self._header['Ascender'] + def get_capheight(self) -> float: """Return the cap height as float.""" return self._header['CapHeight'] + def get_descender(self) -> float: + """Return the descent as float.""" + return self._header['Descender'] + def get_xheight(self) -> float: """Return the xheight as float.""" return self._header['XHeight'] diff --git a/lib/matplotlib/backends/_backend_pdf_ps.py b/lib/matplotlib/backends/_backend_pdf_ps.py index 83a8566517a7..a06779b8efee 100644 --- a/lib/matplotlib/backends/_backend_pdf_ps.py +++ b/lib/matplotlib/backends/_backend_pdf_ps.py @@ -348,6 +348,32 @@ def get_canvas_width_height(self): # docstring inherited return self.width * 72.0, self.height * 72.0 + def _get_font_height_metrics(self, prop): + """ + Return the ascent, descent, and line gap for font described by *prop*. + + TODO: This is a temporary method until we design a proper API for the backends. + + Parameters + ---------- + prop : `.font_manager.FontProperties` + The properties describing the font to measure. + + Returns + ------- + ascent, descent, line_gap : float or None + The ascent, descent and line gap of the determined font, or None to fall + back to normal measurements. + """ + if not mpl.rcParams[self._use_afm_rc_name]: + return None, None, None + font = self._get_font_afm(prop) + scale = prop.get_size_in_points() / 1000 + a = font.get_ascender() * scale + d = -font.get_descender() * scale + g = (a + d) * 0.2 # Preserve previous line spacing of 1.2. + return a, d, g + def get_text_width_height_descent(self, s, prop, ismath): # docstring inherited if ismath == "TeX": diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pdf/pdf_use14corefonts.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pdf/pdf_use14corefonts.pdf index 5cdc2e34e25d..b7dbb9adec70 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_backend_pdf/pdf_use14corefonts.pdf and b/lib/matplotlib/tests/baseline_images/test_backend_pdf/pdf_use14corefonts.pdf differ diff --git a/lib/matplotlib/text.py b/lib/matplotlib/text.py index f6ea6673ff0f..9c6478f9c7df 100644 --- a/lib/matplotlib/text.py +++ b/lib/matplotlib/text.py @@ -437,22 +437,29 @@ def _get_layout(self, renderer): dpi = self.get_figure(root=True).dpi # Determine full vertical extent of font, including ascenders and descenders: if not self.get_usetex(): - font = get_font(fontManager._find_fonts_by_props(self._fontproperties)) - possible_metrics = [ - ('OS/2', 'sTypoLineGap', 'sTypoAscender', 'sTypoDescender'), - ('hhea', 'lineGap', 'ascent', 'descent') - ] - for table_name, linegap_key, ascent_key, descent_key in possible_metrics: - table = font.get_sfnt_table(table_name) - if table is None: - continue - # Rescale to font size/DPI if the metrics were available. - fontsize = self._fontproperties.get_size_in_points() - units_per_em = font.get_sfnt_table('head')['unitsPerEm'] - line_gap = table[linegap_key] / units_per_em * fontsize * dpi / 72 - min_ascent = table[ascent_key] / units_per_em * fontsize * dpi / 72 - min_descent = -table[descent_key] / units_per_em * fontsize * dpi / 72 - break + if hasattr(renderer, '_get_font_height_metrics'): + # TODO: This is a temporary internal method call (for _backend_pdf_ps to + # support AFM files) until we design a proper API for the backends. + min_ascent, min_descent, line_gap = renderer._get_font_height_metrics( + self._fontproperties) + if min_ascent is None: + font = get_font(fontManager._find_fonts_by_props(self._fontproperties)) + possible = [ + ('OS/2', 'sTypoLineGap', 'sTypoAscender', 'sTypoDescender'), + ('hhea', 'lineGap', 'ascent', 'descent') + ] + for table_name, linegap_key, ascent_key, descent_key in possible: + table = font.get_sfnt_table(table_name) + if table is None: + continue + # Rescale to font size/DPI if the metrics were available. + fontsize = self._fontproperties.get_size_in_points() + units_per_em = font.get_sfnt_table('head')['unitsPerEm'] + scale = 1 / units_per_em * fontsize * dpi / 72 + line_gap = table[linegap_key] * scale + min_ascent = table[ascent_key] * scale + min_descent = -table[descent_key] * scale + break if None in (min_ascent, min_descent): # Fallback to font measurement. _, h, min_descent = _get_text_metrics_with_cache(