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

Behdad Esfahbod behdad at kemper.freedesktop.org
Tue May 8 22:21:23 UTC 2018


 src/hb-ot-cmap-table.hh                                                                         |  355 ++++++++--
 src/hb-subset-plan.cc                                                                           |    4 
 src/hb-subset-plan.hh                                                                           |   18 
 test/api/fonts/Roboto-Regular.D7,D8,D9,DA,DE.ttf                                                |binary
 test/api/test-subset-cmap.c                                                                     |    4 
 test/subset/data/expected/basics/Roboto-Regular.abc.default.61,62,63.ttf                        |binary
 test/subset/data/expected/basics/Roboto-Regular.abc.default.61,63.ttf                           |binary
 test/subset/data/expected/basics/Roboto-Regular.abc.default.61.ttf                              |binary
 test/subset/data/expected/basics/Roboto-Regular.abc.default.62.ttf                              |binary
 test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf                              |binary
 test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,62,63.ttf                     |binary
 test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,63.ttf                        |binary
 test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61.ttf                           |binary
 test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.62.ttf                           |binary
 test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.63.ttf                           |binary
 test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf               |binary
 test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf                         |binary
 test/subset/data/expected/full-font/Roboto-Regular.default.D7,D8,D9,DA,DE.ttf                   |binary
 test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf            |binary
 test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf                      |binary
 test/subset/data/expected/full-font/Roboto-Regular.drop-hints.D7,D8,D9,DA,DE.ttf                |binary
 test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,3048,304A,304B.ttf    |binary
 test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,73E0,5EA6,8F38.ttf    |binary
 test/subset/data/expected/japanese/Mplus1p-Regular.default.61,63,65,6B.ttf                      |binary
 test/subset/data/expected/japanese/Mplus1p-Regular.default.660E,6975,73E0,5EA6,8F38,6E05.ttf    |binary
 test/subset/data/expected/japanese/Mplus1p-Regular.default.660E.ttf                             |binary
 test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,3048,304A,304B.ttf |binary
 test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,73E0,5EA6,8F38.ttf |binary
 test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.61,63,65,6B.ttf                   |binary
 test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.ttf |binary
 test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E.ttf                          |binary
 test/subset/data/fonts/Mplus1p-Regular.ttf                                                      |binary
 32 files changed, 306 insertions(+), 75 deletions(-)

New commits:
commit 0644d92ef32b09e32d473c758d2a968f2d125628
Merge: 2a2e28e7 3be050f0
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue May 8 15:21:09 2018 -0700

    Merge pull request #1018 from googlefonts/cmap4
    
    [subset] Add cmap format 4 subsetting.

commit 3be050f07572d8556726b188668d727e3e7ba643
Author: Garret Rieger <grieger at google.com>
Date:   Fri May 4 11:23:32 2018 -0700

    [subset] entrySelectorZ -> entrySelector.

diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index 40125b05..dc55c0d7 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -88,11 +88,11 @@ struct CmapSubtableFormat4
     this->length.set (get_sub_table_size (segments));
 
     this->segCountX2.set (segments.len * 2);
-    this->entrySelectorZ.set (MAX (1u, _hb_bit_storage (segments.len)) - 1);
-    this->searchRangeZ.set (2 * (1u << this->entrySelectorZ));
-    this->rangeShiftZ.set (segments.len * 2 > this->searchRangeZ
-                           ? 2 * segments.len - this->searchRangeZ
-                           : 0);
+    this->entrySelector.set (MAX (1u, _hb_bit_storage (segments.len)) - 1);
+    this->searchRange.set (2 * (1u << this->entrySelector));
+    this->rangeShift.set (segments.len * 2 > this->searchRange
+                          ? 2 * segments.len - this->searchRange
+                          : 0);
 
     HBUINT16 *end_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len);
     c->allocate_size<HBUINT16> (HBUINT16::static_size); // 2 bytes of padding.
@@ -479,8 +479,8 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
     if (unlikely (!c->extend_min (*this))) return false;
 
     this->format.set (12);
-    this->reservedZ.set (0);
-    this->lengthZ.set (get_sub_table_size (groups));
+    this->reserved.set (0);
+    this->length.set (get_sub_table_size (groups));
 
     return CmapSubtableLongSegmented<CmapSubtableFormat12>::serialize (c, groups);
   }
commit 7c22f98da789f831e1afb9078085b2e33d864d25
Author: Garret Rieger <grieger at google.com>
Date:   Thu May 3 13:14:28 2018 -0700

    [subset] add missing template parameter.

diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index 83b47b56..40125b05 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -482,7 +482,7 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
     this->reservedZ.set (0);
     this->lengthZ.set (get_sub_table_size (groups));
 
-    return CmapSubtableLongSegmented::serialize (c, groups);
+    return CmapSubtableLongSegmented<CmapSubtableFormat12>::serialize (c, groups);
   }
 
   static inline size_t get_sub_table_size (const hb_vector_t<CmapSubtableLongGroup> &groups)
commit 95eb0f3bafb7ab0e2451e3e2f8afc5008e18e88e
Author: Garret Rieger <grieger at google.com>
Date:   Thu May 3 13:00:19 2018 -0700

    [subset] Switch to a non-log using implementation of caculating searchRangeZ, entrySelectorZ, and rangeShiftZ in cmap4.

diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index 883ac3a5..83b47b56 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -87,14 +87,12 @@ struct CmapSubtableFormat4
     this->format.set (4);
     this->length.set (get_sub_table_size (segments));
 
-    // 2 * segCount
     this->segCountX2.set (segments.len * 2);
