Repository: matplotlib/matplotlib
File: src/ft2font_wrapper.cpp (C++)

Code before:

static std::array<FT_UInt, 256>
PyFT2Font__get_type1_encoding_vector(PyFT2Font *self)
{
    auto face = self->get_face();
    auto indices = std::array<FT_UInt, 256>{};
    for (auto i = 0u; i < indices.size(); ++i) {
        auto len = FT_Get_PS_Font_Value(face, PS_DICT_ENCODING_ENTRY, i, nullptr, 0);
        if (len == -1) {
            // Explicitly ignore missing entries (mapped to glyph 0 = .notdef).
            continue;
        }
        auto buf = std::make_unique<char[]>(len);
        FT_Get_PS_Font_Value(face, PS_DICT_ENCODING_ENTRY, i, buf.get(), len);
        indices[i] = FT_Get_Name_Index(face, buf.get());
    }
    return indices;
}

/**********************************************************************
 * Layout items
 * */

struct LayoutItem {
    PyFT2Font *ft_object;
    std::u32string character;
    int glyph_index;
    double x;
    double y;
    double prev_kern;

    LayoutItem(PyFT2Font *f, std::u32string c, int i, double x, double y, double k) :
        ft_object(f), character(c), glyph_index(i), x(x), y(y), prev_kern(k) {}
};

const char *PyFT2Font_layout__doc__ = R"""(
    Layout a string and yield information about each used glyph.

    .. warning::
        This API uses the fallback list and is both private and provisional: do not use
        it directly.

    .. versionadded:: 3.11

    Parameters
    ----------
    text : str
        The characters for which to find fonts.
    flags : LoadFlags, default: `.LoadFlags.FORCE_AUTOHINT`
        Any bitwise-OR combination of the `.LoadFlags` flags.
    features : tuple[str, ...], optional

Review comment (refactor):
Actually not really related to this PR, but is there a reason not to use the `std::visit(variant, overloaded {...})` pattern? (see example 4 of https://en.cppreference.com/w/cpp/utility/variant/visit2.html, or grep for `overloaded` in the mplcairo codebase)

Code after:
    flags : LoadFlags, default: `.LoadFlags.FORCE_AUTOHINT`
        Any bitwise-OR combination of the `.LoadFlags` flags.
    features : tuple[str, ...], optional
        The font feature tags to use for the font.

        Available font feature tags may be found at
        https://learn.microsoft.com/en-us/typography/opentype/spec/featurelist
    language : str, optional
        The language of the text in a format accepted by libraqm, namely `a BCP47
        language code <https://www.w3.org/International/articles/language-tags/>`_.

    Returns
    -------
    list[LayoutItem]
)""";

static auto
PyFT2Font_layout(PyFT2Font *self, std::u32string text, LoadFlags flags,
                 std::optional<std::vector<std::string>> features = std::nullopt,
                 std::variant<FT2Font::LanguageType, std::string> languages_or_str = nullptr)
{
    const auto hinting_factor = self->get_hinting_factor();
    const auto load_flags = static_cast<FT_Int32>(flags);

    FT2Font::LanguageType languages;
    if (auto value = std::get_if<FT2Font::LanguageType>(&languages_or_str)) {
        languages = std::move(*value);
    } else if (auto value = std::get_if<std::string>(&languages_or_str)) {
        languages = std::vector<FT2Font::LanguageRange>{
            FT2Font::LanguageRange{*value, 0, text.size()}
        };
    } else {
        // NOTE: this can never happen as pybind11 would have checked the type in the
        // Python wrapper before calling this function, but we need to keep the
        // std::get_if instead of std::get for macOS 10.12 compatibility.
        throw py::type_error("languages must be str or list of tuple");
    }

    std::set<FT_String*> glyph_seen_fonts;
    auto glyphs = self->layout(text, load_flags, features, languages, glyph_seen_fonts);

    std::set<decltype(raqm_glyph_t::cluster)> clusters;
    for (auto &glyph : glyphs) {
        clusters.emplace(glyph.cluster);
    }

    std::vector<LayoutItem> items;

    double x = 0.0;
    double y = 0.0;
    std::optional<double> prev_advance = std::nullopt;