ttf: handle metrics for composite glyphs

To enable glyph-to-character mapping, it is necessary
to include information in GlyphMetrics indicating which
indices of the original text each glyph corresponds to.
Since characters encoded with multiple utf8 bytes still
result in a single glyph, both the starting index in the
utf8 string and the byte length must be stored. This allows
accurate mapping between glyphs and their original text
representation.
This commit is contained in:
Mira Grudzinska 2025-05-17 14:14:51 +02:00
parent 708b24b589
commit c92ddd6cc2
2 changed files with 35 additions and 0 deletions

View file

@ -297,6 +297,8 @@ struct GlyphMetrics
float yOffset; float yOffset;
float minw; float minw;
float minh; float minh;
//for glyph<->text mapping:
uint32_t length;
}; };

View file

@ -198,6 +198,35 @@ static uint32_t* _codepoints(const char* text, size_t n)
} }
static uint32_t* _codepointsLength(const char* text, size_t n) {
auto length = tvg::malloc<uint32_t*>(sizeof(uint32_t) * (n + 1));
size_t i = 0;
auto p = text;
while(*p) {
if (!(*p & 0x80U)) {
length[i++] = 1;
++p;
} else if ((*p & 0xe0U) == 0xc0U) {
length[i++] = 2;
p += 2;
} else if ((*p & 0xf0U) == 0xe0U) {
length[i++] = 3;
p += 3;
} else if ((*p & 0xf8U) == 0xf0U) {
length[i++] = 4;
p += 4;
} else {
tvg::free(length);
return nullptr;
}
}
length[i] = 0;
return length;
}
static void _scale(GlyphMetrics& gmetric, float scale) static void _scale(GlyphMetrics& gmetric, float scale)
{ {
gmetric.kerning.x *= scale; gmetric.kerning.x *= scale;
@ -333,6 +362,8 @@ bool TtfLoader::metrics(char* text, float fontSize, GlyphMetrics** metrics, uint
auto n = strlen(text); auto n = strlen(text);
auto code = _codepoints(text, n); auto code = _codepoints(text, n);
if (!code) return false; if (!code) return false;
auto length = _codepointsLength(text, n);
if (!length) return false;
GlyphMetrics gmetrics; GlyphMetrics gmetrics;
auto lglyph = INVALID_GLYPH, rglyph = INVALID_GLYPH; auto lglyph = INVALID_GLYPH, rglyph = INVALID_GLYPH;
@ -345,6 +376,7 @@ bool TtfLoader::metrics(char* text, float fontSize, GlyphMetrics** metrics, uint
if ((rglyph = reader.glyph(code[idx], gmetrics, nullptr)) != INVALID_GLYPH) { if ((rglyph = reader.glyph(code[idx], gmetrics, nullptr)) != INVALID_GLYPH) {
if (lglyph != INVALID_GLYPH) reader.kerning(lglyph, rglyph, gmetrics.kerning); if (lglyph != INVALID_GLYPH) reader.kerning(lglyph, rglyph, gmetrics.kerning);
_scale(gmetrics, scale); _scale(gmetrics, scale);
gmetrics.length = length[idx];
out.push(gmetrics); out.push(gmetrics);
lglyph = rglyph; lglyph = rglyph;
} }
@ -352,6 +384,7 @@ bool TtfLoader::metrics(char* text, float fontSize, GlyphMetrics** metrics, uint
} }
tvg::free(code); tvg::free(code);
tvg::free(length);
*metrics = out.data; *metrics = out.data;
out.data = nullptr; out.data = nullptr;