Skip to content

Commit

Permalink
Fixes loading TTC (TrueType Collection) font files not honor which fa…
Browse files Browse the repository at this point in the history
…ce to load within the collection (#939).
  • Loading branch information
christianparpart committed Dec 22, 2022
1 parent 6a34be5 commit ac2cc45
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 32 deletions.
1 change: 1 addition & 0 deletions metainfo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
<li>Fixes failing startup due to `background_image.path` pointing to a non-existing file (#928).</li>
<li>Fixes terminfo entries `Se`, and adds missing entries `Rmol`, `Sync` (#936).</li>
<li>Fixes rendering glitches (reverting PR #918 until a better solution has been found).</li>
<li>Fixes loading TTC (TrueType Collection) font files not honor which face to load within the collection (#939).</li>
<li>Adds config entry `indicator_statusline_inactive` colorscheme key to colorize the status line differently when the terminal is currently not in focus.</li>
</ul>
</description>
Expand Down
13 changes: 11 additions & 2 deletions src/text_shaper/font_locator.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ namespace text
struct font_path
{
std::string value;

// in case the font file this path points to is a collection file (e.g. TTC), then this index
// can be used to mandate which font within this TTC is to be used.
int collectionIndex = 0;

std::optional<font_weight> weight = std::nullopt;
std::optional<font_slant> slant = std::nullopt;
};

/// Holds a view into the contents of a font file.
Expand Down Expand Up @@ -90,9 +97,11 @@ struct formatter<text::font_path>
return ctx.begin();
}
template <typename FormatContext>
auto format(text::font_path path, FormatContext& ctx)
auto format(text::font_path spec, FormatContext& ctx)
{
return fmt::format_to(ctx.out(), "path {}", path.value);
auto weightMod = spec.weight ? fmt::format(" {}", spec.weight.value()) : "";
auto slantMod = spec.slant ? fmt::format(" {}", spec.slant.value()) : "";
return fmt::format_to(ctx.out(), "path {}{}{}", spec.value, weightMod, slantMod);
}
};

Expand Down
94 changes: 65 additions & 29 deletions src/text_shaper/fontconfig_locator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#include <text_shaper/font.h>
#include <text_shaper/fontconfig_locator.h>

#include <crispy/assert.h>

#include <range/v3/view/iota.hpp>

#include <fontconfig/fontconfig.h>
Expand Down Expand Up @@ -47,39 +49,56 @@ namespace
}
}

auto static constexpr fontWeightMappings = std::array<std::pair<font_weight, int>, 12>{{
{ font_weight::thin, FC_WEIGHT_THIN, },
{ font_weight::extra_light, FC_WEIGHT_EXTRALIGHT },
{ font_weight::light, FC_WEIGHT_LIGHT },
{ font_weight::demilight, FC_WEIGHT_DEMILIGHT },
{ font_weight::book, FC_WEIGHT_BOOK },
{ font_weight::normal, FC_WEIGHT_NORMAL },
{ font_weight::medium, FC_WEIGHT_MEDIUM },
{ font_weight::demibold, FC_WEIGHT_DEMIBOLD },
{ font_weight::bold, FC_WEIGHT_BOLD },
{ font_weight::extra_bold, FC_WEIGHT_EXTRABOLD },
{ font_weight::black, FC_WEIGHT_BLACK },
{ font_weight::extra_black, FC_WEIGHT_EXTRABLACK },
}};

auto static constexpr fontSlantMappings = std::array<std::pair<font_slant, int>, 3>{{
{ font_slant::italic, FC_SLANT_ITALIC },
{ font_slant::oblique, FC_SLANT_OBLIQUE },
{ font_slant::normal, FC_SLANT_ROMAN }
}};

constexpr optional<font_weight> fcToFontWeight(int value) noexcept
{
for (auto const& mapping: fontWeightMappings)
if (mapping.second == value)
return mapping.first;
return nullopt;
}

constexpr optional<font_slant> fcToFontSlant(int value) noexcept
{
for (auto const& mapping: fontSlantMappings)
if (mapping.second == value)
return mapping.first;
return nullopt;
}

constexpr int fcWeight(font_weight _weight) noexcept
{
switch (_weight)
{
case font_weight::thin: return FC_WEIGHT_THIN;
case font_weight::extra_light: return FC_WEIGHT_EXTRALIGHT;
case font_weight::light: return FC_WEIGHT_LIGHT;
case font_weight::demilight:
#if defined(FC_WEIGHT_DEMILIGHT)
return FC_WEIGHT_DEMILIGHT;
#else
return FC_WEIGHT_LIGHT; // Is this a good fallback? Maybe.
#endif
case font_weight::book: return FC_WEIGHT_BOOK;
case font_weight::normal: return FC_WEIGHT_NORMAL;
case font_weight::medium: return FC_WEIGHT_MEDIUM;
case font_weight::demibold: return FC_WEIGHT_DEMIBOLD;
case font_weight::bold: return FC_WEIGHT_BOLD;
case font_weight::extra_bold: return FC_WEIGHT_EXTRABOLD;
case font_weight::black: return FC_WEIGHT_BLACK;
case font_weight::extra_black: return FC_WEIGHT_EXTRABLACK;
}
return FC_WEIGHT_NORMAL;
for (auto const& mapping: fontWeightMappings)
if (mapping.first == _weight)
return mapping.second;
crispy::fatal("Implementation error. font weight cannot be mapped.");
}

constexpr int fcSlant(font_slant _slant) noexcept
{
switch (_slant)
{
case font_slant::italic: return FC_SLANT_ITALIC;
case font_slant::oblique: return FC_SLANT_OBLIQUE;
case font_slant::normal: return FC_SLANT_ROMAN;
}
for (auto const& mapping: fontSlantMappings)
if (mapping.first == _slant)
return mapping.second;
return FC_SLANT_ROMAN;
}

Expand Down Expand Up @@ -185,6 +204,7 @@ font_source_list fontconfig_locator::locate(font_description const& _fd)
FcPatternAddInteger(pat.get(), FC_SPACING, FC_DUAL);
}


