Verified Commit 0dacc4ed authored by Alba Mendez's avatar Alba Mendez Committed by Marc Jeanmougin
Browse files

fix GSUB table reading

parent 9d6915ef
......@@ -15,6 +15,7 @@
#include <iostream> // For debugging
#include <memory>
#include <unordered_map>
// FreeType
#include FT_FREETYPE_H
......@@ -60,19 +61,69 @@ Glib::ustring extract_tag( guint32 *tag ) {
#if HB_VERSION_ATLEAST(1,2,3) // Released Feb 2016
void get_glyphs(hb_font_t* font, HbSet& set, Glib::ustring& characters) {
// There is a unicode to glyph mapping function but not the inverse!
hb_codepoint_t codepoint = -1;
while (hb_set_next (set.get(), &codepoint)) {
for (hb_codepoint_t unicode_i = 0; unicode_i < 0xffff; ++unicode_i) {
hb_codepoint_t glyph = 0;
hb_font_get_nominal_glyph (font, unicode_i, &glyph);
if (glyph == codepoint) {
characters += (gunichar)unicode_i;
break;
}
// Later (see get_glyphs) we need to lookup the Unicode codepoint for a glyph
// but there's no direct API for that. So, we need a way to iterate over all
// glyph mappings and build a reverse map.
// FIXME: we should handle UVS at some point... or better, work with glyphs directly
// Iterates over all *possibly* mapped Unicode codepoints of a font, sorted.
class FontUnicodeSet {
public:
#if HB_VERSION_ATLEAST(1,9,0) && !defined(HB_NO_FACE_COLLECT_UNICODES) // Released Sep 2018
HbSet set;
FontUnicodeSet(hb_font_t* font): set(hb_set_create()) {
hb_face_collect_unicodes(hb_font_get_face(font), set.get());
}
inline bool next(hb_codepoint_t* x) { return hb_set_next(set.get(), x); }
#else
// if hb_face_collect_unicodes() is not available, fall back to old behavior by
// simulating a set with all BMP codepoints (non-BMP codepoints are ignored)
FontUnicodeSet(hb_font_t* font) {}
inline bool next(hb_codepoint_t* x) {
if (*x == HB_SET_VALUE_INVALID) *x = 0;
else ++(*x);
return (*x) < 0x10000;
}
#endif
};
// Allows looking up the lowest Unicode codepoint mapped to a given glyph.
// To do so, it lazily builds a reverse map.
class GlyphToUnicodeMap {
protected:
hb_font_t* font;
FontUnicodeSet codepointSet;
std::unordered_map<hb_codepoint_t, hb_codepoint_t> mappings;
bool more = true; // false if we have finished iterating the set
hb_codepoint_t codepoint = HB_SET_VALUE_INVALID; // current iteration
public:
GlyphToUnicodeMap(hb_font_t* font): font(font), codepointSet(font) {}
hb_codepoint_t lookup(hb_codepoint_t glyph) {
// first, try to find it in the mappings we've seen so far
if (auto it = mappings.find(glyph); it != mappings.end())
return it->second;
// populate more mappings from the set
while (more = more && codepointSet.next(&codepoint)) {
// get the glyph that this codepoint is associated with, if any
hb_codepoint_t tGlyph;
if (!hb_font_get_nominal_glyph(font, codepoint, &tGlyph)) continue;
// save the mapping, and return if this is the one we were looking for
mappings.emplace(tGlyph, codepoint);
if (tGlyph == glyph) return codepoint;
}
return 0;
}
};
void get_glyphs(GlyphToUnicodeMap& glyphMap, HbSet& set, Glib::ustring& characters) {
hb_codepoint_t glyph = -1;
while (hb_set_next(set.get(), &glyph)) {
if (auto codepoint = glyphMap.lookup(glyph))
characters += codepoint;
}
}
#endif
......@@ -143,6 +194,8 @@ void readOpenTypeGsubTable (hb_font_t* hb_font,
// Find glyphs in OpenType substitution tables ('gsub').
// Note that pango's functions are just dummies. Must use harfbuzz.
GlyphToUnicodeMap glyphMap (hb_font);
// Loop over all tables
for (auto table: tables) {
......@@ -217,10 +270,10 @@ void readOpenTypeGsubTable (hb_font_t* hb_font,
// << " " << hb_set_get_population (glyphs_output)
// << std::endl;
get_glyphs (hb_font, glyphs_before, tables[table.first].before);
get_glyphs (hb_font, glyphs_input, tables[table.first].input );
get_glyphs (hb_font, glyphs_after, tables[table.first].after );
get_glyphs (hb_font, glyphs_output, tables[table.first].output);
get_glyphs (glyphMap, glyphs_before, tables[table.first].before);
get_glyphs (glyphMap, glyphs_input, tables[table.first].input );
get_glyphs (glyphMap, glyphs_after, tables[table.first].after );
get_glyphs (glyphMap, glyphs_output, tables[table.first].output);
// std::cout << " Before: " << tables[table.first].before.c_str() << std::endl;
// std::cout << " Input: " << tables[table.first].input.c_str() << std::endl;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment