diff options
| author | Po Lu | 2023-08-23 09:08:03 +0800 |
|---|---|---|
| committer | Po Lu | 2023-08-23 09:15:16 +0800 |
| commit | d2e8985b8057173f56d081467ce6a69fc85b1dc5 (patch) | |
| tree | cf07ef5c9f0c06fdc7d754079396f12b356298dd /src | |
| parent | 255b7e1a046cbf9a745d58080d74983bfe205859 (diff) | |
| download | emacs-d2e8985b8057173f56d081467ce6a69fc85b1dc5.tar.gz emacs-d2e8985b8057173f56d081467ce6a69fc85b1dc5.zip | |
Fix compatibility problems with several fonts
* src/sfnt.c (sfnt_lookup_glyph_8): Perform binary search
instead of combing through each group if the table is large.
(sfnt_read_simple_glyph): Avoid losing if the last byte of a
vector is identical to the last byte of the glyph data.
(sfnt_read_gvar_table): Don't overwrite gvar table data while
reading shared coordinates.
Diffstat (limited to 'src')
| -rw-r--r-- | src/sfnt.c | 64 |
1 files changed, 45 insertions, 19 deletions
diff --git a/src/sfnt.c b/src/sfnt.c index e71ff9ae101..bf55e9302b0 100644 --- a/src/sfnt.c +++ b/src/sfnt.c | |||
| @@ -1262,6 +1262,19 @@ sfnt_lookup_glyph_6 (sfnt_char character, | |||
| 1262 | return format6->glyph_index_array[character - format6->first_code]; | 1262 | return format6->glyph_index_array[character - format6->first_code]; |
| 1263 | } | 1263 | } |
| 1264 | 1264 | ||
| 1265 | /* Compare the sfnt_char A with B's end code. Employed to bisect | ||
| 1266 | through a format 8 or 12 table. */ | ||
| 1267 | |||
| 1268 | static int | ||
| 1269 | sfnt_compare_char (const void *a, const void *b) | ||
| 1270 | { | ||
| 1271 | struct sfnt_cmap_format_8_or_12_group *group; | ||
| 1272 | |||
| 1273 | group = (struct sfnt_cmap_format_8_or_12_group *) b; | ||
| 1274 | |||
| 1275 | return ((int) *((sfnt_char *) a)) - group->end_char_code; | ||
| 1276 | } | ||
| 1277 | |||
| 1265 | /* Look up the glyph corresponding to CHARACTER in the format 8 cmap | 1278 | /* Look up the glyph corresponding to CHARACTER in the format 8 cmap |
| 1266 | FORMAT8. Return 0 if no glyph was found. */ | 1279 | FORMAT8. Return 0 if no glyph was found. */ |
| 1267 | 1280 | ||
| @@ -1270,10 +1283,35 @@ sfnt_lookup_glyph_8 (sfnt_char character, | |||
| 1270 | struct sfnt_cmap_format_8 *format8) | 1283 | struct sfnt_cmap_format_8 *format8) |
| 1271 | { | 1284 | { |
| 1272 | uint32_t i; | 1285 | uint32_t i; |
| 1286 | struct sfnt_cmap_format_8_or_12_group *group; | ||
| 1273 | 1287 | ||
| 1274 | if (character > 0xffffffff) | 1288 | if (character > 0xffffffff) |
| 1275 | return 0; | 1289 | return 0; |
| 1276 | 1290 | ||
| 1291 | if (format8->num_groups > 64) | ||
| 1292 | { | ||
| 1293 | /* This table is large, likely supplied by a CJK or similar | ||
| 1294 | font. Perform a binary search. */ | ||
| 1295 | |||
| 1296 | /* Find the group whose END_CHAR_CODE is greater than or equal | ||
| 1297 | to CHARACTER. */ | ||
| 1298 | |||
| 1299 | group = sfnt_bsearch_above (&character, format8->groups, | ||
| 1300 | format8->num_groups, | ||
| 1301 | sizeof format8->groups[0], | ||
| 1302 | sfnt_compare_char); | ||
| 1303 | |||
| 1304 | if (group->start_char_code > character) | ||
| 1305 | /* No glyph matches this group. */ | ||
| 1306 | return 0; | ||
| 1307 | |||
| 1308 | /* Otherwise, use this group to map the character to a | ||
| 1309 | glyph. */ | ||
| 1310 | return (group->start_glyph_code | ||
| 1311 | + character | ||
| 1312 | - group->start_char_code); | ||
| 1313 | } | ||
| 1314 | |||
| 1277 | for (i = 0; i < format8->num_groups; ++i) | 1315 | for (i = 0; i < format8->num_groups; ++i) |
| 1278 | { | 1316 | { |
| 1279 | if (format8->groups[i].start_char_code <= character | 1317 | if (format8->groups[i].start_char_code <= character |
| @@ -1286,19 +1324,6 @@ sfnt_lookup_glyph_8 (sfnt_char character, | |||
| 1286 | return 0; | 1324 | return 0; |
| 1287 | } | 1325 | } |
| 1288 | 1326 | ||
| 1289 | /* Compare the sfnt_char A with B's end code. Employed to bisect | ||
| 1290 | through a format 12 table. */ | ||
| 1291 | |||
| 1292 | static int | ||
| 1293 | sfnt_compare_char (const void *a, const void *b) | ||
| 1294 | { | ||
| 1295 | struct sfnt_cmap_format_8_or_12_group *group; | ||
| 1296 | |||
| 1297 | group = (struct sfnt_cmap_format_8_or_12_group *) b; | ||
| 1298 | |||
| 1299 | return ((int) *((sfnt_char *) a)) - group->end_char_code; | ||
| 1300 | } | ||
| 1301 | |||
| 1302 | /* Look up the glyph corresponding to CHARACTER in the format 12 cmap | 1327 | /* Look up the glyph corresponding to CHARACTER in the format 12 cmap |
| 1303 | FORMAT12. Return 0 if no glyph was found. */ | 1328 | FORMAT12. Return 0 if no glyph was found. */ |
| 1304 | 1329 | ||
| @@ -2009,7 +2034,7 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph, | |||
| 2009 | /* The next byte is a delta to apply to the previous | 2034 | /* The next byte is a delta to apply to the previous |
| 2010 | value. Make sure it is in bounds. */ | 2035 | value. Make sure it is in bounds. */ |
| 2011 | 2036 | ||
| 2012 | if (vec_start + 1 >= glyf->glyphs + glyf->size) | 2037 | if (vec_start + 1 > glyf->glyphs + glyf->size) |
| 2013 | { | 2038 | { |
| 2014 | glyph->simple = NULL; | 2039 | glyph->simple = NULL; |
| 2015 | xfree (simple); | 2040 | xfree (simple); |
| @@ -2026,7 +2051,7 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph, | |||
| 2026 | /* The next word is a delta to apply to the previous value. | 2051 | /* The next word is a delta to apply to the previous value. |
| 2027 | Make sure it is in bounds. */ | 2052 | Make sure it is in bounds. */ |
| 2028 | 2053 | ||
| 2029 | if (vec_start + 2 >= glyf->glyphs + glyf->size) | 2054 | if (vec_start + 2 > glyf->glyphs + glyf->size) |
| 2030 | { | 2055 | { |
| 2031 | glyph->simple = NULL; | 2056 | glyph->simple = NULL; |
| 2032 | xfree (simple); | 2057 | xfree (simple); |
| @@ -2061,7 +2086,7 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph, | |||
| 2061 | /* The next byte is a delta to apply to the previous | 2086 | /* The next byte is a delta to apply to the previous |
| 2062 | value. Make sure it is in bounds. */ | 2087 | value. Make sure it is in bounds. */ |
| 2063 | 2088 | ||
| 2064 | if (vec_start + 1 >= glyf->glyphs + glyf->size) | 2089 | if (vec_start + 1 > glyf->glyphs + glyf->size) |
| 2065 | { | 2090 | { |
| 2066 | glyph->simple = NULL; | 2091 | glyph->simple = NULL; |
| 2067 | xfree (simple); | 2092 | xfree (simple); |
| @@ -2078,7 +2103,7 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph, | |||
| 2078 | /* The next word is a delta to apply to the previous value. | 2103 | /* The next word is a delta to apply to the previous value. |
| 2079 | Make sure it is in bounds. */ | 2104 | Make sure it is in bounds. */ |
| 2080 | 2105 | ||
| 2081 | if (vec_start + 2 >= glyf->glyphs + glyf->size) | 2106 | if (vec_start + 2 > glyf->glyphs + glyf->size) |
| 2082 | { | 2107 | { |
| 2083 | glyph->simple = NULL; | 2108 | glyph->simple = NULL; |
| 2084 | xfree (simple); | 2109 | xfree (simple); |
| @@ -13184,7 +13209,8 @@ sfnt_read_gvar_table (int fd, struct sfnt_offset_subtable *subtable) | |||
| 13184 | 13209 | ||
| 13185 | /* Start reading shared coordinates. */ | 13210 | /* Start reading shared coordinates. */ |
| 13186 | 13211 | ||
| 13187 | gvar->global_coords = ((sfnt_f2dot14 *) ((char *) gvar + off_size)); | 13212 | gvar->global_coords = ((sfnt_f2dot14 *) ((char *) (gvar + 1) |
| 13213 | + off_size)); | ||
| 13188 | 13214 | ||
| 13189 | if (gvar->shared_coord_count) | 13215 | if (gvar->shared_coord_count) |
| 13190 | { | 13216 | { |
| @@ -13199,7 +13225,7 @@ sfnt_read_gvar_table (int fd, struct sfnt_offset_subtable *subtable) | |||
| 13199 | != coordinate_size) | 13225 | != coordinate_size) |
| 13200 | goto bail; | 13226 | goto bail; |
| 13201 | 13227 | ||
| 13202 | for (i = 0; i <= coordinate_size / sizeof *gvar->global_coords; ++i) | 13228 | for (i = 0; i < coordinate_size / sizeof *gvar->global_coords; ++i) |
| 13203 | sfnt_swap16 (&gvar->global_coords[i]); | 13229 | sfnt_swap16 (&gvar->global_coords[i]); |
| 13204 | } | 13230 | } |
| 13205 | 13231 | ||