aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2023-08-24 16:32:42 +0800
committerPo Lu2023-08-24 16:36:13 +0800
commitad5e17d0638be46f982d1448e8fef1d28d224735 (patch)
treecd9fd66de4de975c1624d41ef9a5603d8ba2f081 /src
parentb9917f11521d47426330d79c65f9726c8fd7f8f7 (diff)
downloademacs-ad5e17d0638be46f982d1448e8fef1d28d224735.tar.gz
emacs-ad5e17d0638be46f982d1448e8fef1d28d224735.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/sfnt.c26
-rw-r--r--src/sfnt.h3
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,
432 int seg_count, i; 432 int seg_count, i;
433 433
434 min_bytes = SFNT_ENDOF (struct sfnt_cmap_format_4, 434 min_bytes = SFNT_ENDOF (struct sfnt_cmap_format_4,
435 entry_selector, uint16_t); 435 range_shift, uint16_t);
436 436
437 /* Check that the length is at least min_bytes. */ 437 /* Check that the length is at least min_bytes. */
438 if (header->length < min_bytes) 438 if (header->length < min_bytes)
@@ -460,6 +460,7 @@ sfnt_read_cmap_format_4 (int fd,
460 sfnt_swap16 (&format4->seg_count_x2); 460 sfnt_swap16 (&format4->seg_count_x2);
461 sfnt_swap16 (&format4->search_range); 461 sfnt_swap16 (&format4->search_range);
462 sfnt_swap16 (&format4->entry_selector); 462 sfnt_swap16 (&format4->entry_selector);
463 sfnt_swap16 (&format4->range_shift);
463 464
464 /* Get the number of segments to read. */ 465 /* Get the number of segments to read. */
465 seg_count = format4->seg_count_x2 / 2; 466 seg_count = format4->seg_count_x2 / 2;
@@ -467,7 +468,7 @@ sfnt_read_cmap_format_4 (int fd,
467 /* Now calculate whether or not the size is sufficiently large. */ 468 /* Now calculate whether or not the size is sufficiently large. */
468 bytes_minus_format4 469 bytes_minus_format4
469 = format4->length - SFNT_ENDOF (struct sfnt_cmap_format_4, 470 = format4->length - SFNT_ENDOF (struct sfnt_cmap_format_4,
470 entry_selector, uint16_t); 471 range_shift, uint16_t);
471 variable_size = (seg_count * sizeof *format4->end_code 472 variable_size = (seg_count * sizeof *format4->end_code
472 + sizeof *format4->reserved_pad 473 + sizeof *format4->reserved_pad
473 + seg_count * sizeof *format4->start_code 474 + seg_count * sizeof *format4->start_code
@@ -1222,27 +1223,6 @@ sfnt_lookup_glyph_4 (sfnt_char character,
1222 if (glyph) 1223 if (glyph)
1223 return glyph; 1224 return glyph;
1224 1225
1225 /* Droid Sans Mono has overlapping segments in its format 4 cmap
1226 subtable where the first segment's end code is 32, while the
1227 second segment's start code is also 32. The TrueType Reference
1228 Manual says that mapping should begin by searching for the first
1229 segment whose end code is greater than or equal to the character
1230 being indexed, but that results in the first subtable being
1231 found, which doesn't work, while the second table does. Try to
1232 detect this situation and use the second table if possible. */
1233
1234 if (!glyph
1235 /* The character being looked up is the current segment's end
1236 code. */
1237 && code == format4->end_code[segment]
1238 /* There is an additional segment. */
1239 && segment + 1 < format4->seg_count_x2 / 2
1240 /* That segment's start code is the same as this segment's end
1241 code. */
1242 && format4->start_code[segment + 1] == format4->end_code[segment])
1243 /* Try the second segment. */
1244 return sfnt_lookup_glyph_4_1 (character, segment + 1, format4);
1245
1246 /* Fail. */ 1226 /* Fail. */
1247 return 0; 1227 return 0;
1248} 1228}
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
364 /* log2(searchRange/2) */ 364 /* log2(searchRange/2) */
365 uint16_t entry_selector; 365 uint16_t entry_selector;
366 366
367 /* (2 * segCount) - searchRange */
368 uint16_t range_shift;
369
367 /* Variable-length data. */ 370 /* Variable-length data. */
368 uint16_t *end_code; 371 uint16_t *end_code;
369 uint16_t *reserved_pad; 372 uint16_t *reserved_pad;