@@ -48,6 +48,7 @@ static inline void free_memory(lvfontio_ondiskfont_t *self, void *ptr) {
4848
4949// Forward declarations for helper functions
5050static 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 );
5152static uint16_t find_free_slot (lvfontio_ondiskfont_t * self , uint32_t codepoint );
5253static FRESULT read_bits (FIL * file , size_t num_bits , uint8_t * byte_val , uint8_t * remaining_bits , uint32_t * result );
5354static 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+
731767static 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