From ad5e17d0638be46f982d1448e8fef1d28d224735 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Thu, 24 Aug 2023 16:32:42 +0800 Subject: [PATCH] Properly parse format 4 cmap tables * src/sfnt.c (sfnt_read_cmap_format_4): Read range_shift field propery. Prior to this, it would be inadvertently treated as an entry within the segment end code array, which only functioned by happenstance. (sfnt_lookup_glyph_4): Remove workaround grounded upon an erroneous interpretation of the bug fixed by the aformentioned change. * src/sfnt.h (struct sfnt_cmap_format_4): Introduce previously absent `range_shift' field. --- src/sfnt.c | 26 +++----------------------- src/sfnt.h | 3 +++ 2 files changed, 6 insertions(+), 23 deletions(-) diff --git a/src/sfnt.c b/src/sfnt.c index c987ec42441..87a11019b13 100644 --- a/src/sfnt.c +++ b/src/sfnt.c @@ -432,7 +432,7 @@ sfnt_read_cmap_format_4 (int fd, int seg_count, i; min_bytes = SFNT_ENDOF (struct sfnt_cmap_format_4, - entry_selector, uint16_t); + range_shift, uint16_t); /* Check that the length is at least min_bytes. */ if (header->length < min_bytes) @@ -460,6 +460,7 @@ sfnt_read_cmap_format_4 (int fd, sfnt_swap16 (&format4->seg_count_x2); sfnt_swap16 (&format4->search_range); sfnt_swap16 (&format4->entry_selector); + sfnt_swap16 (&format4->range_shift); /* Get the number of segments to read. */ seg_count = format4->seg_count_x2 / 2; @@ -467,7 +468,7 @@ sfnt_read_cmap_format_4 (int fd, /* Now calculate whether or not the size is sufficiently large. */ bytes_minus_format4 = format4->length - SFNT_ENDOF (struct sfnt_cmap_format_4, - entry_selector, uint16_t); + range_shift, uint16_t); variable_size = (seg_count * sizeof *format4->end_code + sizeof *format4->reserved_pad + seg_count * sizeof *format4->start_code @@ -1222,27 +1223,6 @@ sfnt_lookup_glyph_4 (sfnt_char character, if (glyph) return glyph; - /* Droid Sans Mono has overlapping segments in its format 4 cmap - subtable where the first segment's end code is 32, while the - second segment's start code is also 32. The TrueType Reference - Manual says that mapping should begin by searching for the first - segment whose end code is greater than or equal to the character - being indexed, but that results in the first subtable being - found, which doesn't work, while the second table does. Try to - detect this situation and use the second table if possible. */ - - if (!glyph - /* The character being looked up is the current segment's end - code. */ - && code == format4->end_code[segment] - /* There is an additional segment. */ - && segment + 1 < format4->seg_count_x2 / 2 - /* That segment's start code is the same as this segment's end - code. */ - && format4->start_code[segment + 1] == format4->end_code[segment]) - /* Try the second segment. */ - return sfnt_lookup_glyph_4_1 (character, segment + 1, format4); - /* Fail. */ return 0; } diff --git a/src/sfnt.h b/src/sfnt.h index 0fb67e918a6..1a6b2209abc 100644 --- a/src/sfnt.h +++ b/src/sfnt.h @@ -364,6 +364,9 @@ struct sfnt_cmap_format_4 /* log2(searchRange/2) */ uint16_t entry_selector; + /* (2 * segCount) - searchRange */ + uint16_t range_shift; + /* Variable-length data. */ uint16_t *end_code; uint16_t *reserved_pad; -- 2.39.2