From cc744f54214c322876d7c15bfc8e831c7550ebc5 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Tue, 6 Nov 2018 12:23:13 +0100 Subject: [PATCH] Warn on FreeType missing glyphs. --- lib/matplotlib/backends/backend_pdf.py | 10 ++++++++-- src/ft2font.cpp | 23 ++++++++++++++++++++--- src/ft2font_wrapper.cpp | 4 ++-- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py index d046b0cf42b7..086bd96c2265 100644 --- a/lib/matplotlib/backends/backend_pdf.py +++ b/lib/matplotlib/backends/backend_pdf.py @@ -16,6 +16,7 @@ import sys import time import types +import warnings import zlib import numpy as np @@ -937,8 +938,13 @@ def get_char_width(charcode): s, flags=LOAD_NO_SCALE | LOAD_NO_HINTING).horiAdvance return cvt(width) - widths = [get_char_width(charcode) - for charcode in range(firstchar, lastchar+1)] + with warnings.catch_warnings(): + # Ignore 'Required glyph missing from current font' warning + # from ft2font: here we're just builting the widths table, but + # the missing glyphs may not even be used in the actual string. + warnings.filterwarnings("ignore") + widths = [get_char_width(charcode) + for charcode in range(firstchar, lastchar+1)] descriptor['MaxWidth'] = max(widths) # Make the "Differences" array, sort the ccodes < 255 from diff --git a/src/ft2font.cpp b/src/ft2font.cpp index e2fc3b818193..b5306de0b5af 100644 --- a/src/ft2font.cpp +++ b/src/ft2font.cpp @@ -8,6 +8,7 @@ #include "ft2font.h" #include "mplutils.h" +#include "py_exceptions.h" #ifndef M_PI #define M_PI 3.14159265358979323846264338328 @@ -162,9 +163,24 @@ FT2Image::draw_rect_filled(unsigned long x0, unsigned long y0, unsigned long x1, inline double conv(long v) { - return double(v) / 64.0; + return v / 64.; } +static FT_UInt ft_get_char_index_or_warn(FT_Face face, FT_ULong charcode) +{ + FT_UInt glyph_index = FT_Get_Char_Index(face, charcode); + if (!glyph_index) { + PyErr_WarnFormat(NULL, 1, "Glyph %lu missing from current font.", charcode); + // Apparently PyErr_WarnFormat returns 0 even if the exception propagates + // due to running with -Werror, so check the error flag directly instead. + if (PyErr_Occurred()) { + throw py::exception(); + } + } + return glyph_index; +} + + int FT2Font::get_path_count() { // get the glyph as a path, a list of (COMMAND, *args) as described in matplotlib.path @@ -610,7 +626,7 @@ void FT2Font::set_text( FT_BBox glyph_bbox; FT_Pos last_advance; - glyph_index = FT_Get_Char_Index(face, codepoints[n]); + glyph_index = ft_get_char_index_or_warn(face, codepoints[n]); // retrieve kerning distance and move pen position if (use_kerning && previous && glyph_index) { @@ -663,7 +679,8 @@ void FT2Font::set_text( void FT2Font::load_char(long charcode, FT_Int32 flags) { - int error = FT_Load_Char(face, (unsigned long)charcode, flags); + FT_UInt glyph_index = ft_get_char_index_or_warn(face, (FT_ULong)charcode); + int error = FT_Load_Glyph(face, glyph_index, flags); if (error) { throw std::runtime_error("Could not load charcode"); diff --git a/src/ft2font_wrapper.cpp b/src/ft2font_wrapper.cpp index a90c7b115e0e..3ebaffffb9d2 100644 --- a/src/ft2font_wrapper.cpp +++ b/src/ft2font_wrapper.cpp @@ -998,8 +998,8 @@ static PyObject *PyFT2Font_get_char_index(PyFT2Font *self, PyObject *args, PyObj const char *PyFT2Font_get_sfnt__doc__ = "get_sfnt(name)\n" "\n" - "Get all values from the SFNT names table. Result is a dictionary whose" - "key is the platform-ID, ISO-encoding-scheme, language-code, and" + "Get all values from the SFNT names table. Result is a dictionary whose " + "key is the platform-ID, ISO-encoding-scheme, language-code, and " "description.\n"; static PyObject *PyFT2Font_get_sfnt(PyFT2Font *self, PyObject *args, PyObject *kwds)