Merge pull request #2894 from googlefonts/gpos_2

[subset] Update PairPosFormat2 subsetting to match fontTools
This commit is contained in:
Behdad Esfahbod 2021-03-17 10:20:59 -07:00 committed by GitHub
commit 5f4c321d4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 44 additions and 26 deletions

View File

@ -88,10 +88,10 @@ static inline void ClassDef_serialize (hb_serialize_context_t *c,
Iterator it); Iterator it);
static void ClassDef_remap_and_serialize (hb_serialize_context_t *c, static void ClassDef_remap_and_serialize (hb_serialize_context_t *c,
const hb_set_t &glyphset,
const hb_map_t &gid_klass_map, const hb_map_t &gid_klass_map,
hb_sorted_vector_t<HBGlyphID> &glyphs, hb_sorted_vector_t<HBGlyphID> &glyphs,
const hb_set_t &klasses, const hb_set_t &klasses,
bool use_class_zero,
hb_map_t *klass_map /*INOUT*/); hb_map_t *klass_map /*INOUT*/);
struct hb_subset_layout_context_t : struct hb_subset_layout_context_t :
@ -1645,10 +1645,10 @@ Coverage_serialize (hb_serialize_context_t *c,
{ c->start_embed<Coverage> ()->serialize (c, it); } { c->start_embed<Coverage> ()->serialize (c, it); }
static void ClassDef_remap_and_serialize (hb_serialize_context_t *c, static void ClassDef_remap_and_serialize (hb_serialize_context_t *c,
const hb_set_t &glyphset,
const hb_map_t &gid_klass_map, const hb_map_t &gid_klass_map,
hb_sorted_vector_t<HBGlyphID> &glyphs, hb_sorted_vector_t<HBGlyphID> &glyphs,
const hb_set_t &klasses, const hb_set_t &klasses,
bool use_class_zero,
hb_map_t *klass_map /*INOUT*/) hb_map_t *klass_map /*INOUT*/)
{ {
if (!klass_map) if (!klass_map)
@ -1660,7 +1660,7 @@ static void ClassDef_remap_and_serialize (hb_serialize_context_t *c,
/* any glyph not assigned a class value falls into Class zero (0), /* any glyph not assigned a class value falls into Class zero (0),
* if any glyph assigned to class 0, remapping must start with 0->0*/ * if any glyph assigned to class 0, remapping must start with 0->0*/
if (glyphset.get_population () > gid_klass_map.get_population ()) if (!use_class_zero)
klass_map->set (0, 0); klass_map->set (0, 0);
unsigned idx = klass_map->has (0) ? 1 : 0; unsigned idx = klass_map->has (0) ? 1 : 0;
@ -1730,7 +1730,9 @@ struct ClassDefFormat1
} }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
hb_map_t *klass_map = nullptr /*OUT*/) const hb_map_t *klass_map = nullptr /*OUT*/,
bool use_class_zero = true,
const Coverage* glyph_filter = nullptr) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub (); const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
@ -1742,9 +1744,12 @@ struct ClassDefFormat1
hb_codepoint_t start = startGlyph; hb_codepoint_t start = startGlyph;
hb_codepoint_t end = start + classValue.len; hb_codepoint_t end = start + classValue.len;
for (const hb_codepoint_t gid : + hb_range (start, end) for (const hb_codepoint_t gid : + hb_range (start, end)
| hb_filter (glyphset)) | hb_filter (glyphset))
{ {
if (glyph_filter && !glyph_filter->has(gid)) continue;
unsigned klass = classValue[gid - start]; unsigned klass = classValue[gid - start];
if (!klass) continue; if (!klass) continue;
@ -1753,8 +1758,12 @@ struct ClassDefFormat1
orig_klasses.add (klass); orig_klasses.add (klass);
} }
ClassDef_remap_and_serialize (c->serializer, glyphset, gid_org_klass_map, unsigned glyph_count = glyph_filter
glyphs, orig_klasses, klass_map); ? hb_len (hb_iter (glyphset) | hb_filter (glyph_filter))
: glyphset.get_population ();
use_class_zero = use_class_zero && glyph_count <= gid_org_klass_map.get_population ();
ClassDef_remap_and_serialize (c->serializer, gid_org_klass_map,
glyphs, orig_klasses, use_class_zero, klass_map);
return_trace ((bool) glyphs); return_trace ((bool) glyphs);
} }
@ -1903,7 +1912,9 @@ struct ClassDefFormat2
} }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
hb_map_t *klass_map = nullptr /*OUT*/) const hb_map_t *klass_map = nullptr /*OUT*/,
bool use_class_zero = true,
const Coverage* glyph_filter = nullptr) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub (); const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
@ -1923,14 +1934,19 @@ struct ClassDefFormat2
for (hb_codepoint_t g = start; g < end; g++) for (hb_codepoint_t g = start; g < end; g++)
{ {
if (!glyphset.has (g)) continue; if (!glyphset.has (g)) continue;
if (glyph_filter && !glyph_filter->has (g)) continue;
glyphs.push (glyph_map[g]); glyphs.push (glyph_map[g]);
gid_org_klass_map.set (glyph_map[g], klass); gid_org_klass_map.set (glyph_map[g], klass);
orig_klasses.add (klass); orig_klasses.add (klass);
} }
} }
ClassDef_remap_and_serialize (c->serializer, glyphset, gid_org_klass_map, unsigned glyph_count = glyph_filter
glyphs, orig_klasses, klass_map); ? hb_len (hb_iter (glyphset) | hb_filter (glyph_filter))
: glyphset.get_population ();
use_class_zero = use_class_zero && glyph_count <= gid_org_klass_map.get_population ();
ClassDef_remap_and_serialize (c->serializer, gid_org_klass_map,
glyphs, orig_klasses, use_class_zero, klass_map);
return_trace ((bool) glyphs); return_trace ((bool) glyphs);
} }
@ -2045,10 +2061,9 @@ struct ClassDef
if (likely (it)) if (likely (it))
{ {
hb_codepoint_t glyph_min = (*it).first; hb_codepoint_t glyph_min = (*it).first;
hb_codepoint_t glyph_max = + it hb_codepoint_t glyph_max = glyph_min;
| hb_map (hb_first)
| hb_reduce (hb_max, 0u);
unsigned num_glyphs = 0;
unsigned num_ranges = 1; unsigned num_ranges = 1;
hb_codepoint_t prev_gid = glyph_min; hb_codepoint_t prev_gid = glyph_min;
unsigned prev_klass = (*it).second; unsigned prev_klass = (*it).second;
@ -2057,7 +2072,9 @@ struct ClassDef
{ {
hb_codepoint_t cur_gid = gid_klass_pair.first; hb_codepoint_t cur_gid = gid_klass_pair.first;
unsigned cur_klass = gid_klass_pair.second; unsigned cur_klass = gid_klass_pair.second;
if (cur_klass) num_glyphs++;
if (cur_gid == glyph_min || !cur_klass) continue; if (cur_gid == glyph_min || !cur_klass) continue;
if (cur_gid > glyph_max) glyph_max = cur_gid;
if (cur_gid != prev_gid + 1 || if (cur_gid != prev_gid + 1 ||
cur_klass != prev_klass) cur_klass != prev_klass)
num_ranges++; num_ranges++;
@ -2066,7 +2083,7 @@ struct ClassDef
prev_klass = cur_klass; prev_klass = cur_klass;
} }
if (1 + (glyph_max - glyph_min + 1) <= num_ranges * 3) if (num_glyphs && 1 + (glyph_max - glyph_min + 1) <= num_ranges * 3)
format = 1; format = 1;
} }
u.format = format; u.format = format;
@ -2080,12 +2097,14 @@ struct ClassDef
} }
bool subset (hb_subset_context_t *c, bool subset (hb_subset_context_t *c,
hb_map_t *klass_map = nullptr /*OUT*/) const hb_map_t *klass_map = nullptr /*OUT*/,
bool use_class_zero = true,
const Coverage* glyph_filter = nullptr) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
switch (u.format) { switch (u.format) {
case 1: return_trace (u.format1.subset (c, klass_map)); case 1: return_trace (u.format1.subset (c, klass_map, use_class_zero, glyph_filter));
case 2: return_trace (u.format2.subset (c, klass_map)); case 2: return_trace (u.format2.subset (c, klass_map, use_class_zero, glyph_filter));
default:return_trace (false); default:return_trace (false);
} }
} }

View File

@ -1358,7 +1358,7 @@ struct PairPosFormat2
if ((!valueFormat1.has_device ()) && (!valueFormat2.has_device ())) return; if ((!valueFormat1.has_device ()) && (!valueFormat2.has_device ())) return;
hb_set_t class1_set, class2_set; hb_set_t class1_set, class2_set;
for (const unsigned cp : c->glyph_set->iter ()) for (const unsigned cp : + c->glyph_set->iter () | hb_filter (this + coverage))
{ {
unsigned klass1 = (this+classDef1).get (cp); unsigned klass1 = (this+classDef1).get (cp);
unsigned klass2 = (this+classDef2).get (cp); unsigned klass2 = (this+classDef2).get (cp);
@ -1366,7 +1366,10 @@ struct PairPosFormat2
class2_set.add (klass2); class2_set.add (klass2);
} }
if (class1_set.is_empty () || class2_set.is_empty ()) return; if (class1_set.is_empty ()
|| class2_set.is_empty ()
|| (class2_set.get_population() == 1 && class2_set.has(0)))
return;
unsigned len1 = valueFormat1.get_len (); unsigned len1 = valueFormat1.get_len ();
unsigned len2 = valueFormat2.get_len (); unsigned len2 = valueFormat2.get_len ();
@ -1435,11 +1438,11 @@ struct PairPosFormat2
out->valueFormat2 = valueFormat2; out->valueFormat2 = valueFormat2;
hb_map_t klass1_map; hb_map_t klass1_map;
out->classDef1.serialize_subset (c, classDef1, this, &klass1_map); out->classDef1.serialize_subset (c, classDef1, this, &klass1_map, true, &(this + coverage));
out->class1Count = klass1_map.get_population (); out->class1Count = klass1_map.get_population ();
hb_map_t klass2_map; hb_map_t klass2_map;
out->classDef2.serialize_subset (c, classDef2, this, &klass2_map); out->classDef2.serialize_subset (c, classDef2, this, &klass2_map, false);
out->class2Count = klass2_map.get_population (); out->class2Count = klass2_map.get_population ();
unsigned len1 = valueFormat1.get_len (); unsigned len1 = valueFormat1.get_len ();

