Skip to content

Commit 4747606

Browse files
Use HarfBuzz kerning instead of FreeType's (#639)
1 parent 7690e8e commit 4747606

File tree

5 files changed

+26
-112
lines changed

5 files changed

+26
-112
lines changed

Samples/basic/harfbuzz/src/FontEngineInterfaceHarfBuzz.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ bool FontEngineInterfaceHarfBuzz::LoadFontFace(const String& file_name, int face
4545
return FontProvider::LoadFontFace(file_name, face_index, fallback_face, weight);
4646
}
4747

48-
bool FontEngineInterfaceHarfBuzz::LoadFontFace(Span<const byte> data, int face_index, const String& font_family, Style::FontStyle style, Style::FontWeight weight,
49-
bool fallback_face)
48+
bool FontEngineInterfaceHarfBuzz::LoadFontFace(Span<const byte> data, int face_index, const String& font_family, Style::FontStyle style,
49+
Style::FontWeight weight, bool fallback_face)
5050
{
5151
return FontProvider::LoadFontFace(data, face_index, font_family, style, weight, fallback_face);
5252
}

Samples/basic/harfbuzz/src/FontFaceHandleHarfBuzz.cpp

Lines changed: 24 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,10 @@ bool FontFaceHandleHarfBuzz::Initialize(FontFaceHandleFreetype face, int font_si
6868
if (!FreeType::InitialiseFaceHandle(ft_face, font_size, glyphs, metrics, load_default_glyphs))
6969
return false;
7070

71-
has_kerning = Rml::FreeType::HasKerning(ft_face);
72-
FillKerningPairCache();
73-
7471
hb_font = hb_ft_font_create_referenced((FT_Face)ft_face);
7572
RMLUI_ASSERT(hb_font != nullptr);
7673
hb_font_set_ptem(hb_font, (float)font_size);
74+
hb_ft_font_set_funcs(hb_font);
7775

7876
// Generate the default layer and layer configuration.
7977
base_layer = GetOrCreateLayer(nullptr);
@@ -98,7 +96,7 @@ const FallbackFontGlyphMap& FontFaceHandleHarfBuzz::GetFallbackGlyphs() const
9896
}
9997

