Skip to content

Commit 907360e

Browse files
committed
fix default_advance_width calculation, fix f_read(_,NULL) call, fix second slot of full width glyph overriding
1 parent f75864d commit 907360e

File tree

1 file changed

+62
-25
lines changed

1 file changed

+62
-25
lines changed

shared-module/lvfontio/OnDiskFont.c

Lines changed: 62 additions & 25 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,18 +225,24 @@ 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-
advance_count[0]++;
229-
} else if (advances[1] == glyph_advance) {
230-
advance_count[1]++;
231-
} else if (advance_count[0] == 0) {
232-
advances[0] = glyph_advance;
233-
advance_count[0] = 1;
234-
} else if (advance_count[1] == 0) {
235-
advances[1] = glyph_advance;
236-
advance_count[1] = 1;
237-
} else {
238-
break;
228+
229+
// Ignore zero-advance glyphs when inferring the terminal cell width.
230+
// Some fonts include placeholders/control glyphs with zero advance,
231+
// which would otherwise skew default_advance_width too small.
232+
if (glyph_advance > 0) {
233+
if (advances[0] == glyph_advance) {
234+
advance_count[0]++;
235+
} else if (advances[1] == glyph_advance) {
236+
advance_count[1]++;
237+
} else if (advance_count[0] == 0) {
238+
advances[0] = glyph_advance;
239+
advance_count[0] = 1;
240+
} else if (advance_count[1] == 0) {
241+
advances[1] = glyph_advance;
242+
advance_count[1] = 1;
243+
} else {
244+
break;
245+
}
239246
}
240247
cid++;
241248
}
@@ -257,6 +264,12 @@ static bool load_font_header(lvfontio_ondiskfont_t *self, FIL *file, size_t *max
257264
*max_slots = advance_count[0] + advance_count[1];
258265
}
259266

267+
if (self->header.default_advance_width == 0) {
268+
self->header.default_advance_width = 1;
269+
}
270+
if (*max_slots == 0) {
271+
*max_slots = 1;
272+
}
260273
found_glyf = true;
261274
}
262275

@@ -344,8 +357,9 @@ static int32_t get_char_id(lvfontio_ondiskfont_t *self, uint32_t codepoint) {
344357
for (size_t j = 0; j < self->cmap_ranges[i].entries_count; j++) {
345358
// Read code point at the index
346359
uint16_t candidate_codepoint_delta;
347-
res = f_read(&self->file, &candidate_codepoint_delta, 2, NULL);
348-
if (res != FR_OK) {
360+
UINT bytes_read;
361+
res = f_read(&self->file, &candidate_codepoint_delta, 2, &bytes_read);
362+
if (res != FR_OK || bytes_read < 2) {
349363
return -1;
350364
}
351365

@@ -574,18 +588,18 @@ int16_t common_hal_lvfontio_ondiskfont_cache_glyph(lvfontio_ondiskfont_t *self,
574588
// Check if already cached
575589
int16_t existing_slot = find_codepoint_slot(self, codepoint);
576590
if (existing_slot >= 0) {
577-
// Glyph is already cached, increment reference count
591+
// Glyph is already cached, increment reference count(s).
578592
self->reference_counts[existing_slot]++;
579593

580-
// Check if this is a full-width character by looking for a second slot
581-
// with the same codepoint right after this one
594+
bool cached_is_full_width = existing_slot + 1 < self->max_glyphs &&
595+
self->codepoints[existing_slot + 1] == codepoint;
596+
597+
if (cached_is_full_width) {
598+
self->reference_counts[existing_slot + 1]++;
599+
}
600+
582601
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-
}
602+
*is_full_width = cached_is_full_width;
589603
}
590604

591605
return existing_slot;
@@ -722,12 +736,34 @@ static int16_t find_codepoint_slot(lvfontio_ondiskfont_t *self, uint32_t codepoi
722736
for (uint16_t i = 0; i < self->max_glyphs; i++) {
723737
int16_t slot = (i + offset) % self->max_glyphs;
724738
if (self->codepoints[slot] == codepoint) {
739+
// If this is the second slot of a full-width glyph pair, return the
740+
// first slot so callers always get a canonical index.
741+
if (slot > 0 && self->codepoints[slot - 1] == codepoint) {
742+
return slot - 1;
743+
}
725744
return slot;
726745
}
727746
}
728747
return -1;
729748
}
730749

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

@@ -739,10 +775,11 @@ static uint16_t find_free_slot(lvfontio_ondiskfont_t *self, uint32_t codepoint)
739775
}
740776
}
741777

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

0 commit comments

Comments
 (0)