View File

@ -32,7 +32,6 @@
static void static void
test_subset_gpos_lookup_subtable (void) test_subset_gpos_lookup_subtable (void)
{ {
#ifdef HB_EXPERIMENTAL_API
hb_face_t *face_pwa = hb_test_open_font_file ("fonts/Roboto-Regular-gpos-.aw.ttf"); hb_face_t *face_pwa = hb_test_open_font_file ("fonts/Roboto-Regular-gpos-.aw.ttf");
hb_face_t *face_wa = hb_test_open_font_file ("fonts/Roboto-Regular-gpos-aw.ttf"); hb_face_t *face_wa = hb_test_open_font_file ("fonts/Roboto-Regular-gpos-aw.ttf");
@ -53,14 +52,11 @@ test_subset_gpos_lookup_subtable (void)
hb_face_destroy (face_pwa_subset); hb_face_destroy (face_pwa_subset);
hb_face_destroy (face_pwa); hb_face_destroy (face_pwa);
hb_face_destroy (face_wa); hb_face_destroy (face_wa);
#endif
} }
/* TODO: Once GDEF subsetting is implemented, this test may fail & expected result need update. */
static void static void
test_subset_gpos_pairpos1_vf (void) test_subset_gpos_pairpos1_vf (void)
{ {
#ifdef HB_EXPERIMENTAL_API
hb_face_t *face_wav = hb_test_open_font_file ("fonts/AdobeVFPrototype.WAV.gpos.otf"); hb_face_t *face_wav = hb_test_open_font_file ("fonts/AdobeVFPrototype.WAV.gpos.otf");
hb_face_t *face_wa = hb_test_open_font_file ("fonts/AdobeVFPrototype.WA.gpos.otf"); hb_face_t *face_wa = hb_test_open_font_file ("fonts/AdobeVFPrototype.WA.gpos.otf");
@ -81,7 +77,6 @@ test_subset_gpos_pairpos1_vf (void)
hb_face_destroy (face_wav_subset); hb_face_destroy (face_wav_subset);
hb_face_destroy (face_wav); hb_face_destroy (face_wav);
hb_face_destroy (face_wa); hb_face_destroy (face_wa);
#endif
} }
int int

View File

@ -9,5 +9,6 @@ keep-layout-retain-gids.txt
SUBSETS: SUBSETS:
!# !#
!#% !#%
.#
ABC ABC
* *