Skip to content

Commit 2e9e78b

Browse files
committedApr 3, 2025
Implement font fallback for libraqm
1 parent e7ba81f commit 2e9e78b

File tree

1 file changed

+51
-3
lines changed

1 file changed

+51
-3
lines changed
 

‎src/ft2font.cpp

+51-3
Original file line numberDiff line numberDiff line change
@@ -444,13 +444,61 @@ void FT2Font::set_text(
444444
throw std::runtime_error("failed to set text flags for layout");
445445
}
446446

447-
std::set<FT_String*> glyph_seen_fonts;
448-
glyph_seen_fonts.insert(face->family_name);
449-
450447
if (!raqm_layout(rq)) {
451448
throw std::runtime_error("failed to layout text");
452449
}
453450

451+
std::vector<std::pair<size_t, const FT_Face&>> face_substitutions;
452+
std::set<FT_String*> glyph_seen_fonts;
453+
glyph_seen_fonts.insert(face->family_name);
454+
455+
// Attempt to use fallback fonts if necessary.
456+
for (auto const& fallback : fallbacks) {
457+
size_t num_glyphs = 0;
458+
auto const& rq_glyphs = raqm_get_glyphs(rq, &num_glyphs);
459+
bool new_fallback_used = false;
460+
461+
for (size_t i = 0; i < num_glyphs; i++) {
462+
auto const& rglyph = rq_glyphs[i];
463+
464+
if (rglyph.index == 0) {
465+
face_substitutions.emplace_back(rglyph.cluster, fallback->face);
466+
new_fallback_used = true;
467+
}
468+
}
469+
470+
if (new_fallback_used) {
471+
// If a fallback was used, then re-attempt the layout with the new fonts.
472+
if (!fallback->warn_if_used) {
473+
glyph_seen_fonts.insert(fallback->face->family_name);
474+
}
475+
476+
raqm_clear_contents(rq);
477+
if (!raqm_set_text(rq,
478+
reinterpret_cast<const uint32_t *>(text.data()),
479+
text.size()))
480+
{
481+
throw std::runtime_error("failed to set text for layout");
482+
}
483+
if (!raqm_set_freetype_face(rq, face)) {
484+
throw std::runtime_error("failed to set text face for layout");
485+
}
486+
for (auto [cluster, face] : face_substitutions) {
487+
raqm_set_freetype_face_range(rq, face, cluster, 1);
488+
}
489+
if (!raqm_set_freetype_load_flags(rq, flags)) {
490+
throw std::runtime_error("failed to set text flags for layout");
491+
}
492+
493+
if (!raqm_layout(rq)) {
494+
throw std::runtime_error("failed to layout text");
495+
}
496+
} else {
497+
// If we never used a fallback, then we're good to go with the existing
498+
// layout we have already made.
499+
break;
500+
}
501+
}
454502

455503
size_t num_glyphs = 0;
456504
auto const& rq_glyphs = raqm_get_glyphs(rq, &num_glyphs);

0 commit comments

Comments
 (0)
Please sign in to comment.