-    // 2 * (2**floor(log2(segCount)))
-    this->searchRangeZ.set (2 * (1 << (int) (log (segments.len) / log (2.0))));
-    // log2(searchRange/2)
-    this->entrySelectorZ.set (log ((double) this->searchRangeZ / 2.0) / log (2.0));
-    // 2 x segCount - searchRange
-    this->rangeShiftZ.set (2 * segments.len - this->searchRangeZ);
+    this->entrySelectorZ.set (MAX (1u, _hb_bit_storage (segments.len)) - 1);
+    this->searchRangeZ.set (2 * (1u << this->entrySelectorZ));
+    this->rangeShiftZ.set (segments.len * 2 > this->searchRangeZ
+                           ? 2 * segments.len - this->searchRangeZ
+                           : 0);
 
     HBUINT16 *end_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len);
     c->allocate_size<HBUINT16> (HBUINT16::static_size); // 2 bytes of padding.
commit b0d7971be0fa3c9393b04038b8d0a76398b0d8d7
Author: Garret Rieger <grieger at google.com>
Date:   Thu May 3 11:22:51 2018 -0700

    [subset] Updated expected files for japanese subset integration tests to include cmap4.

diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,3048,304A,304B.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,3048,304A,304B.ttf
index db7daa88..33989996 100644
Binary files a/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,3048,304A,304B.ttf and b/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,3048,304A,304B.ttf differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,73E0,5EA6,8F38.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,73E0,5EA6,8F38.ttf
index d05b5eec..66b98a6d 100644
Binary files a/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,73E0,5EA6,8F38.ttf and b/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,73E0,5EA6,8F38.ttf differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.61,63,65,6B.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.61,63,65,6B.ttf
index cef6a42c..22d1bb30 100644
Binary files a/test/subset/data/expected/japanese/Mplus1p-Regular.default.61,63,65,6B.ttf and b/test/subset/data/expected/japanese/Mplus1p-Regular.default.61,63,65,6B.ttf differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E,6975,73E0,5EA6,8F38,6E05.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E,6975,73E0,5EA6,8F38,6E05.ttf
index d7852d8a..28043592 100644
Binary files a/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E,6975,73E0,5EA6,8F38,6E05.ttf and b/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E,6975,73E0,5EA6,8F38,6E05.ttf differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E.ttf
index be607c29..333ca516 100644
Binary files a/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E.ttf and b/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E.ttf differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,3048,304A,304B.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,3048,304A,304B.ttf
index 1e5a7c7f..c84b20cb 100644
Binary files a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,3048,304A,304B.ttf and b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,3048,304A,304B.ttf differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,73E0,5EA6,8F38.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,73E0,5EA6,8F38.ttf
index 3845822d..e757b9e3 100644
Binary files a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,73E0,5EA6,8F38.ttf and b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,73E0,5EA6,8F38.ttf differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.61,63,65,6B.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.61,63,65,6B.ttf
index fce81232..e869ff1f 100644
Binary files a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.61,63,65,6B.ttf and b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.61,63,65,6B.ttf differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.ttf
index b72eaf9c..ed4ed4c1 100644
Binary files a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.ttf and b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.ttf differ
diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E.ttf
index ee7baba6..cb502388 100644
Binary files a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E.ttf and b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E.ttf differ
diff --git a/test/subset/data/fonts/Mplus1p-Regular.ttf b/test/subset/data/fonts/Mplus1p-Regular.ttf
index 2a5205ef..f89a28ef 100644
Binary files a/test/subset/data/fonts/Mplus1p-Regular.ttf and b/test/subset/data/fonts/Mplus1p-Regular.ttf differ
commit 79479273170275447042aa50912acee74bbacdf6
Author: Garret Rieger <grieger at google.com>
Date:   Thu May 3 11:18:02 2018 -0700

    [subset] Update expected files for subset integration tests to include cmap4.

diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,62,63.ttf
index 02cd7efb..12d92081 100644
Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,62,63.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,62,63.ttf differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,63.ttf
index 4942ad0c..1af233f4 100644
Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,63.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,63.ttf differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61.ttf
index 08fe7718..a699eea0 100644
Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61.ttf differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.62.ttf
index 8d7e6b22..52706dc9 100644
Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.default.62.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.default.62.ttf differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf
index 0f3a934c..3de7c773 100644
Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,62,63.ttf
index 70206add..52dc4745 100644
Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,62,63.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,62,63.ttf differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,63.ttf
index c74c0299..1873672b 100644
Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,63.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,63.ttf differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61.ttf
index 8ba816d7..128eae01 100644
Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61.ttf differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.62.ttf
index 837438a5..122b1097 100644
Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.62.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.62.ttf differ
diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.63.ttf
index 311737ab..381e97e9 100644
Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.63.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.63.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf
index 60e361d2..93efe655 100644
Binary files a/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf and b/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf
index 1fc430a4..d4d26d7e 100644
Binary files a/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf and b/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.default.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.default.D7,D8,D9,DA,DE.ttf
index 2ff53536..7e271f22 100644
Binary files a/test/subset/data/expected/full-font/Roboto-Regular.default.D7,D8,D9,DA,DE.ttf and b/test/subset/data/expected/full-font/Roboto-Regular.default.D7,D8,D9,DA,DE.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf
index 98f01e19..99b91bd3 100644
Binary files a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf and b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf
index ea212f03..eb94906a 100644
Binary files a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf and b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf differ
diff --git a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.D7,D8,D9,DA,DE.ttf
index 895c6e6b..ff361bae 100644
Binary files a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.D7,D8,D9,DA,DE.ttf and b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.D7,D8,D9,DA,DE.ttf differ
commit a8e7f9b958dcb4e00226f78d0ff83f031bc1323d
Author: Garret Rieger <grieger at google.com>
Date:   Thu May 3 10:59:00 2018 -0700

    [subset] Get cmap tests passing again.

diff --git a/test/api/fonts/Roboto-Regular.D7,D8,D9,DA,DE.ttf b/test/api/fonts/Roboto-Regular.D7,D8,D9,DA,DE.ttf
index 38799ccb..3a71f53f 100644
Binary files a/test/api/fonts/Roboto-Regular.D7,D8,D9,DA,DE.ttf and b/test/api/fonts/Roboto-Regular.D7,D8,D9,DA,DE.ttf differ
diff --git a/test/api/test-subset-cmap.c b/test/api/test-subset-cmap.c
index 8c519387..84d34bcd 100644
--- a/test/api/test-subset-cmap.c
+++ b/test/api/test-subset-cmap.c
@@ -74,7 +74,7 @@ test_subset_cmap_non_consecutive_glyphs (void)
 static void
 test_subset_cmap_noop (void)
 {
-  hb_face_t *face_abc = hb_subset_test_open_font("fonts/Roboto-Regular.abc.cmap-format12-only.ttf");
+  hb_face_t *face_abc = hb_subset_test_open_font("fonts/Roboto-Regular.abc.ttf");
 
   hb_set_t *codepoints = hb_set_create();
   hb_face_t *face_abc_subset;
commit c817992f495cba21bf468014f22afe349fbc799f
Author: Garret Rieger <grieger at google.com>
Date:   Thu May 3 10:53:20 2018 -0700

    [subset] Write out a format 4, plat 0 encoding record to match fontTools.

diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index 7e42b4fc..883ac3a5 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -764,7 +764,7 @@ struct cmap
     inline size_t final_size() const
     {
       return 4 // header
-          +  8 * 2 // 2 EncodingRecord
+          +  8 * 3 // 3 EncodingRecord
           +  CmapSubtableFormat4::get_sub_table_size (this->format4_segments)
           +  CmapSubtableFormat12::get_sub_table_size (this->format12_groups);
     }
@@ -807,24 +807,30 @@ struct cmap
 
     cmap->version.set (0);
 
-    if (unlikely (!cmap->encodingRecord.serialize (&c, /* numTables */ 2)))
+    if (unlikely (!cmap->encodingRecord.serialize (&c, /* numTables */ 3)))
       return false;
 
     // TODO(grieger): Convert the below to a for loop
 
-    // Format 4 Encoding Record
-    EncodingRecord &format4_rec = cmap->encodingRecord[0];
-    format4_rec.platformID.set (3); // Windows
-    format4_rec.encodingID.set (1); // Unicode BMP
+    // Format 4, Plat 0 Encoding Record
+    EncodingRecord &format4_plat0_rec = cmap->encodingRecord[0];
+    format4_plat0_rec.platformID.set (0); // Unicode
+    format4_plat0_rec.encodingID.set (3);
+
+    // Format 4, Plat 3 Encoding Record
+    EncodingRecord &format4_plat3_rec = cmap->encodingRecord[1];
+    format4_plat3_rec.platformID.set (3); // Windows
+    format4_plat3_rec.encodingID.set (1); // Unicode BMP
 
     // Format 12 Encoding Record
-    EncodingRecord &format12_rec = cmap->encodingRecord[1];
+    EncodingRecord &format12_rec = cmap->encodingRecord[2];
     format12_rec.platformID.set (3); // Windows
     format12_rec.encodingID.set (10); // Unicode UCS-4
 
-    // Write out format 4 sub table.
+    // Write out format 4 sub table
     {
-      CmapSubtable &subtable = format4_rec.subtable.serialize (&c, cmap);
+      CmapSubtable &subtable = format4_plat0_rec.subtable.serialize (&c, cmap);
+      format4_plat3_rec.subtable.set (format4_plat0_rec.subtable);
       subtable.u.format.set (4);
 
       CmapSubtableFormat4 &format4 = subtable.u.format4;
diff --git a/test/api/test-subset-cmap.c b/test/api/test-subset-cmap.c
index 52548742..8c519387 100644
--- a/test/api/test-subset-cmap.c
+++ b/test/api/test-subset-cmap.c
@@ -33,7 +33,7 @@ static void
 test_subset_cmap (void)
 {
   hb_face_t *face_abc = hb_subset_test_open_font ("fonts/Roboto-Regular.abc.ttf");
-  hb_face_t *face_ac = hb_subset_test_open_font ("fonts/Roboto-Regular.ac.cmap-format12-only.ttf");
+  hb_face_t *face_ac = hb_subset_test_open_font ("fonts/Roboto-Regular.ac.ttf");
 
   hb_set_t *codepoints = hb_set_create ();
   hb_face_t *face_abc_subset;
commit 9ef55a4c1354028f4d5e81300cdaf8ce5e03b8e9
Author: Garret Rieger <grieger at google.com>
Date:   Wed May 2 18:50:56 2018 -0700

    [subset] A few bug fixes for cmap format 4 subsetting.

diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index 63380cad..7e42b4fc 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -92,7 +92,7 @@ struct CmapSubtableFormat4
     // 2 * (2**floor(log2(segCount)))
     this->searchRangeZ.set (2 * (1 << (int) (log (segments.len) / log (2.0))));
     // log2(searchRange/2)
-    this->entrySelectorZ.set (log ((double) this->searchRangeZ) / log (2.0));
+    this->entrySelectorZ.set (log ((double) this->searchRangeZ / 2.0) / log (2.0));
     // 2 x segCount - searchRange
     this->rangeShiftZ.set (2 * segments.len - this->searchRangeZ);
 
@@ -102,20 +102,26 @@ struct CmapSubtableFormat4
     HBINT16 *id_delta = c->allocate_size<HBINT16> (HBUINT16::static_size * segments.len);
     HBUINT16 *id_range_offset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len);
 
+    if (id_range_offset == nullptr)
+      return_trace (false);
+
     for (unsigned int i = 0; i < segments.len; i++)
     {
       end_count[i].set (segments[i].end_code);
       start_count[i].set (segments[i].start_code);
       if (segments[i].use_delta)
       {
-        hb_codepoint_t start_gid;
-        if (unlikely (!hb_subset_plan_new_gid_for_codepoint (plan, segments[i].start_code, &start_gid)))
-          return false;
+        hb_codepoint_t cp = segments[i].start_code;
+        hb_codepoint_t start_gid = 0;
+        if (unlikely (!hb_subset_plan_new_gid_for_codepoint (plan, cp, &start_gid) && cp != 0xFFFF))
+          return_trace (false);
         id_delta[i].set (start_gid - segments[i].start_code);
       } else {
         id_delta[i].set (0);
         unsigned int num_codepoints = segments[i].end_code - segments[i].start_code + 1;
         HBUINT16 *glyph_id_array = c->allocate_size<HBUINT16> (HBUINT16::static_size * num_codepoints);
+        if (glyph_id_array == nullptr)
+          return_trace (false);
         // From the cmap spec:
         //
         // id_range_offset[i]/2
@@ -134,15 +140,15 @@ struct CmapSubtableFormat4
         for (unsigned int j = 0; j < num_codepoints; j++)
         {
           hb_codepoint_t cp = segments[i].start_code + j;
-          hb_codepoint_t new_gid = 0; // Default to not def for 0xFFFF
-          if (unlikely (!hb_subset_plan_new_gid_for_codepoint (plan, cp, &new_gid) && cp != 0xFFFF))
-            return false;
+          hb_codepoint_t new_gid;
+          if (unlikely (!hb_subset_plan_new_gid_for_codepoint (plan, cp, &new_gid)))
+            return_trace (false);
           glyph_id_array[j].set (new_gid);
         }
       }
     }
 
-    return true;
+    return_trace (true);
   }
 
   static inline size_t get_sub_table_size (const hb_vector_t<segment_plan> &segments)
@@ -201,16 +207,17 @@ struct CmapSubtableFormat4
           segment->use_delta = false;
       }
 
-      // There must be a final entry with end_code == 0xFFFF. Check if we need to add one.
-      if (segment == nullptr || segment->end_code != 0xFFFF) {
-        segment = segments->push ();
-        segment->start_code.set (0xFFFF);
-        segment->end_code.set (0xFFFF);
-        segment->use_delta = false;
-      }
-
       last_gid = new_gid;
     }
+
+    // There must be a final entry with end_code == 0xFFFF. Check if we need to add one.
+    if (segment == nullptr || segment->end_code != 0xFFFF) {
+      segment = segments->push ();
+      segment->start_code.set (0xFFFF);
+      segment->end_code.set (0xFFFF);
+      segment->use_delta = true;
+    }
+
     return true;
   }
 
@@ -756,11 +763,10 @@ struct cmap
 
     inline size_t final_size() const
     {
-      return
-          4 // header
-          + 8 * 2 // 2 EncodingRecord
-          + CmapSubtableFormat4::get_sub_table_size (this->format4_segments);
-          + CmapSubtableFormat12::get_sub_table_size (this->format12_groups);
+      return 4 // header
+          +  8 * 2 // 2 EncodingRecord
+          +  CmapSubtableFormat4::get_sub_table_size (this->format4_segments)
+          +  CmapSubtableFormat12::get_sub_table_size (this->format12_groups);
     }
 
     // Format 4
@@ -801,7 +807,8 @@ struct cmap
 
     cmap->version.set (0);
 
-    if (unlikely (!cmap->encodingRecord.serialize (&c, /* numTables */ 2))) return false;
+    if (unlikely (!cmap->encodingRecord.serialize (&c, /* numTables */ 2)))
+      return false;
 
     // TODO(grieger): Convert the below to a for loop
 
@@ -821,7 +828,8 @@ struct cmap
       subtable.u.format.set (4);
 
       CmapSubtableFormat4 &format4 = subtable.u.format4;
-      if (unlikely (!format4.serialize (&c, plan, cmap_subset_plan.format4_segments))) return false;
+      if (unlikely (!format4.serialize (&c, plan, cmap_subset_plan.format4_segments)))
+        return false;
     }
 
     // Write out format 12 sub table.
@@ -830,7 +838,8 @@ struct cmap
       subtable.u.format.set (12);
 
       CmapSubtableFormat12 &format12 = subtable.u.format12;
-      if (unlikely (!format12.serialize (&c, cmap_subset_plan.format12_groups))) return false;
+      if (unlikely (!format12.serialize (&c, cmap_subset_plan.format12_groups)))
+        return false;
     }
 
     c.end_serialize ();
commit 81ea75f5c860ef682184bd2c9d0ff8b48251e3ce
Author: Garret Rieger <grieger at google.com>
Date:   Wed May 2 17:46:30 2018 -0700

    [subset] Complete implementation of cmap4 subsetting.

diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index 115f3663..63380cad 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -113,11 +113,36 @@ struct CmapSubtableFormat4
           return false;
         id_delta[i].set (start_gid - segments[i].start_code);
       } else {
-        // TODO: fill out glyphIdArray and id_range_offset.
+        id_delta[i].set (0);
+        unsigned int num_codepoints = segments[i].end_code - segments[i].start_code + 1;
+        HBUINT16 *glyph_id_array = c->allocate_size<HBUINT16> (HBUINT16::static_size * num_codepoints);
+        // From the cmap spec:
+        //
+        // id_range_offset[i]/2
+        // + (cp - segments[i].start_code)
+        // + (id_range_offset + i)
+        // =
+        // glyph_id_array + (cp - segments[i].start_code)
+        //
+        // So, solve for id_range_offset[i]:
+        //
+        // id_range_offset[i]
+        // =
+        // 2 * (glyph_id_array - id_range_offset - i)
+        id_range_offset[i].set (2 * (
+            glyph_id_array - id_range_offset - i));
+        for (unsigned int j = 0; j < num_codepoints; j++)
+        {
+          hb_codepoint_t cp = segments[i].start_code + j;
+          hb_codepoint_t new_gid = 0; // Default to not def for 0xFFFF
+          if (unlikely (!hb_subset_plan_new_gid_for_codepoint (plan, cp, &new_gid) && cp != 0xFFFF))
+            return false;
+          glyph_id_array[j].set (new_gid);
+        }
       }
     }
 
-    // TODO: glyphdIdArray
+    return true;
   }
 
   static inline size_t get_sub_table_size (const hb_vector_t<segment_plan> &segments)
@@ -181,7 +206,7 @@ struct CmapSubtableFormat4
         segment = segments->push ();
         segment->start_code.set (0xFFFF);
         segment->end_code.set (0xFFFF);
-        segment->use_delta = true;
+        segment->use_delta = false;
       }
 
       last_gid = new_gid;
commit 4195a52b041af749046b716dcac7d6560ae37611
Author: Garret Rieger <grieger at google.com>
Date:   Wed May 2 17:11:18 2018 -0700

    [subset] WIP implementation of serialize for cmap format 4.

diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index 84ad1c7e..115f3663 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -80,7 +80,44 @@ struct CmapSubtableFormat4
                   const hb_subset_plan_t *plan,
                   const hb_vector_t<segment_plan> &segments)
   {
-    // TODO
+    TRACE_SERIALIZE (this);
+
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+
+    this->format.set (4);
+    this->length.set (get_sub_table_size (segments));
+
+    // 2 * segCount
+    this->segCountX2.set (segments.len * 2);
+    // 2 * (2**floor(log2(segCount)))
+    this->searchRangeZ.set (2 * (1 << (int) (log (segments.len) / log (2.0))));
+    // log2(searchRange/2)
+    this->entrySelectorZ.set (log ((double) this->searchRangeZ) / log (2.0));
+    // 2 x segCount - searchRange
+    this->rangeShiftZ.set (2 * segments.len - this->searchRangeZ);
+
+    HBUINT16 *end_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len);
+    c->allocate_size<HBUINT16> (HBUINT16::static_size); // 2 bytes of padding.
+    HBUINT16 *start_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len);
+    HBINT16 *id_delta = c->allocate_size<HBINT16> (HBUINT16::static_size * segments.len);
+    HBUINT16 *id_range_offset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len);
+
+    for (unsigned int i = 0; i < segments.len; i++)
+    {
+      end_count[i].set (segments[i].end_code);
+      start_count[i].set (segments[i].start_code);
+      if (segments[i].use_delta)
+      {
+        hb_codepoint_t start_gid;
+        if (unlikely (!hb_subset_plan_new_gid_for_codepoint (plan, segments[i].start_code, &start_gid)))
+          return false;
+        id_delta[i].set (start_gid - segments[i].start_code);
+      } else {
+        // TODO: fill out glyphIdArray and id_range_offset.
+      }
+    }
+
+    // TODO: glyphdIdArray
   }
 
   static inline size_t get_sub_table_size (const hb_vector_t<segment_plan> &segments)
commit cfa592d31ce2fd1ec2765a69ab31bf80161479dd
Author: Garret Rieger <grieger at google.com>
Date:   Wed May 2 16:37:38 2018 -0700

    [subset] Add an implement for cmap format 4 create_sub_table_plan.

diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index 7e9675b3..84ad1c7e 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -108,7 +108,48 @@ struct CmapSubtableFormat4
   static inline bool create_sub_table_plan (const hb_subset_plan_t *plan,
                                             hb_vector_t<segment_plan> *segments)
   {
-    // TODO
+    segment_plan *segment = nullptr;
+    hb_codepoint_t last_gid = 0;
+    for (unsigned int i = 0; i < plan->codepoints.len; i++) {
+      hb_codepoint_t cp = plan->codepoints[i];
+      hb_codepoint_t new_gid;
+      if (unlikely (!hb_subset_plan_new_gid_for_codepoint (plan, cp, &new_gid)))
+      {
+	DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
+	return false;
+      }
+
+      if (cp > 0xFFFF) {
+        // We are now outside of unicode BMP, stop adding to this cmap.
+        break;
+      }
+
+      if (!segment
+          || cp != segment->end_code + 1)
+      {
+        segment = segments->push ();
+        segment->start_code.set (cp);
+        segment->end_code.set (cp);
+        segment->use_delta = true;
+      } else {
+        segment->end_code.set (cp);
+        if (last_gid + 1 != new_gid)
+          // gid's are not consecutive in this segment so delta
+          // cannot be used.
+          segment->use_delta = false;
+      }
+
+      // There must be a final entry with end_code == 0xFFFF. Check if we need to add one.
+      if (segment == nullptr || segment->end_code != 0xFFFF) {
+        segment = segments->push ();
+        segment->start_code.set (0xFFFF);
+        segment->end_code.set (0xFFFF);
+        segment->use_delta = true;
+      }
+
+      last_gid = new_gid;
+    }
+    return true;
   }
 
   struct accelerator_t
commit 295d67ea7d0ddac5666bd6aa4b647dd9cbf8e8f7
Author: Garret Rieger <grieger at google.com>
Date:   Wed May 2 16:12:04 2018 -0700

    [subset] WIP cmap format 4 subsetting.

diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index f0e70afe..7e9675b3 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -69,6 +69,48 @@ struct CmapSubtableFormat0
 
 struct CmapSubtableFormat4
 {
+  struct segment_plan
+  {
+    HBUINT16 start_code;
+    HBUINT16 end_code;
+    bool use_delta;
+  };
+
+  bool serialize (hb_serialize_context_t *c,
+                  const hb_subset_plan_t *plan,
+                  const hb_vector_t<segment_plan> &segments)
+  {
+    // TODO
+  }
+
+  static inline size_t get_sub_table_size (const hb_vector_t<segment_plan> &segments)
+  {
+    size_t segment_size = 0;
+    for (unsigned int i = 0; i < segments.len; i++)
+    {
+      // Parallel array entries
+      segment_size +=
+            2  // end count
+          + 2  // start count
+          + 2  // delta
+          + 2; // range offset
+
+      if (!segments[i].use_delta)
+        // Add bytes for the glyph index array entries for this segment.
+        segment_size += (segments[i].end_code - segments[i].start_code + 1) * 2;
+    }
+
+    return min_size
+        + 2 // Padding
+        + segment_size;
+  }
+
+  static inline bool create_sub_table_plan (const hb_subset_plan_t *plan,
+                                            hb_vector_t<segment_plan> *segments)
+  {
+    // TODO
+  }
+
   struct accelerator_t
   {
     inline void init (const CmapSubtableFormat4 *subtable)
@@ -175,6 +217,8 @@ struct CmapSubtableFormat4
     return_trace (16 + 4 * (unsigned int) segCountX2 <= length);
   }
 
+
+
   protected:
   HBUINT16	format;		/* Format number is set to 4. */
   HBUINT16	length;		/* This is the length in bytes of the
@@ -597,24 +641,29 @@ struct cmap
   struct subset_plan {
     subset_plan(void)
     {
-      groups.init();
+      format4_segments.init();
+      format12_groups.init();
     }
 
     ~subset_plan(void)
     {
-      groups.fini();
+      format4_segments.fini();
+      format12_groups.fini();
     }
 
     inline size_t final_size() const
     {
       return
           4 // header
-          + 8 // 1 EncodingRecord
-          + CmapSubtableFormat12::get_sub_table_size (this->groups);
+          + 8 * 2 // 2 EncodingRecord
+          + CmapSubtableFormat4::get_sub_table_size (this->format4_segments);
+          + CmapSubtableFormat12::get_sub_table_size (this->format12_groups);
     }
 
+    // Format 4
+    hb_vector_t<CmapSubtableFormat4::segment_plan> format4_segments;
     // Format 12
-    hb_vector_t<CmapSubtableLongGroup> groups;
+    hb_vector_t<CmapSubtableLongGroup> format12_groups;
   };
 
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -628,10 +677,14 @@ struct cmap
   inline bool _create_plan (const hb_subset_plan_t *plan,
                             subset_plan *cmap_plan) const
   {
-    return CmapSubtableFormat12::create_sub_table_plan (plan, &cmap_plan->groups);
+    if (unlikely( !CmapSubtableFormat4::create_sub_table_plan (plan, &cmap_plan->format4_segments)))
+      return false;
+
+    return CmapSubtableFormat12::create_sub_table_plan (plan, &cmap_plan->format12_groups);
   }
 
-  inline bool _subset (const subset_plan &cmap_subset_plan,
+  inline bool _subset (const hb_subset_plan_t *plan,
+                       const subset_plan &cmap_subset_plan,
 		       size_t dest_sz,
 		       void *dest) const
   {
@@ -645,18 +698,37 @@ struct cmap
 
     cmap->version.set (0);
 
-    if (unlikely (!cmap->encodingRecord.serialize (&c, /* numTables */ 1))) return false;
+    if (unlikely (!cmap->encodingRecord.serialize (&c, /* numTables */ 2))) return false;
+
+    // TODO(grieger): Convert the below to a for loop
 
-    EncodingRecord &rec = cmap->encodingRecord[0];
-    rec.platformID.set (3); // Windows
-    rec.encodingID.set (10); // Unicode UCS-4
+    // Format 4 Encoding Record
+    EncodingRecord &format4_rec = cmap->encodingRecord[0];
+    format4_rec.platformID.set (3); // Windows
+    format4_rec.encodingID.set (1); // Unicode BMP
+
+    // Format 12 Encoding Record
+    EncodingRecord &format12_rec = cmap->encodingRecord[1];
+    format12_rec.platformID.set (3); // Windows
+    format12_rec.encodingID.set (10); // Unicode UCS-4
+
+    // Write out format 4 sub table.
+    {
+      CmapSubtable &subtable = format4_rec.subtable.serialize (&c, cmap);
+      subtable.u.format.set (4);
+
+      CmapSubtableFormat4 &format4 = subtable.u.format4;
+      if (unlikely (!format4.serialize (&c, plan, cmap_subset_plan.format4_segments))) return false;
+    }
 
     // Write out format 12 sub table.
-    CmapSubtable &subtable = rec.subtable.serialize (&c, cmap);
-    subtable.u.format.set (12);
+    {
+      CmapSubtable &subtable = format12_rec.subtable.serialize (&c, cmap);
+      subtable.u.format.set (12);
 
-    CmapSubtableFormat12 &format12 = subtable.u.format12;
-    if (unlikely (!format12.serialize (&c, cmap_subset_plan.groups))) return false;
+      CmapSubtableFormat12 &format12 = subtable.u.format12;
+      if (unlikely (!format12.serialize (&c, cmap_subset_plan.format12_groups))) return false;
+    }
 
     c.end_serialize ();
 
@@ -681,7 +753,7 @@ struct cmap
       return false;
     }
 
-    if (unlikely (!_subset (cmap_subset_plan, dest_sz, dest)))
+    if (unlikely (!_subset (plan, cmap_subset_plan, dest_sz, dest)))
     {
       DEBUG_MSG(SUBSET, nullptr, "Failed to perform subsetting of cmap.");
       free (dest);
commit 0053d13283458996372f04bd501001d450523605
Author: Garret Rieger <grieger at google.com>
Date:   Wed May 2 15:42:43 2018 -0700

    [subset] Refactor cmap subsetting to make it possible to add support for more sub tables.

diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index 83a0b519..f0e70afe 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -294,7 +294,7 @@ struct CmapSubtableLongSegmented
   }
 
   inline bool serialize (hb_serialize_context_t *c,
-                         hb_vector_t<CmapSubtableLongGroup> &group_data)
+                         const hb_vector_t<CmapSubtableLongGroup> &group_data)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
@@ -319,6 +319,69 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
   static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
 						hb_codepoint_t u)
   { return group.glyphID + (u - group.startCharCode); }
+
+
+  bool serialize (hb_serialize_context_t *c,
+                  const hb_vector_t<CmapSubtableLongGroup> &groups)
+  {
+    if (unlikely (!c->extend_min (*this))) return false;
+
+    this->format.set (12);
+    this->reservedZ.set (0);
+    this->lengthZ.set (get_sub_table_size (groups));
+
+    return CmapSubtableLongSegmented::serialize (c, groups);
+  }
+
+  static inline size_t get_sub_table_size (const hb_vector_t<CmapSubtableLongGroup> &groups)
+  {
+    return 16 + 12 * groups.len;
+  }
+
+  static inline bool create_sub_table_plan (const hb_subset_plan_t *plan,
+                                            hb_vector_t<CmapSubtableLongGroup> *groups)
+  {
+    CmapSubtableLongGroup *group = nullptr;
+    for (unsigned int i = 0; i < plan->codepoints.len; i++) {
+
+      hb_codepoint_t cp = plan->codepoints[i];
+      hb_codepoint_t new_gid;
+      if (unlikely (!hb_subset_plan_new_gid_for_codepoint (plan, cp, &new_gid)))
+      {
+	DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
+	return false;
+      }
+
+      if (!group || !_is_gid_consecutive (group, cp, new_gid))
+      {
+        group = groups->push ();
+        group->startCharCode.set (cp);
+        group->endCharCode.set (cp);
+        group->glyphID.set (new_gid);
+      } else
+      {
+        group->endCharCode.set (cp);
+      }
+    }
+
+    DEBUG_MSG(SUBSET, nullptr, "cmap");
+    for (unsigned int i = 0; i < groups->len; i++) {
+      CmapSubtableLongGroup& group = (*groups)[i];
+      DEBUG_MSG(SUBSET, nullptr, "  %d: U+%04X-U+%04X, gid %d-%d", i, (uint32_t) group.startCharCode, (uint32_t) group.endCharCode, (uint32_t) group.glyphID, (uint32_t) group.glyphID + ((uint32_t) group.endCharCode - (uint32_t) group.startCharCode));
+    }
+
+    return true;
+  }
+
+ private:
+  static inline bool _is_gid_consecutive (CmapSubtableLongGroup *group,
+					  hb_codepoint_t cp,
+					  hb_codepoint_t new_gid)
+  {
+    return (cp - 1 == group->endCharCode) &&
+	new_gid == group->glyphID + (cp - group->startCharCode);
+  }
+
 };
 
 struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
@@ -531,6 +594,29 @@ struct cmap
 {
   static const hb_tag_t tableTag	= HB_OT_TAG_cmap;
 
+  struct subset_plan {
+    subset_plan(void)
+    {
+      groups.init();
+    }
+
+    ~subset_plan(void)
+    {
+      groups.fini();
+    }
+
+    inline size_t final_size() const
+    {
+      return
+          4 // header
+          + 8 // 1 EncodingRecord
+          + CmapSubtableFormat12::get_sub_table_size (this->groups);
+    }
+
+    // Format 12
+    hb_vector_t<CmapSubtableLongGroup> groups;
+  };
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -539,50 +625,13 @@ struct cmap
 		  encodingRecord.sanitize (c, this));
   }
 
-  static inline bool _is_gid_consecutive (CmapSubtableLongGroup *group,
-					  hb_codepoint_t cp,
-					  hb_codepoint_t new_gid)
+  inline bool _create_plan (const hb_subset_plan_t *plan,
+                            subset_plan *cmap_plan) const
   {
-    return (cp - 1 == group->endCharCode) &&
-	new_gid == group->glyphID + (cp - group->startCharCode);
+    return CmapSubtableFormat12::create_sub_table_plan (plan, &cmap_plan->groups);
   }
 
-  inline bool populate_groups (hb_subset_plan_t *plan,
-			       hb_vector_t<CmapSubtableLongGroup> *groups) const
-  {
-    CmapSubtableLongGroup *group = nullptr;
-    for (unsigned int i = 0; i < plan->codepoints.len; i++) {
-
-      hb_codepoint_t cp = plan->codepoints[i];
-      hb_codepoint_t new_gid;
-      if (unlikely (!hb_subset_plan_new_gid_for_codepoint (plan, cp, &new_gid)))
-      {
-	DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
-	return false;
-      }
-
-      if (!group || !_is_gid_consecutive (group, cp, new_gid))
-      {
-        group = groups->push ();
-        group->startCharCode.set (cp);
-        group->endCharCode.set (cp);
-        group->glyphID.set (new_gid);
-      } else
-      {
-        group->endCharCode.set (cp);
-      }
-    }
-
-    DEBUG_MSG(SUBSET, nullptr, "cmap");
-    for (unsigned int i = 0; i < groups->len; i++) {
-      CmapSubtableLongGroup& group = (*groups)[i];
-      DEBUG_MSG(SUBSET, nullptr, "  %d: U+%04X-U+%04X, gid %d-%d", i, (uint32_t) group.startCharCode, (uint32_t) group.endCharCode, (uint32_t) group.glyphID, (uint32_t) group.glyphID + ((uint32_t) group.endCharCode - (uint32_t) group.startCharCode));
-    }
-
-    return true;
-  }
-
-  inline bool _subset (hb_vector_t<CmapSubtableLongGroup> &groups,
+  inline bool _subset (const subset_plan &cmap_subset_plan,
 		       size_t dest_sz,
 		       void *dest) const
   {
@@ -602,19 +651,12 @@ struct cmap
     rec.platformID.set (3); // Windows
     rec.encodingID.set (10); // Unicode UCS-4
 
-    /* capture offset to subtable */
+    // Write out format 12 sub table.
     CmapSubtable &subtable = rec.subtable.serialize (&c, cmap);
-
     subtable.u.format.set (12);
 
     CmapSubtableFormat12 &format12 = subtable.u.format12;
-    if (unlikely (!c.extend_min (format12))) return false;
-
-    format12.format.set (12);
-    format12.reserved.set (0);
-    format12.length.set (16 + 12 * groups.len);
-
-    if (unlikely (!format12.serialize (&c, groups))) return false;
+    if (unlikely (!format12.serialize (&c, cmap_subset_plan.groups))) return false;
 
     c.end_serialize ();
 
@@ -623,24 +665,25 @@ struct cmap
 
   inline bool subset (hb_subset_plan_t *plan) const
   {
-    hb_auto_t<hb_vector_t<CmapSubtableLongGroup> > groups;
+    subset_plan cmap_subset_plan;
 
-    if (unlikely (!populate_groups (plan, &groups))) return false;
+    if (unlikely (!_create_plan (plan, &cmap_subset_plan)))
+    {
+      DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cmap subsetting plan.");
+      return false;
+    }
 
     // We now know how big our blob needs to be
-    // TODO use APIs from the structs to get size?
-    size_t dest_sz = 4 // header
-                   + 8 // 1 EncodingRecord
-                   + 16 // Format 12 header
-                   + 12 * groups.len; // SequentialMapGroup records
+    size_t dest_sz = cmap_subset_plan.final_size();
     void *dest = malloc (dest_sz);
     if (unlikely (!dest)) {
       DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for cmap subset output", (unsigned long) dest_sz);
       return false;
     }
 
-    if (unlikely (!_subset (groups, dest_sz, dest)))
+    if (unlikely (!_subset (cmap_subset_plan, dest_sz, dest)))
     {
+      DEBUG_MSG(SUBSET, nullptr, "Failed to perform subsetting of cmap.");
       free (dest);
       return false;
     }
commit 03b27548123756dfd9988a8fc74bc78733fb2c44
Author: Garret Rieger <grieger at google.com>
Date:   Wed May 2 15:42:08 2018 -0700

    [subset] Add const to the hb_subset_plan_t input to a couple functions in hb-subset-plan.

diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc
index 0c11765c..d70215b0 100644
--- a/src/hb-subset-plan.cc
+++ b/src/hb-subset-plan.cc
@@ -40,7 +40,7 @@ _hb_codepoint_t_cmp (const void *pa, const void *pb)
 }
 
 hb_bool_t
-hb_subset_plan_new_gid_for_codepoint (hb_subset_plan_t *plan,
+hb_subset_plan_new_gid_for_codepoint (const hb_subset_plan_t *plan,
                                       hb_codepoint_t codepoint,
                                       hb_codepoint_t *new_gid)
 {
@@ -58,7 +58,7 @@ hb_subset_plan_new_gid_for_codepoint (hb_subset_plan_t *plan,
 }
 
 hb_bool_t
-hb_subset_plan_new_gid_for_old_id (hb_subset_plan_t *plan,
+hb_subset_plan_new_gid_for_old_id (const hb_subset_plan_t *plan,
                                    hb_codepoint_t old_gid,
                                    hb_codepoint_t *new_gid)
 {
diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh
index 3b9db03f..1c8697b6 100644
--- a/src/hb-subset-plan.hh
+++ b/src/hb-subset-plan.hh
@@ -65,19 +65,19 @@ hb_subset_plan_create (hb_face_t           *face,
                        hb_subset_input_t   *input);
 
 HB_INTERNAL hb_bool_t
-hb_subset_plan_new_gid_for_old_id(hb_subset_plan_t *plan,
-                                  hb_codepoint_t old_gid,
-                                  hb_codepoint_t *new_gid /* OUT */);
+hb_subset_plan_new_gid_for_old_id (const hb_subset_plan_t *plan,
+                                   hb_codepoint_t old_gid,
+                                   hb_codepoint_t *new_gid /* OUT */);
 
 HB_INTERNAL hb_bool_t
-hb_subset_plan_new_gid_for_codepoint(hb_subset_plan_t *plan,
-                                     hb_codepoint_t codepont,
-                                     hb_codepoint_t *new_gid /* OUT */);
+hb_subset_plan_new_gid_for_codepoint (const hb_subset_plan_t *plan,
+                                      hb_codepoint_t codepont,
+                                      hb_codepoint_t *new_gid /* OUT */);
 
 HB_INTERNAL hb_bool_t
-hb_subset_plan_add_table(hb_subset_plan_t *plan,
-                         hb_tag_t tag,
-                         hb_blob_t *contents);
+hb_subset_plan_add_table (hb_subset_plan_t *plan,
+                          hb_tag_t tag,
+                          hb_blob_t *contents);
 
 HB_INTERNAL void
 hb_subset_plan_destroy (hb_subset_plan_t *plan);


More information about the HarfBuzz mailing list