if (_fd.weight != font_weight::normal)
FcPatternAddInteger(pat.get(), FC_WEIGHT, fcWeight(_fd.weight));
if (_fd.slant != font_slant::normal)
Expand Down Expand Up @@ -245,8 +265,24 @@ font_source_list fontconfig_locator::locate(font_description const& _fd)
}
}

output.emplace_back(font_path { string { (char const*) (file) } });
LocatorLog()("Font {} (spacing {}) in chain: {}", output.size(), spacing, (char const*) file);
int integerValue = -1;
optional<font_weight> weight = nullopt;
optional<font_slant> slant = nullopt;
int ttcIndex = -1;

if (FcPatternGetInteger(font, FC_INDEX, 0, &integerValue) == FcResultMatch && integerValue >= 0)
ttcIndex = integerValue;
if (FcPatternGetInteger(font, FC_WEIGHT, 0, &integerValue) == FcResultMatch)
weight = fcToFontWeight(integerValue);
if (FcPatternGetInteger(font, FC_SLANT, 0, &integerValue) == FcResultMatch)
slant = fcToFontSlant(integerValue);

output.emplace_back(font_path { string { (char const*) (file) }, ttcIndex, weight, slant });
LocatorLog()("Font {} (ttc index {}, weight {}, slant {}, spacing {}) in chain: {}", output.size(),
ttcIndex,
weight.has_value() ? fmt::format("{}", *weight) : "NONE",
slant.has_value() ? fmt::format("{}", *slant) : "NONE",
spacing, (char const*) file);
}

#if defined(_WIN32)
Expand Down
2 changes: 1 addition & 1 deletion src/text_shaper/open_shaper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ namespace
if (holds_alternative<font_path>(_source))
{
auto const& sourcePath = get<font_path>(_source);
FT_Error ec = FT_New_Face(_ft, sourcePath.value.c_str(), 0, &ftFace);
FT_Error ec = FT_New_Face(_ft, sourcePath.value.c_str(), sourcePath.collectionIndex, &ftFace);
if (!ftFace)
{
// clang-format off
Expand Down

0 comments on commit ac2cc45

Please sign in to comment.