fix: UTF-8 support in TTF drawText
- drawText now decodes UTF-8 codepoints instead of iterating bytes - Fixes rendering of accented characters (á, é, í, ó, ú, ñ, etc.) - Uses std.unicode.utf8ByteSequenceLength + utf8Decode - Invalid UTF-8 sequences are gracefully skipped 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
222c4e1542
commit
105e3c63d1
1 changed files with 26 additions and 10 deletions
|
|
@ -861,25 +861,41 @@ pub const TtfFont = struct {
|
|||
var cx = x;
|
||||
const baseline_y = y + self.ascent();
|
||||
|
||||
for (text) |c| {
|
||||
if (c == '\n') continue;
|
||||
if (c == ' ') {
|
||||
const metrics = self.getGlyphMetrics(c);
|
||||
// UTF-8 iteration: decode codepoints instead of iterating bytes
|
||||
var i: usize = 0;
|
||||
while (i < text.len) {
|
||||
// Get UTF-8 sequence length
|
||||
const cp_len = std.unicode.utf8ByteSequenceLength(text[i]) catch {
|
||||
i += 1; // Skip invalid byte
|
||||
continue;
|
||||
};
|
||||
if (i + cp_len > text.len) break; // Not enough bytes
|
||||
|
||||
// Decode codepoint
|
||||
const cp: u32 = std.unicode.utf8Decode(text[i..][0..cp_len]) catch {
|
||||
i += cp_len;
|
||||
continue;
|
||||
};
|
||||
i += cp_len;
|
||||
|
||||
if (cp == '\n') continue;
|
||||
if (cp == ' ') {
|
||||
const metrics = self.getGlyphMetrics(cp);
|
||||
cx += @intCast(metrics.advance);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try to get cached glyph or rasterize
|
||||
const cache_key = makeCacheKey(c, self.render_size);
|
||||
const cache_key = makeCacheKey(cp, self.render_size);
|
||||
|
||||
if (self.glyph_cache.get(cache_key)) |cached| {
|
||||
// Draw cached glyph
|
||||
self.drawGlyphBitmap(fb, cx, baseline_y, cached, color, clip);
|
||||
const metrics = self.getGlyphMetrics(c);
|
||||
const metrics = self.getGlyphMetrics(cp);
|
||||
cx += @intCast(metrics.advance);
|
||||
} else {
|
||||
// Rasterize and cache
|
||||
const glyph_index = self.getGlyphIndex(c);
|
||||
const glyph_index = self.getGlyphIndex(cp);
|
||||
if (self.getGlyphOutline(glyph_index)) |outline| {
|
||||
defer {
|
||||
var outline_copy = outline;
|
||||
|
|
@ -895,9 +911,9 @@ pub const TtfFont = struct {
|
|||
.height = @intCast(bitmap.height),
|
||||
.bearing_x = @intCast(bitmap.bearing_x),
|
||||
.bearing_y = @intCast(bitmap.bearing_y),
|
||||
.advance = self.getGlyphMetrics(c).advance,
|
||||
.advance = self.getGlyphMetrics(cp).advance,
|
||||
},
|
||||
.codepoint = c,
|
||||
.codepoint = cp,
|
||||
};
|
||||
|
||||
self.glyph_cache.put(cache_key, cached_glyph) catch {};
|
||||
|
|
@ -905,7 +921,7 @@ pub const TtfFont = struct {
|
|||
}
|
||||
}
|
||||
|
||||
const metrics = self.getGlyphMetrics(c);
|
||||
const metrics = self.getGlyphMetrics(cp);
|
||||
cx += @intCast(metrics.advance);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue