[HarfBuzz] harfbuzz: Branch 'master' - 9 commits

Behdad Esfahbod behdad at kemper.freedesktop.org
Sun Jun 10 21:25:24 UTC 2018


 src/hb-face.cc                              |    2 -
 src/hb-ft.cc                                |    8 ++--
 src/hb-ot-layout.cc                         |   32 ++++++++++++++++
 src/hb-ot-layout.h                          |    6 +++
 src/hb-ot-shape.cc                          |   10 -----
 src/hb-private.hh                           |    2 -
 src/hb-subset-input.cc                      |   17 ++++++++
 src/hb-subset-plan.cc                       |   21 +++++++++-
 src/hb-subset-plan.hh                       |    1 
 src/hb-subset-private.hh                    |    1 
 src/hb-subset.cc                            |    5 +-
 src/hb-subset.h                             |    3 +
 test/api/fonts/Roboto-Regular.gsub.fi.ttf   |binary
 test/api/fonts/Roboto-Regular.gsub.fil.ttf  |binary
 test/api/fonts/Roboto-Regular.nogsub.fi.ttf |binary
 test/api/test-subset-glyf.c                 |   56 +++++++++++++++++++++++++++-
 test/fuzzing/hb-subset-fuzzer.cc            |   27 ++++++++++---
 17 files changed, 163 insertions(+), 28 deletions(-)

New commits:
commit b8e406f0c7c381d46e2d2bbe35a6107d560f2122
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun Jun 10 17:22:38 2018 -0400

    More fixes for SunStudio 12.6 build
    
    Followup to https://github.com/harfbuzz/harfbuzz/pull/1053

diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index 69132386..7caafba8 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -119,7 +119,7 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
   if (font->immutable)
     return;
 
-  if (font->destroy != _hb_ft_font_destroy)
+  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
     return;
 
   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
