Skip to content

Commit 89a726e

Browse files
authored
Merge pull request #10865 from FoamyGuy/lvfontio_fix_full_width_glyphs
Fix lvfontio full width glyphs
2 parents 566eaee + f4f77e4 commit 89a726e

File tree

1 file changed

+54
-13
lines changed

1 file changed

+54
-13
lines changed

shared-module/lvfontio/OnDiskFont.c

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ static inline void free_memory(lvfontio_ondiskfont_t *self, void *ptr) {
4848

4949
// Forward declarations for helper functions
5050
static int16_t find_codepoint_slot(lvfontio_ondiskfont_t *self, uint32_t codepoint);
51+
static bool slot_has_active_full_width_partner(lvfontio_ondiskfont_t *self, uint16_t slot);
5152
static uint16_t find_free_slot(lvfontio_ondiskfont_t *self, uint32_t codepoint);
5253
static FRESULT read_bits(FIL *file, size_t num_bits, uint8_t *byte_val, uint8_t *remaining_bits, uint32_t *result);
5354
static FRESULT read_glyph_dimensions(FIL *file, lvfontio_ondiskfont_t *self, uint32_t *advance_width, int32_t *bbox_x, int32_t *bbox_y, uint32_t *bbox_w, uint32_t *bbox_h, uint8_t *byte_val, uint8_t *remaining_bits);
@@ -224,7 +225,12 @@ static bool load_font_header(lvfontio_ondiskfont_t *self, FIL *file, size_t *max
224225

225226
// Throw away the bitmap bits.
226227
read_bits(file, self->header.bits_per_pixel * bbox_w * bbox_h, &byte_val, &remaining_bits, NULL);
227-
if (advances[0] == glyph_advance) {
228+
229+
if (glyph_advance == 0) {
230+
// Ignore zero-advance glyphs when inferring the terminal cell width.
231+
// Some fonts include placeholders/control glyphs with zero advance,
232+
// which would otherwise skew default_advance_width too small.
233+
} else if (advances[0] == glyph_advance) {
228234
advance_count[0]++;
229235
} else if (advances[1] == glyph_advance) {
230236
advance_count[1]++;
@@ -257,6 +263,12 @@ static bool load_font_header(lvfontio_ondiskfont_t *self, FIL *file, size_t *max
257263
*max_slots = advance_count[0] + advance_count[1];
258264
}
259265

266+
if (self->header.default_advance_width == 0) {
267+
self->header.default_advance_width = 1;
268+
}
269+
if (*max_slots == 0) {
270+
*max_slots = 1;
271+
}
260272
found_glyf = true;
261273
}
262274

@@ -344,8 +356,9 @@ static int32_t get_char_id(lvfontio_ondiskfont_t *self, uint32_t codepoint) {
344356
for (size_t j = 0; j < self->cmap_ranges[i].entries_count; j++) {
345357
// Read code point at the index
346358
uint16_t candidate_codepoint_delta;
347-
res = f_read(&self->file, &candidate_codepoint_delta, 2, NULL);
348-
if (res != FR_OK) {
359+
UINT bytes_read;
360+
res = f_read(&self->file, &candidate_codepoint_delta, 2, &bytes_read);
361+
if (res != FR_OK || bytes_read < 2) {
349362
return -1;
350363
}
351364

@@ -574,18 +587,20 @@ int16_t common_hal_lvfontio_ondiskfont_cache_glyph(lvfontio_ondiskfont_t *self,
574587
// Check if already cached
575588
int16_t existing_slot = find_codepoint_slot(self, codepoint);
576589
if (existing_slot >= 0) {
577-
// Glyph is already cached, increment reference count
590+
// Glyph is already cached, increment reference count(s).
578591
self->reference_counts[existing_slot]++;
579592

580593
// Check if this is a full-width character by looking for a second slot
581-
// with the same codepoint right after this one
594+
// with the same codepoint right after this one, wrapping at the end.
595+
uint16_t next_slot = (existing_slot + 1) % self->max_glyphs;
596+
bool cached_is_full_width = self->codepoints[next_slot] == codepoint;
597+
598+
if (cached_is_full_width) {
599+
self->reference_counts[next_slot]++;
600+
}
601+
582602
if (is_full_width != NULL) {
583-
if (existing_slot + 1 < self->max_glyphs &&
584-
self->codepoints[existing_slot + 1] == codepoint) {
585-
*is_full_width = true;
586-
} else {
587-
*is_full_width = false;
588-
}
603+
*is_full_width = cached_is_full_width;
589604
}
590605

591606
return existing_slot;
@@ -722,12 +737,37 @@ static int16_t find_codepoint_slot(lvfontio_ondiskfont_t *self, uint32_t codepoi
722737
for (uint16_t i = 0; i < self->max_glyphs; i++) {
723738
int16_t slot = (i + offset) % self->max_glyphs;
724739
if (self->codepoints[slot] == codepoint) {
740+
// If this is the second slot of a full-width glyph pair, return the
741+
// first slot so callers always get a canonical index.
742+
if (slot > 0 && self->codepoints[slot - 1] == codepoint) {
743+
return slot - 1;
744+
}
725745
return slot;
726746
}
727747
}
728748
return -1;
729749
}
730750

751+
static bool slot_has_active_full_width_partner(lvfontio_ondiskfont_t *self, uint16_t slot) {
752+
uint32_t codepoint = self->codepoints[slot];
753+
if (codepoint == LVFONTIO_INVALID_CODEPOINT) {
754+
return false;
755+
}
756+
757+
// Don't evict one half of a full-width pair while the other half is still in use.
758+
uint16_t prev_slot = (slot + self->max_glyphs - 1) % self->max_glyphs;
759+
uint16_t next_slot = (slot + 1) % self->max_glyphs;
760+
761+
if (self->codepoints[prev_slot] == codepoint && self->reference_counts[prev_slot] > 0) {
762+
return true;
763+
}
764+
if (self->codepoints[next_slot] == codepoint && self->reference_counts[next_slot] > 0) {
765+
return true;
766+
}
767+
768+
return false;
769+
}
770+
731771
static uint16_t find_free_slot(lvfontio_ondiskfont_t *self, uint32_t codepoint) {
732772
size_t offset = codepoint % self->max_glyphs;
733773

@@ -739,10 +779,11 @@ static uint16_t find_free_slot(lvfontio_ondiskfont_t *self, uint32_t codepoint)
739779
}
740780
}
741781

742-
// If none found, look for slots with zero reference count, starting at the offset
782+
// If none found, look for slots with zero reference count, starting at the offset.
783+
// Avoid reusing one half of an active full-width glyph pair.
743784
for (uint16_t i = 0; i < self->max_glyphs; i++) {
744785
int16_t slot = (i + offset) % self->max_glyphs;
745-
if (self->reference_counts[slot] == 0) {
786+
if (self->reference_counts[slot] == 0 && !slot_has_active_full_width_partner(self, slot)) {
746787
return slot;
747788
}
748789
}

0 commit comments

Comments
 (0)