aboutsummaryrefslogtreecommitdiffstats
path: root/text/shape-build.c
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-09-28 16:04:05 +0100
committereunhhu <[email protected]>2026-09-28 16:04:05 +0100
commit960fa21762484d3014a6778a7673f15acf2d34bb (patch)
tree9e9a38a919b3cb8ed82c84524b7dd72b289ce49e /text/shape-build.c
parentddbbc39cc65946f59298eab546c906ad3dea6841 (diff)
downloadvega-960fa21762484d3014a6778a7673f15acf2d34bb.tar.gz
vega-960fa21762484d3014a6778a7673f15acf2d34bb.zip
Map characters as HarfBuzz maps them, not as it lists them
The shaping section's character map came from hb_face_collect_unicodes. HarfBuzz's own suite showed where that list and its mapping part: it cuts a format 13 map short (AdobeBlank2's whole Unicode to one glyph), and a symbol map (3,0) it searches through the private use area, Latin and, in an old Arabic font, Arabic too. Now every code point is asked with hb_font_get_nominal_glyph (about 30 ms a font) and the map carried as groups: codes going to consecutive glyphs, or all to one (12 bytes each, so a format 13 map stays small). HarfBuzz's suite: 5011 of 5199 cases the same (1355 before). The installed fonts (213) and the Noto ones (21) still shape as HarfBuzz does on random runs.
Diffstat (limited to 'text/shape-build.c')
-rw-r--r--text/shape-build.c48
1 files changed, 36 insertions, 12 deletions
diff --git a/text/shape-build.c b/text/shape-build.c
index 7cb251d..fac333b 100644
--- a/text/shape-build.c
+++ b/text/shape-build.c
@@ -914,11 +914,40 @@ bool vega_shaping_compile(hb_face_t *face, const uint32_t *scripts, size_t scrip
}
unsigned glyph_count = hb_face_get_glyph_count(face);
if (glyph_count > 65535) FAIL("more than 65535 glyphs");
- hb_face_collect_unicodes(face, unicodes);
- uint32_t cmap_count = 0;
- for (hb_codepoint_t u = HB_SET_VALUE_INVALID; hb_set_next(unicodes, &u);) {
+ /* The character map as HarfBuzz maps, not as it lists (a format 13 map
+ * it lists cut short, a symbol map it maps into the private use area):
+ * every code point asked, in groups of codes going to consecutive
+ * glyphs, or all to one. */
+ uint32_t *groups = NULL, group_count = 0, allocated = 0;
+ for (hb_codepoint_t u = 0; u <= 0x10FFFF; ++u) {
hb_codepoint_t g;
- if (hb_font_get_nominal_glyph(font, u, &g) && g) cmap_count++;
+ if (!hb_font_get_nominal_glyph(font, u, &g) || !g) continue;
+ hb_set_add(unicodes, u);
+ if (group_count) {
+ uint32_t *last = groups + 3 * (group_count - 1), glyph = last[2] & 0x7FFFFFFF;
+ bool single = last[0] == last[1], same = last[2] >> 31;
+ if (last[1] + 1 == u && ((single || !same) && g == glyph + (u - last[0]))) {
+ last[1] = u;
+ continue;
+ }
+ if (last[1] + 1 == u && (single || same) && g == glyph) {
+ last[1] = u;
+ last[2] = glyph | 0x80000000u;
+ continue;
+ }
+ }
+ if (group_count == allocated) {
+ allocated = allocated ? 2 * allocated : 256;
+ uint32_t *grown = realloc(groups, 3 * (size_t)allocated * sizeof(*groups));
+ if (!grown) {
+ free(groups);
+ FAIL("out of memory");
+ }
+ groups = grown;
+ }
+ uint32_t *next = groups + 3 * group_count++;
+ next[0] = next[1] = u;
+ next[2] = g;
}
hb_blob_t *tables[3] = {hb_face_reference_table(face, HB_OT_TAG_GDEF), hb_face_reference_table(face, HB_OT_TAG_GSUB),
hb_face_reference_table(face, HB_OT_TAG_GPOS)};
@@ -928,15 +957,10 @@ bool vega_shaping_compile(hb_face_t *face, const uint32_t *scripts, size_t scrip
put16(&o, hb_face_get_upem(face));
put16(&o, glyph_count);
for (int i = 0; i < 17; ++i) put32(&o, 0);
- set32(&o, 12, cmap_count);
+ set32(&o, 12, group_count);
set32(&o, 16, (uint32_t)o.size);
- for (hb_codepoint_t u = HB_SET_VALUE_INVALID; hb_set_next(unicodes, &u);) {
- hb_codepoint_t g;
- if (hb_font_get_nominal_glyph(font, u, &g) && g) {
- put32(&o, u);
- put32(&o, g);
- }
- }
+ for (uint32_t i = 0; i < 3 * group_count; ++i) put32(&o, groups[i]);
+ free(groups);
set32(&o, 20, (uint32_t)o.size);
for (unsigned g = 0; g < glyph_count; ++g) {
hb_position_t advance = hb_font_get_glyph_h_advance(font, g);