mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 05:33:36 +00:00
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:
parent
708b24b589
commit
c92ddd6cc2
2 changed files with 35 additions and 0 deletions
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Reference in a new issue