Skip to content

Simplify/improve error reporting from ft2font. #30102

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 27 additions & 81 deletions src/ft2font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,26 +43,6 @@

FT_Library _ft2Library;

// FreeType error codes; loaded as per fterror.h.
static char const* ft_error_string(FT_Error error) {
#undef __FTERRORS_H__
#define FT_ERROR_START_LIST switch (error) {
#define FT_ERRORDEF( e, v, s ) case v: return s;
#define FT_ERROR_END_LIST default: return NULL; }
#include FT_ERRORS_H
}

void throw_ft_error(std::string message, FT_Error error) {
char const* s = ft_error_string(error);
std::ostringstream os("");
if (s) {
os << message << " (" << s << "; error code 0x" << std::hex << error << ")";
} else { // Should not occur, but don't add another error from failed lookup.
os << message << " (error code 0x" << std::hex << error << ")";
}
throw std::runtime_error(os.str());
}

FT2Image::FT2Image(unsigned long width, unsigned long height)
: m_buffer((unsigned char *)calloc(width * height, 1)), m_width(width), m_height(height)
{
Expand Down Expand Up @@ -237,26 +217,16 @@
kerning_factor(0)
{
clear();

FT_Error error = FT_Open_Face(_ft2Library, &open_args, 0, &face);
if (error) {
throw_ft_error("Can not load face", error);
}

// set a default fontsize 12 pt at 72dpi
error = FT_Set_Char_Size(face, 12 * 64, 0, 72 * (unsigned int)hinting_factor, 72);
if (error) {
FT_Done_Face(face);
throw_ft_error("Could not set the fontsize", error);
}

FT_CHECK(FT_Open_Face, _ft2Library, &open_args, 0, &face);
if (open_args.stream != nullptr) {
face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM;
}

FT_Matrix transform = { 65536 / hinting_factor, 0, 0, 65536 };
FT_Set_Transform(face, &transform, nullptr);

try {
set_size(12., 72.); // Set a default fontsize 12 pt at 72dpi.
} catch (...) {

Check warning on line 226 in src/ft2font.cpp

View check run for this annotation

Codecov / codecov/patch

src/ft2font.cpp#L226

Added line #L226 was not covered by tests
FT_Done_Face(face);
throw;
}

Check warning on line 229 in src/ft2font.cpp

View check run for this annotation

Codecov / codecov/patch

src/ft2font.cpp#L228-L229

Added lines #L228 - L229 were not covered by tests
// Set fallbacks
std::copy(fallback_list.begin(), fallback_list.end(), std::back_inserter(fallbacks));
}
Expand Down Expand Up @@ -293,11 +263,9 @@

void FT2Font::set_size(double ptsize, double dpi)
{
FT_Error error = FT_Set_Char_Size(
FT_CHECK(
FT_Set_Char_Size,
face, (FT_F26Dot6)(ptsize * 64), 0, (FT_UInt)(dpi * hinting_factor), (FT_UInt)dpi);
if (error) {
throw_ft_error("Could not set the fontsize", error);
}
FT_Matrix transform = { 65536 / hinting_factor, 0, 0, 65536 };
FT_Set_Transform(face, &transform, nullptr);

Expand All @@ -311,17 +279,12 @@
if (i >= face->num_charmaps) {
throw std::runtime_error("i exceeds the available number of char maps");
}
FT_CharMap charmap = face->charmaps[i];
if (FT_Error error = FT_Set_Charmap(face, charmap)) {
throw_ft_error("Could not set the charmap", error);
}
FT_CHECK(FT_Set_Charmap, face, face->charmaps[i]);
}

void FT2Font::select_charmap(unsigned long i)
{
if (FT_Error error = FT_Select_Charmap(face, (FT_Encoding)i)) {
throw_ft_error("Could not set the charmap", error);
}
FT_CHECK(FT_Select_Charmap, face, (FT_Encoding)i);
}

int FT2Font::get_kerning(FT_UInt left, FT_UInt right, FT_Kerning_Mode mode,
Expand Down Expand Up @@ -477,10 +440,10 @@
if (!was_found) {
ft_glyph_warn(charcode, glyph_seen_fonts);
if (charcode_error) {
throw_ft_error("Could not load charcode", charcode_error);
THROW_FT_ERROR("charcode loading", charcode_error);
}
else if (glyph_error) {
throw_ft_error("Could not load charcode", glyph_error);
THROW_FT_ERROR("charcode loading", glyph_error);
}
} else if (ft_object_with_glyph->warn_if_used) {
ft_glyph_warn(charcode, glyph_seen_fonts);
Expand All @@ -494,13 +457,9 @@
glyph_seen_fonts.insert((face != nullptr)?face->family_name: nullptr);
ft_glyph_warn((FT_ULong)charcode, glyph_seen_fonts);
}
if (FT_Error error = FT_Load_Glyph(face, glyph_index, flags)) {
throw_ft_error("Could not load charcode", error);
}
FT_CHECK(FT_Load_Glyph, face, glyph_index, flags);
FT_Glyph thisGlyph;
if (FT_Error error = FT_Get_Glyph(face->glyph, &thisGlyph)) {
throw_ft_error("Could not get glyph", error);
}
FT_CHECK(FT_Get_Glyph, face->glyph, &thisGlyph);
glyphs.push_back(thisGlyph);
}
}
Expand Down Expand Up @@ -600,13 +559,9 @@

void FT2Font::load_glyph(FT_UInt glyph_index, FT_Int32 flags)
{
if (FT_Error error = FT_Load_Glyph(face, glyph_index, flags)) {
throw_ft_error("Could not load glyph", error);
}
FT_CHECK(FT_Load_Glyph, face, glyph_index, flags);
FT_Glyph thisGlyph;
if (FT_Error error = FT_Get_Glyph(face->glyph, &thisGlyph)) {
throw_ft_error("Could not get glyph", error);
}
FT_CHECK(FT_Get_Glyph, face->glyph, &thisGlyph);
glyphs.push_back(thisGlyph);
}

Expand Down Expand Up @@ -651,13 +606,10 @@
image = py::array_t<uint8_t>{{height, width}};
std::memset(image.mutable_data(0), 0, image.nbytes());

for (auto & glyph : glyphs) {
FT_Error error = FT_Glyph_To_Bitmap(
for (auto & glyph: glyphs) {
FT_CHECK(
FT_Glyph_To_Bitmap,
&glyph, antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, nullptr, 1);
if (error) {
throw_ft_error("Could not convert glyph to bitmap", error);
}

FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph;
// now, draw to our target surface (convert position)

Expand All @@ -681,16 +633,12 @@
throw std::runtime_error("glyph num is out of range");
}

FT_Error error = FT_Glyph_To_Bitmap(
&glyphs[glyphInd],
antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO,
&sub_offset, // additional translation
1 // destroy image
);
if (error) {
throw_ft_error("Could not convert glyph to bitmap", error);
}

FT_CHECK(
FT_Glyph_To_Bitmap,
&glyphs[glyphInd],
antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO,
&sub_offset, // additional translation
1); // destroy image
FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyphs[glyphInd];

draw_bitmap(im, &bitmap->bitmap, x + bitmap->left, y);
Expand All @@ -715,9 +663,7 @@
throw std::runtime_error("Failed to convert glyph to standard name");
}
} else {
if (FT_Error error = FT_Get_Glyph_Name(face, glyph_number, buffer.data(), buffer.size())) {
throw_ft_error("Could not get glyph names", error);
}
FT_CHECK(FT_Get_Glyph_Name, face, glyph_number, buffer.data(), buffer.size());
auto len = buffer.find('\0');
if (len != buffer.npos) {
buffer.resize(len);
Expand Down
31 changes: 28 additions & 3 deletions src/ft2font.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#ifndef MPL_FT2FONT_H
#define MPL_FT2FONT_H

#include <filesystem>
#include <set>
#include <string>
#include <string_view>
Expand All @@ -26,12 +27,36 @@ extern "C" {
#include <pybind11/numpy.h>
namespace py = pybind11;

/*
By definition, FT_FIXED as 2 16bit values stored in a single long.
*/
// By definition, FT_FIXED as 2 16bit values stored in a single long.
#define FIXED_MAJOR(val) (signed short)((val & 0xffff0000) >> 16)
#define FIXED_MINOR(val) (unsigned short)(val & 0xffff)

// Error handling (error codes are loaded as described in fterror.h).
inline char const* ft_error_string(FT_Error error) {
#undef __FTERRORS_H__
#define FT_ERROR_START_LIST switch (error) {
#define FT_ERRORDEF( e, v, s ) case v: return s;
#define FT_ERROR_END_LIST default: return NULL; }
#include FT_ERRORS_H
}

// No more than 16 hex digits + "0x" + null byte for a 64-bit int error.
#define THROW_FT_ERROR(name, err) { \
char buf[20] = {0}; \
sprintf(buf, "%#04x", err); \
throw std::runtime_error{ \
name " (" \
+ std::filesystem::path(__FILE__).filename().string() \
+ " line " + std::to_string(__LINE__) + ") failed with error " \
+ std::string{buf} + ": " + std::string{ft_error_string(err)}}; \
} (void)0

#define FT_CHECK(func, ...) { \
if (auto const& error_ = func(__VA_ARGS__)) { \
THROW_FT_ERROR(#func, error_); \
} \
} (void)0

// the FreeType string rendered into a width, height buffer
class FT2Image
{
Expand Down
Loading