10098
int FontFaceHandleHarfBuzz::GetStringWidth(StringView string, const TextShapingContext& text_shaping_context,
101-
const LanguageDataMap& registered_languages, Character prior_character)
99+
const LanguageDataMap& registered_languages, Character /*prior_character*/)
102100
{
103101
int width = 0;
104102

@@ -109,10 +107,9 @@ int FontFaceHandleHarfBuzz::GetStringWidth(StringView string, const TextShapingC
109107
hb_buffer_add_utf8(shaping_buffer, string.begin(), (int)string.size(), 0, (int)string.size());
110108
hb_shape(hb_font, shaping_buffer, nullptr, 0);
111109

112-
FontGlyphIndex prior_glyph_codepoint = FreeType::GetGlyphIndexFromCharacter(ft_face, prior_character);
113-
114110
unsigned int glyph_count = 0;
115111
hb_glyph_info_t* glyph_info = hb_buffer_get_glyph_infos(shaping_buffer, &glyph_count);
112+
hb_glyph_position_t* glyph_positions = hb_buffer_get_glyph_positions(shaping_buffer, &glyph_count);
116113

117114
for (int g = 0; g < (int)glyph_count; ++g)
118115
{
@@ -121,19 +118,19 @@ int FontFaceHandleHarfBuzz::GetStringWidth(StringView string, const TextShapingC
121118
if (IsASCIIControlCharacter(character))
122119
continue;
123120

124-
FontGlyphIndex glyph_codepoint = glyph_info[g].codepoint;
125-
const FontGlyph* glyph = GetOrAppendGlyph(glyph_codepoint, character);
121+
FontGlyphIndex glyph_index = glyph_info[g].codepoint;
122+
const FontGlyph* glyph = GetOrAppendGlyph(glyph_index, character);
126123
if (!glyph)
127124
continue;
128125

129-
// Adjust the cursor for the kerning between this character and the previous one.
130-
width += GetKerning(prior_glyph_codepoint, glyph_codepoint);
131-
132126
// Adjust the cursor for this character's advance.
133-
width += glyph->advance;
134-
width += (int)text_shaping_context.letter_spacing;
127+
if (glyph_index != 0)
128+
width += glyph_positions[g].x_advance >> 6;
129+
else
130+
// Use the unshaped advance for unsupported characters.
131+
width += glyph->advance;
135132

136-
prior_glyph_codepoint = glyph_codepoint;
133+
width += (int)text_shaping_context.letter_spacing;
137134
}
138135

139136
hb_buffer_destroy(shaping_buffer);
@@ -265,7 +262,6 @@ int FontFaceHandleHarfBuzz::GenerateString(RenderManager& render_manager, Textur
265262
RMLUI_ASSERT(geometry_index + num_textures <= (int)mesh_list.size());
266263

267264
line_width = 0;
268-
FontGlyphIndex prior_glyph_codepoint = 0;
269265

270266
// Set the mesh and textures to the geometries.
271267
for (int tex_index = 0; tex_index < num_textures; ++tex_index)
@@ -279,6 +275,7 @@ int FontFaceHandleHarfBuzz::GenerateString(RenderManager& render_manager, Textur
279275

280276
unsigned int glyph_count = 0;
281277
hb_glyph_info_t* glyph_info = hb_buffer_get_glyph_infos(shaping_buffer, &glyph_count);
278+
hb_glyph_position_t* glyph_positions = hb_buffer_get_glyph_positions(shaping_buffer, &glyph_count);
282279

283280
mesh_list[geometry_index].mesh.indices.reserve(string.size() * 6);
284281
mesh_list[geometry_index].mesh.vertices.reserve(string.size() * 4);
@@ -291,25 +288,28 @@ int FontFaceHandleHarfBuzz::GenerateString(RenderManager& render_manager, Textur
291288
if (IsASCIIControlCharacter(character))
292289
continue;
293290

294-
FontGlyphIndex glyph_codepoint = glyph_info[g].codepoint;
295-
const FontGlyph* glyph = GetOrAppendGlyph(glyph_codepoint, character);
291+
FontGlyphIndex glyph_index = glyph_info[g].codepoint;
292+
const FontGlyph* glyph = GetOrAppendGlyph(glyph_index, character);
296293
if (!glyph)
297294
continue;
298295

299-
// Adjust the cursor for the kerning between this character and the previous one.
300-
line_width += GetKerning(prior_glyph_codepoint, glyph_codepoint);
301-
302296
ColourbPremultiplied glyph_color = layer_colour;
303297
// Use white vertex colors on RGB glyphs.
304298
if (layer == base_layer && glyph->color_format == ColorFormat::RGBA8)
305299
glyph_color = ColourbPremultiplied(layer_colour.alpha, layer_colour.alpha);
306300

307-
layer->GenerateGeometry(&mesh_list[geometry_index], glyph_codepoint, character, Vector2f(position.x + line_width, position.y),
308-
glyph_color);
301+
Vector2f glyph_offset = {float(glyph_positions[g].x_offset >> 6), float(glyph_positions[g].y_offset >> 6)};
302+
Vector2f glyph_geometry_position = Vector2f{position.x + line_width, position.y} + glyph_offset;
303+
layer->GenerateGeometry(&mesh_list[geometry_index], glyph_index, character, glyph_geometry_position, glyph_color);
304+
305+
// Adjust the cursor for this character's advance.
306+
if (glyph_index != 0)
307+
line_width += glyph_positions[g].x_advance >> 6;
308+
else
309+
// Use the unshaped advance for unsupported characters.
310+
line_width += glyph->advance;
309311

310-
line_width += glyph->advance;
311312
line_width += (int)text_shaping_context.letter_spacing;
312-
prior_glyph_codepoint = glyph_codepoint;
313313
}
314314

315315
geometry_index += num_textures;
@@ -383,49 +383,6 @@ bool FontFaceHandleHarfBuzz::AppendFallbackGlyph(Character character)
383383
return false;
384384
}
385385

386-
void FontFaceHandleHarfBuzz::FillKerningPairCache()
387-
{
388-
if (!has_kerning)
389-
return;
390-
391-
static constexpr char32_t KerningCache_AsciiSubsetBegin = 32;
392-
static constexpr char32_t KerningCache_AsciiSubsetLast = 126;
393-
394-
for (char32_t i = KerningCache_AsciiSubsetBegin; i <= KerningCache_AsciiSubsetLast; i++)
395-
{
396-
for (char32_t j = KerningCache_AsciiSubsetBegin; j <= KerningCache_AsciiSubsetLast; j++)
397-
{
398-
const bool first_iteration = (i == KerningCache_AsciiSubsetBegin && j == KerningCache_AsciiSubsetBegin);
399-
400-
// Fetch the kerning from the font face. Submit zero font size on subsequent iterations for performance reasons.
401-
const int kerning = FreeType::GetKerning(ft_face, first_iteration ? metrics.size : 0,
402-
FreeType::GetGlyphIndexFromCharacter(ft_face, Character(i)), FreeType::GetGlyphIndexFromCharacter(ft_face, Character(j)));
403-
if (kerning != 0)
404-
{
405-
kerning_pair_cache.emplace(AsciiPair((i << 8) | j), KerningIntType(kerning));
406-
}
407-
}
408-
}
409-
}
410-
411-
int FontFaceHandleHarfBuzz::GetKerning(FontGlyphIndex lhs, FontGlyphIndex rhs) const
412-
{
413-
// Check if we have no kerning, or if we are have an unsupported character.
414-
if (!has_kerning || lhs == 0 || rhs == 0)
415-
return 0;
416-
417-
// See if the kerning pair has been cached.
418-
const auto it = kerning_pair_cache.find(AsciiPair((int(lhs) << 8) | int(rhs)));
419-
if (it != kerning_pair_cache.end())
420-
{
421-
return it->second;
422-
}
423-
424-
// Fetch it from the font face instead.
425-
const int result = FreeType::GetKerning(ft_face, metrics.size, lhs, rhs);
426-
return result;
427-
}
428-
429386
const FontGlyph* FontFaceHandleHarfBuzz::GetOrAppendGlyph(FontGlyphIndex glyph_index, Character& character, bool look_in_fallback_fonts)
430387
{
431388
if (glyph_index == 0 && look_in_fallback_fonts && character != Character::Replacement)

Samples/basic/harfbuzz/src/FontFaceHandleHarfBuzz.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,6 @@ class FontFaceHandleHarfBuzz : public Rml::NonCopyMoveable {
119119
// Build and append fallback glyph to 'fallback_glyphs'.
120120
bool AppendFallbackGlyph(Character character);
121121

122-
// Build a kerning cache for common characters.
123-
void FillKerningPairCache();
124-
125-
// Return the kerning for a codepoint pair.
126-
int GetKerning(FontGlyphIndex lhs, FontGlyphIndex rhs) const;
127-
128122
/// Retrieve a glyph from the given code index, building and appending a new glyph if not already built.
129123
/// @param[in] glyph_index The glyph index.
130124
/// @param[in-out] character The character codepoint, can be changed e.g. to the replacement character if no glyph is found..
@@ -168,13 +162,6 @@ class FontFaceHandleHarfBuzz : public Rml::NonCopyMoveable {
168162
// Each font layer that generated geometry or textures, indexed by the font-effect's fingerprint key.
169163
FontLayerCache layer_cache;
170164

171-
// Pre-cache kerning pairs for some ascii subset of all characters.
172-
using AsciiPair = uint16_t;
173-
using KerningIntType = int16_t;
174-
using KerningPairs = UnorderedMap<AsciiPair, KerningIntType>;
175-
KerningPairs kerning_pair_cache;
176-
177-
bool has_kerning = false;
178165
bool is_layers_dirty = false;
179166
int version = 0;
180167

Samples/basic/harfbuzz/src/FreeTypeInterface.cpp

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -80,32 +80,6 @@ bool AppendGlyph(FontFaceHandleFreetype face, int font_size, FontGlyphIndex glyp
8080
return true;
8181
}
8282

83-
int GetKerning(FontFaceHandleFreetype face, int font_size, FontGlyphIndex lhs, FontGlyphIndex rhs)
84-
{
85-
FT_Face ft_face = (FT_Face)face;
86-
87-
RMLUI_ASSERT(FT_HAS_KERNING(ft_face));
88-
89-
// Set face size again in case it was used at another size in another font face handle.
90-
// Font size value of zero assumes it is already set.
91-
if (font_size > 0)
92-
{
93-
float bitmap_scaling_factor = 1.0f;
94-
if (!SetFontSize(ft_face, font_size, bitmap_scaling_factor) || bitmap_scaling_factor != 1.0f)
95-
return 0;
96-
}
97-
98-
FT_Vector ft_kerning;
99-
100-
FT_Error ft_error = FT_Get_Kerning(ft_face, lhs, rhs, FT_KERNING_DEFAULT, &ft_kerning);
101-
102-
if (ft_error)
103-
return 0;
104-
105-
int kerning = ft_kerning.x >> 6;
106-
return kerning;
107-
}
108-
10983
FontGlyphIndex GetGlyphIndexFromCharacter(FontFaceHandleFreetype face, Character character)
11084
{
11185
return FT_Get_Char_Index((FT_Face)face, (FT_ULong)character);

Samples/basic/harfbuzz/src/FreeTypeInterface.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,6 @@ bool InitialiseFaceHandle(FontFaceHandleFreetype face, int font_size, FontGlyphM
4242
// Build a new glyph representing the given glyph index and append to 'glyphs'.
4343
bool AppendGlyph(FontFaceHandleFreetype face, int font_size, FontGlyphIndex glyph_index, Character character, FontGlyphMap& glyphs);
4444

45-
// Returns the kerning between two characters given by glyph indices.
46-
// 'font_size' value of zero assumes the font size is already set on the face, and skips this step for performance reasons.
47-
int GetKerning(FontFaceHandleFreetype face, int font_size, FontGlyphIndex lhs, FontGlyphIndex rhs);
48-
4945
// Returns the corresponding glyph index from a character code.
5046
FontGlyphIndex GetGlyphIndexFromCharacter(FontFaceHandleFreetype face, Character character);
5147

0 commit comments

Comments
 (0)