@@ -139,7 +139,7 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
 int
 hb_ft_font_get_load_flags (hb_font_t *font)
 {
-  if (font->destroy != _hb_ft_font_destroy)
+  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
     return 0;
 
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
@@ -150,7 +150,7 @@ hb_ft_font_get_load_flags (hb_font_t *font)
 FT_Face
 hb_ft_font_get_face (hb_font_t *font)
 {
-  if (font->destroy != _hb_ft_font_destroy)
+  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
     return nullptr;
 
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
@@ -615,7 +615,7 @@ hb_ft_font_create (FT_Face           ft_face,
 void
 hb_ft_font_changed (hb_font_t *font)
 {
-  if (font->destroy != _hb_ft_font_destroy)
+  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
     return;
 
   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
diff --git a/src/hb-subset.cc b/src/hb-subset.cc
index 906327b8..4098832b 100644
--- a/src/hb-subset.cc
+++ b/src/hb-subset.cc
@@ -221,7 +221,7 @@ hb_subset_face_create (void)
 hb_bool_t
 hb_subset_face_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
 {
-  if (unlikely (face->destroy != _hb_subset_face_data_destroy))
+  if (unlikely (face->destroy != (hb_destroy_func_t) _hb_subset_face_data_destroy))
     return false;
 
   hb_subset_face_data_t *data = (hb_subset_face_data_t *) face->user_data;
commit 498e4373dc2eb98fa9b18a0824c7912ed84a4c80
Author: prrace <philip.race at oracle.com>
Date:   Sat Jun 9 16:04:28 2018 -0700

    Fix SunStudio 12.6 build (#1053)

diff --git a/src/hb-face.cc b/src/hb-face.cc
index b8d7e84d..2fef09d0 100644
--- a/src/hb-face.cc
+++ b/src/hb-face.cc
@@ -514,7 +514,7 @@ hb_face_get_table_tags (hb_face_t    *face,
 			unsigned int *table_count, /* IN/OUT */
 			hb_tag_t     *table_tags /* OUT */)
 {
-  if (face->destroy != _hb_face_for_data_closure_destroy)
+  if (face->destroy != (hb_destroy_func_t) _hb_face_for_data_closure_destroy)
   {
     if (table_count)
       *table_count = 0;
diff --git a/src/hb-private.hh b/src/hb-private.hh
index 4edb27cb..ac00e022 100644
--- a/src/hb-private.hh
+++ b/src/hb-private.hh
@@ -147,7 +147,7 @@ extern "C" void  hb_free_impl(void *ptr);
 #define HB_FUNC __func__
 #endif
 
-#ifdef __SUNPRO_CC
+#if defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x5140)
 /* https://github.com/harfbuzz/harfbuzz/issues/630 */
 #define __restrict
 #endif
commit 46f7e7760f4c9b1b2886a27eff3c0fabdab45dbe
Author: Garret Rieger <grieger at google.com>
Date:   Thu Jun 7 15:55:45 2018 -0700

    [subset] Use REPLACEME instead of version.

diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc
index 5aa50883..39c5ac4f 100644
--- a/src/hb-subset-input.cc
+++ b/src/hb-subset-input.cc
@@ -127,7 +127,7 @@ hb_subset_input_drop_hints (hb_subset_input_t *subset_input)
  * the subsetting operation. Currently this defaults to
  * true.
  *
- * Since: 1.8.0
+ * Since: REPLACEME
  **/
 HB_EXTERN hb_bool_t *
 hb_subset_input_drop_ot_layout (hb_subset_input_t *subset_input)
commit fc246ec985890f8256f6e03cdf74c86b9b51ff2a
Author: Garret Rieger <grieger at google.com>
Date:   Thu Jun 7 15:54:19 2018 -0700

    [subset] Move variable declaration out of loop.

diff --git a/test/api/test-subset-glyf.c b/test/api/test-subset-glyf.c
index d6f6ddea..e4440e0f 100644
--- a/test/api/test-subset-glyf.c
+++ b/test/api/test-subset-glyf.c
@@ -232,10 +232,10 @@ test_subset_glyf_strip_hints_invalid (void)
     'A', 'B', 'C', 'D', 'E', 'X', 'Y', 'Z', '1', '2',
     '3', '@', '_', '%', '&', ')', '*', '$', '!'
   };
-  for (unsigned int i = 0; i < sizeof (text) / sizeof (hb_codepoint_t); i++)
+  unsigned int i;
+  for (i = 0; i < sizeof (text) / sizeof (hb_codepoint_t); i++)
   {
     hb_set_add (codepoints, text[i]);
-    // hb_set_add (codepoints_drop_hints, text[i]);
   }
 
   hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
commit 197cb18b22ce11f32f5f2c68c13f7068fb5cc338
Author: Garret Rieger <grieger at google.com>
Date:   Thu Jun 7 15:32:52 2018 -0700

    [subset] Add test cases for gsub closure in subsetting.

diff --git a/test/api/fonts/Roboto-Regular.gsub.fi.ttf b/test/api/fonts/Roboto-Regular.gsub.fi.ttf
new file mode 100644
index 00000000..f41953bd
Binary files /dev/null and b/test/api/fonts/Roboto-Regular.gsub.fi.ttf differ
diff --git a/test/api/fonts/Roboto-Regular.gsub.fil.ttf b/test/api/fonts/Roboto-Regular.gsub.fil.ttf
new file mode 100644
index 00000000..03e0be1a
Binary files /dev/null and b/test/api/fonts/Roboto-Regular.gsub.fil.ttf differ
diff --git a/test/api/fonts/Roboto-Regular.nogsub.fi.ttf b/test/api/fonts/Roboto-Regular.nogsub.fi.ttf
new file mode 100644
index 00000000..6a08aa9a
Binary files /dev/null and b/test/api/fonts/Roboto-Regular.nogsub.fi.ttf differ
diff --git a/test/api/test-subset-glyf.c b/test/api/test-subset-glyf.c
index acc6143e..d6f6ddea 100644
--- a/test/api/test-subset-glyf.c
+++ b/test/api/test-subset-glyf.c
@@ -101,6 +101,56 @@ test_subset_glyf_with_components (void)
 }
 
 static void
+test_subset_glyf_with_gsub (void)
+{
+  hb_face_t *face_fil = hb_subset_test_open_font ("fonts/Roboto-Regular.gsub.fil.ttf");
+  hb_face_t *face_fi = hb_subset_test_open_font ("fonts/Roboto-Regular.gsub.fi.ttf");
+
+  hb_set_t *codepoints = hb_set_create();
+  hb_set_add (codepoints, 102); // f
+  hb_set_add (codepoints, 105); // i
+
+  hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
+  hb_set_destroy (codepoints);
+  *hb_subset_input_drop_ot_layout (input) = false;
+
+  hb_face_t *face_subset = hb_subset_test_create_subset (face_fil, input);
+
+  hb_subset_test_check (face_fi, face_subset, HB_TAG ('g','l','y','f'));
+  hb_subset_test_check (face_fi, face_subset, HB_TAG ('l','o','c', 'a'));
+  check_maxp_num_glyphs(face_subset, 5, true);
+
+  hb_face_destroy (face_subset);
+  hb_face_destroy (face_fi);
+  hb_face_destroy (face_fil);
+}
+
+static void
+test_subset_glyf_without_gsub (void)
+{
+  hb_face_t *face_fil = hb_subset_test_open_font ("fonts/Roboto-Regular.gsub.fil.ttf");
+  hb_face_t *face_fi = hb_subset_test_open_font ("fonts/Roboto-Regular.nogsub.fi.ttf");
+
+  hb_set_t *codepoints = hb_set_create();
+  hb_set_add (codepoints, 102); // f
+  hb_set_add (codepoints, 105); // i
+
+  hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
+  hb_set_destroy (codepoints);
+  *hb_subset_input_drop_ot_layout (input) = true;
+
+  hb_face_t *face_subset = hb_subset_test_create_subset (face_fil, input);
+
+  hb_subset_test_check (face_fi, face_subset, HB_TAG ('g','l','y','f'));
+  hb_subset_test_check (face_fi, face_subset, HB_TAG ('l','o','c', 'a'));
+  check_maxp_num_glyphs(face_subset, 3, true);
+
+  hb_face_destroy (face_subset);
+  hb_face_destroy (face_fi);
+  hb_face_destroy (face_fil);
+}
+
+static void
 test_subset_glyf_noop (void)
 {
   hb_face_t *face_abc = hb_subset_test_open_font("fonts/Roboto-Regular.abc.ttf");
@@ -213,6 +263,8 @@ main (int argc, char **argv)
   hb_test_add (test_subset_glyf_strip_hints_composite);
   hb_test_add (test_subset_glyf_strip_hints_invalid);
   hb_test_add (test_subset_glyf_with_components);
+  hb_test_add (test_subset_glyf_with_gsub);
+  hb_test_add (test_subset_glyf_without_gsub);
 
   return hb_test_run();
 }
commit 37eab27be3b88079614f66e484c700bb2d40af10
Author: Garret Rieger <grieger at google.com>
Date:   Thu Jun 7 14:39:03 2018 -0700

    [subset] Add fuzzing of gsub closure to hb-subset-fuzzer.

diff --git a/test/fuzzing/hb-subset-fuzzer.cc b/test/fuzzing/hb-subset-fuzzer.cc
index c3703f2c..28ce921c 100644
--- a/test/fuzzing/hb-subset-fuzzer.cc
+++ b/test/fuzzing/hb-subset-fuzzer.cc
@@ -6,16 +6,17 @@
 
 #include "hb-subset.h"
 
-
 void trySubset (hb_face_t *face,
                 const hb_codepoint_t text[],
                 int text_length,
-                bool drop_hints)
+                bool drop_hints,
+                bool drop_ot_layout)
 {
   hb_subset_profile_t *profile = hb_subset_profile_create ();
 
   hb_subset_input_t *input = hb_subset_input_create_or_fail ();
-  *hb_subset_input_drop_hints(input) = drop_hints;
+  *hb_subset_input_drop_hints (input) = drop_hints;
+  *hb_subset_input_drop_ot_layout (input) = drop_ot_layout;
   hb_set_t *codepoints = hb_subset_input_unicode_set (input);
 
   for (int i = 0; i < text_length; i++)
@@ -30,6 +31,20 @@ void trySubset (hb_face_t *face,
   hb_subset_profile_destroy (profile);
 }
 
+void trySubset (hb_face_t *face,
+                const hb_codepoint_t text[],
+                int text_length)
+{
+  for (unsigned int drop_hints = 0; drop_hints < 2; drop_hints++)
+  {
+    for (unsigned int drop_ot_layout = 0; drop_ot_layout < 2; drop_ot_layout++)
+    {
+      trySubset (face, text, text_length,
+                 (bool) drop_hints, (bool) drop_ot_layout);
+    }
+  }
+}
+
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
 {
   hb_blob_t *blob = hb_blob_create ((const char *)data, size,
@@ -42,8 +57,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
         '3', '@', '_', '%', '&', ')', '*', '$', '!'
       };
 
-  trySubset (face, text, sizeof (text) / sizeof (hb_codepoint_t), true);
-  trySubset (face, text, sizeof (text) / sizeof (hb_codepoint_t), false);
+  trySubset (face, text, sizeof (text) / sizeof (hb_codepoint_t));
 
   hb_codepoint_t text_from_data[16];
   if (size > sizeof(text_from_data)) {
@@ -51,8 +65,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
            data + size - sizeof(text_from_data),
            sizeof(text_from_data));
     unsigned int text_size = sizeof (text_from_data) / sizeof (hb_codepoint_t);
-    trySubset (face, text_from_data, text_size, true);
-    trySubset (face, text_from_data, text_size, false);
+    trySubset (face, text_from_data, text_size);
   }
 
   hb_face_destroy (face);
commit feb23892a36a7c855306db6d21521d5e8362bdf7
Author: Garret Rieger <grieger at google.com>
Date:   Thu Jun 7 14:32:34 2018 -0700

    [subset] Use gsub closure if ot layout is not being dropped.

diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index 10814438..e8d4bcae 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -973,8 +973,14 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t      *face,
   do
   {
     glyphs_length = glyphs->get_population ();
-    for (hb_codepoint_t lookup_index = HB_SET_VALUE_INVALID; hb_set_next (lookups, &lookup_index);)
-      gsub.get_lookup (lookup_index).closure (&c, lookup_index);
+    if (lookups != nullptr)
+    {
+      for (hb_codepoint_t lookup_index = HB_SET_VALUE_INVALID; hb_set_next (lookups, &lookup_index);)
+        gsub.get_lookup (lookup_index).closure (&c, lookup_index);
+    } else {
+      for (unsigned int i = 0; i < gsub.get_lookup_count (); i++)
+        gsub.get_lookup (i).closure (&c, i);
+    }
   } while (glyphs_length != glyphs->get_population ());
 }
 
diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc
index 53f83ee8..55c4e3f6 100644
--- a/src/hb-subset-plan.cc
+++ b/src/hb-subset-plan.cc
@@ -54,8 +54,21 @@ _add_gid_and_children (const OT::glyf::accelerator_t &glyf,
 }
 
 static void
+_gsub_closure (hb_face_t *face, hb_set_t *gids_to_retain)
+{
+  // TODO(grieger): This uses all lookups, instead collect
+  //                the set of lookups that are relevant.
+  //                See fontTools implementation.
+  hb_ot_layout_lookups_substitute_closure (face,
+                                           nullptr,
+                                           gids_to_retain);
+}
+
+
+static void
 _populate_gids_to_retain (hb_face_t *face,
                           const hb_set_t *unicodes,
+                          bool close_over_gsub,
                           hb_set_t *unicodes_to_retain,
                           hb_map_t *codepoint_to_glyph,
                           hb_vector_t<hb_codepoint_t> *glyphs)
@@ -82,10 +95,12 @@ _populate_gids_to_retain (hb_face_t *face,
     initial_gids_to_retain->add (gid);
   }
 
+  if (close_over_gsub)
+    // Add all glyphs needed for GSUB substitutions.
+    _gsub_closure (face, initial_gids_to_retain);
+
   // Populate a full set of glyphs to retain by adding all referenced
   // composite glyphs.
-  // TODO expand with glyphs reached by G*
-
   hb_codepoint_t gid = HB_SET_VALUE_INVALID;
   hb_set_t *all_gids_to_retain = hb_set_create ();
   while (initial_gids_to_retain->next (&gid))
@@ -141,6 +156,7 @@ hb_subset_plan_create (hb_face_t           *face,
 
   _populate_gids_to_retain (face,
                             input->unicodes,
+                            !plan->drop_ot_layout,
                             plan->unicodes,
                             plan->codepoint_to_glyph,
                             &plan->glyphs);
commit a5673da9be70f2ba0ff79aab4bd9a4480cb0223e
Author: Garret Rieger <grieger at google.com>
Date:   Thu Jun 7 14:23:03 2018 -0700

    [subset] Add drop_ot_layout setting to subset input.

diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc
index c4003dd3..5aa50883 100644
--- a/src/hb-subset-input.cc
+++ b/src/hb-subset-input.cc
@@ -45,6 +45,7 @@ hb_subset_input_create_or_fail (void)
 
   input->unicodes = hb_set_create ();
   input->glyphs = hb_set_create ();
+  input->drop_ot_layout = true;
 
   return input;
 }
@@ -117,3 +118,19 @@ hb_subset_input_drop_hints (hb_subset_input_t *subset_input)
 {
   return &subset_input->drop_hints;
 }
+
+/**
+ * hb_subset_input_drop_ot_layout:
+ * @subset_input: a subset_input.
+ *
+ * If enabled ot layout tables will be dropped as part of
+ * the subsetting operation. Currently this defaults to
+ * true.
+ *
+ * Since: 1.8.0
+ **/
+HB_EXTERN hb_bool_t *
+hb_subset_input_drop_ot_layout (hb_subset_input_t *subset_input)
+{
+  return &subset_input->drop_ot_layout;
+}
diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc
index 7100efc8..53f83ee8 100644
--- a/src/hb-subset-plan.cc
+++ b/src/hb-subset-plan.cc
@@ -131,6 +131,7 @@ hb_subset_plan_create (hb_face_t           *face,
   hb_subset_plan_t *plan = hb_object_create<hb_subset_plan_t> ();
 
   plan->drop_hints = input->drop_hints;
+  plan->drop_ot_layout = input->drop_ot_layout;
   plan->unicodes = hb_set_create();
   plan->glyphs.init();
   plan->source = hb_face_reference (face);
diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh
index c9904af8..f4b261df 100644
--- a/src/hb-subset-plan.hh
+++ b/src/hb-subset-plan.hh
@@ -41,6 +41,7 @@ struct hb_subset_plan_t
   ASSERT_POD ();
 
   hb_bool_t drop_hints;
+  hb_bool_t drop_ot_layout;
 
   // For each cp that we'd like to retain maps to the corresponding gid.
   hb_set_t *unicodes;
diff --git a/src/hb-subset-private.hh b/src/hb-subset-private.hh
index 5fa72527..6b2b207f 100644
--- a/src/hb-subset-private.hh
+++ b/src/hb-subset-private.hh
@@ -44,6 +44,7 @@ struct hb_subset_input_t {
   hb_set_t *glyphs;
 
   hb_bool_t drop_hints;
+  hb_bool_t drop_ot_layout;
   /* TODO
    *
    * features
diff --git a/src/hb-subset.cc b/src/hb-subset.cc
index 6d388e29..906327b8 100644
--- a/src/hb-subset.cc
+++ b/src/hb-subset.cc
@@ -302,10 +302,11 @@ _should_drop_table(hb_subset_plan_t *plan, hb_tag_t tag)
     case HB_TAG ('h', 'd', 'm', 'x'): /* hint table, fallthrough */
     case HB_TAG ('V', 'D', 'M', 'X'): /* hint table, fallthrough */
       return plan->drop_hints;
-    // Drop Layout Tables until subsetting is supported.
+    // Drop Layout Tables if requested.
     case HB_TAG ('G', 'D', 'E', 'F'): /* temporary */
     case HB_TAG ('G', 'P', 'O', 'S'): /* temporary */
     case HB_TAG ('G', 'S', 'U', 'B'): /* temporary */
+      return plan->drop_ot_layout;
     // Drop these tables below by default, list pulled
     // from fontTools:
     case HB_TAG ('B', 'A', 'S', 'E'):
diff --git a/src/hb-subset.h b/src/hb-subset.h
index 409581c7..f6d2ae0a 100644
--- a/src/hb-subset.h
+++ b/src/hb-subset.h
@@ -71,6 +71,9 @@ hb_subset_input_glyph_set (hb_subset_input_t *subset_input);
 HB_EXTERN hb_bool_t *
 hb_subset_input_drop_hints (hb_subset_input_t *subset_input);
 
+HB_EXTERN hb_bool_t *
+hb_subset_input_drop_ot_layout (hb_subset_input_t *subset_input);
+
 /* hb_subset() */
 HB_EXTERN hb_face_t *
 hb_subset (hb_face_t *source,
commit 57badadb769d0bcdbee00afce3af4972bc5c6bf1
Author: Garret Rieger <grieger at google.com>
Date:   Wed Jun 6 16:02:51 2018 -0700

    [subset] add a new closure call to hb-ot-layout that can compute the closure over multiple lookups.

diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index a7607f62..10814438 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -952,6 +952,32 @@ hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
   l.closure (&c, lookup_index);
 }
 
+/**
+ * hb_ot_layout_lookups_substitute_closure:
+ *
+ * Compute the transitive closure of glyphs needed for all of the
+ * provided lookups.
+ *
+ * Since: 1.8.1
+ **/
+void
+hb_ot_layout_lookups_substitute_closure (hb_face_t      *face,
+                                         const hb_set_t *lookups,
+                                         hb_set_t       *glyphs)
+{
+  hb_auto_t<hb_map_t> done_lookups;
+  OT::hb_closure_context_t c (face, glyphs, &done_lookups);
+  const OT::GSUB& gsub = _get_gsub (face);
+
+  unsigned int glyphs_length;
+  do
+  {
+    glyphs_length = glyphs->get_population ();
+    for (hb_codepoint_t lookup_index = HB_SET_VALUE_INVALID; hb_set_next (lookups, &lookup_index);)
+      gsub.get_lookup (lookup_index).closure (&c, lookup_index);
+  } while (glyphs_length != glyphs->get_population ());
+}
+
 /*
  * OT::GPOS
  */
diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h
index d82dc022..02787962 100644
--- a/src/hb-ot-layout.h
+++ b/src/hb-ot-layout.h
@@ -277,6 +277,12 @@ hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
 				        hb_set_t     *glyphs
 					/*TODO , hb_bool_t  inclusive */);
 
+HB_EXTERN void
+hb_ot_layout_lookups_substitute_closure (hb_face_t      *face,
+                                         const hb_set_t *lookups,
+                                         hb_set_t       *glyphs);
+
+
 #ifdef HB_NOT_IMPLEMENTED
 /* Note: You better have GDEF when using this API, or marks won't do much. */
 HB_EXTERN hb_bool_t
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index c20b110e..36e0bf9c 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -957,15 +957,7 @@ hb_ot_shape_glyphs_closure (hb_font_t          *font,
 
   hb_set_t *lookups = hb_set_create ();
   hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, lookups);
-
-  /* And find transitive closure. */
-  hb_set_t *copy = hb_set_create ();
-  do {
-    copy->set (glyphs);
-    for (hb_codepoint_t lookup_index = HB_SET_VALUE_INVALID; hb_set_next (lookups, &lookup_index);)
-      hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs);
-  } while (!copy->is_equal (glyphs));
-  hb_set_destroy (copy);
+  hb_ot_layout_lookups_substitute_closure (font->face, lookups, glyphs);
 
   hb_set_destroy (lookups);
 


More information about the HarfBuzz mailing list