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

Behdad Esfahbod behdad at kemper.freedesktop.org
Wed Feb 28 22:13:34 UTC 2018


 .travis.yml                                                                          |    4 
 CMakeLists.txt                                                                       |   70 --
 src/Makefile.sources                                                                 |    4 
 src/hb-ot-color.cc                                                                   |  183 +++++
 src/hb-ot-color.h                                                                    |   89 ++
 src/hb-ot-colr-table.hh                                                              |   98 +++
 src/hb-ot-cpal-table.hh                                                              |  169 +++++
 src/hb-ot-glyf-table.hh                                                              |   10 
 src/hb-ot-layout-private.hh                                                          |    4 
 src/hb-ot-layout.cc                                                                  |   10 
 src/hb-ot-maxp-table.hh                                                              |   63 +
 src/hb-ot.h                                                                          |    1 
 src/hb-subset-glyf.cc                                                                |   20 
 test/api/CMakeLists.txt                                                              |    2 
 test/api/Makefile.am                                                                 |    1 
 test/api/fonts/Roboto-Regular.components.1fc.nohints.ttf                             |binary
 test/api/hb-test.h                                                                   |   32 +
 test/api/test-ot-color.c                                                             |  319 ++++++++++
 test/api/test-subset-glyf.c                                                          |   58 +
 test/shaping/data/in-house/fonts/319f5d7ebffbefc5c5e6569f8cea73444d7a7268.ttf        |binary
 test/shaping/data/in-house/fonts/e90374e5e439e00725b4fe7a8d73db57c5a97f82.ttf        |binary
 test/subset/data/Makefile.am                                                         |    1 
 test/subset/data/Makefile.sources                                                    |    1 
 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.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.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/fonts/Roboto-Regular.ttf                                            |binary
 test/subset/data/profiles/drop-hints.txt                                             |    1 
 test/subset/data/tests/basics.tests                                                  |    5 
 test/subset/data/tests/full-font.tests                                               |   11 
 test/subset/generate-expected-outputs.py                                             |   23 
 test/subset/run-tests.py                                                             |    3 
 test/subset/subset_test_suite.py                                                     |   11 
 43 files changed, 1112 insertions(+), 81 deletions(-)

New commits:
commit 588a4e0f9b2d71362503a274de7200f3eb4367f7
Merge: 55a4dfa3 b3f1a045
Author: rsheeter <rsheeter at google.com>
Date:   Wed Feb 28 13:52:29 2018 -0800

    Merge pull request #845 from googlefonts/drophints
    
    [subset] drop hints from composites

commit b3f1a045a8b86747afce6bc154f2a166ea678efb
Author: Rod Sheeter <rsheeter at google.com>
Date:   Wed Feb 28 11:41:24 2018 -0800

    [subset] kick the build

diff --git a/src/hb-subset-glyf.cc b/src/hb-subset-glyf.cc
index 9b36a001..0b84c856 100644
--- a/src/hb-subset-glyf.cc
+++ b/src/hb-subset-glyf.cc
@@ -192,7 +192,7 @@ _write_glyf_and_loca_prime (hb_subset_plan_t              *plan,
     {
       memcpy (glyf_prime_data_next, glyf_data + start_offset, instruction_start - start_offset);
       memcpy (glyf_prime_data_next + instruction_start - start_offset, glyf_data + instruction_end, end_offset - instruction_end);
-      /* if the instructions end at the end this was a composite glyph */
+      /* if the instructions end at the end this was a composite glyph, else simple */
       if (instruction_end == end_offset)
       {
         if (unlikely (!_remove_composite_instruction_flag (glyf_prime_data_next, length))) return false;
commit 20d57399235b410d2bdc98103c8bb3dfd1c34176
Author: Rod Sheeter <rsheeter at google.com>
Date:   Wed Feb 28 11:15:08 2018 -0800

    [subset] extract a method to flip off composite instruction flag

diff --git a/src/hb-subset-glyf.cc b/src/hb-subset-glyf.cc
index 03676668..9b36a001 100644
--- a/src/hb-subset-glyf.cc
+++ b/src/hb-subset-glyf.cc
@@ -136,6 +136,20 @@ _update_components (hb_subset_plan_t * plan,
   }
 }
 
+static bool _remove_composite_instruction_flag(char *glyf_prime, unsigned int length)
+{
+  /* remove WE_HAVE_INSTRUCTIONS from flags in dest */
+  OT::glyf::CompositeGlyphHeader::Iterator composite_it;
+  if (unlikely (!OT::glyf::CompositeGlyphHeader::get_iterator (glyf_prime, length, &composite_it))) return false;
+  const OT::glyf::CompositeGlyphHeader *glyph;
+  do {
+    glyph = composite_it.current;
+    OT::HBUINT16 *flags = const_cast<OT::HBUINT16 *> (&glyph->flags);
+    flags->set ( (uint16_t) *flags & ~OT::glyf::CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS);
+  } while (composite_it.move_to_next());
+  return true;
+}
+
 static bool
 _write_glyf_and_loca_prime (hb_subset_plan_t              *plan,
 			    const OT::glyf::accelerator_t &glyf,
@@ -181,15 +195,7 @@ _write_glyf_and_loca_prime (hb_subset_plan_t              *plan,
       /* if the instructions end at the end this was a composite glyph */
       if (instruction_end == end_offset)
       {
-        /* remove WE_HAVE_INSTRUCTIONS from flags in dest */
-        OT::glyf::CompositeGlyphHeader::Iterator composite_it;
-        if (unlikely (!OT::glyf::CompositeGlyphHeader::get_iterator (glyf_prime_data_next, length, &composite_it))) return false;
-        const OT::glyf::CompositeGlyphHeader *glyph;
-        do {
-          glyph = composite_it.current;
-          OT::HBUINT16 *flags = const_cast<OT::HBUINT16 *> (&glyph->flags);
-          flags->set ( (uint16_t) *flags & ~OT::glyf::CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS);
-        } while (composite_it.move_to_next());
+        if (unlikely (!_remove_composite_instruction_flag (glyf_prime_data_next, length))) return false;
       }
       else
         /* zero instruction length, which is just before instruction_start */
commit 55a4dfa374bae1db846c3b848b7e59fb0014b627
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Wed Feb 28 15:43:23 2018 +0330

    Use old project location of coverity
    
    https://github.com/harfbuzz/harfbuzz/commit/8089711a61687d565f207c56d3d2b658f514d7ab#commitcomment-27835452

diff --git a/.travis.yml b/.travis.yml
index 02accdc9..9fbf6b22 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,7 +12,7 @@ env:
     - CONFIGURE_OPTS="--with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2"
     - NOCONFIGURE=1
     # COVERITY_SCAN_TOKEN
-    - secure: "Vw1UUHsAr4t3xuvOqqBsFAORptmNcQRrcGJnzSX7jDODBIRNfnU2LIBTagrPNKfSUhyQgCHqt1gX9iWNWvVfy3sDOXr2MXZeoqmF6Y1mS35J0rA/EPJgRHsdkxygkmFnXVeQkEuI55BINkaSoOpAeunmXKJNw1p9JVw368Fm/tU="
+    - secure: "MRJtVu/fQoWNwMAamvIJBCX/1SMvEuEUk/ljAif/y2/3syyWgxFGp17UGnDILdoZYyCqTM+jQciY2P0nVqbjjOAUlML4QOAalqw8kPp8iTsnHUe+KOMVrOVP6p6qAQxk1im1O41cCMkmVKvk+NXe/on5euz6LGF2laHZaOAMoes="
 
 matrix:
   include:
@@ -79,7 +79,7 @@ addons:
 
   coverity_scan:
     project:
-      name: HarfBuzz
+      name: behdad/harfbuzz
       version: 1.0
       description: HarfBuzz OpenType text shaping engine
     notification_email: harfbuzz-bots-chatter at googlegroups.com
commit 3821978bcd92cbdb607111452796e051c456f391
Merge: 77227462 f671f7f0
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Wed Feb 28 13:30:17 2018 +0330

    Merge pull request #847 from ebraminio/colr
    
    [colr] Implement

commit f671f7f0a8caa7b5763e00146e1ec4b9a7258227
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Wed Feb 28 13:19:40 2018 +0330

    [colr] Implement

diff --git a/src/Makefile.sources b/src/Makefile.sources
index fc3383b8..a3bd1565 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -97,6 +97,7 @@ HB_OT_sources = \
 	hb-ot-layout-jstf-table.hh \
 	hb-ot-layout-private.hh \
 	hb-ot-color.cc \
+	hb-ot-colr-table.hh \
 	hb-ot-cpal-table.hh \
 	hb-ot-map.cc \
 	hb-ot-map-private.hh \
diff --git a/src/hb-ot-color.cc b/src/hb-ot-color.cc
index f89e58ac..da4fa408 100644
--- a/src/hb-ot-color.cc
+++ b/src/hb-ot-color.cc
@@ -26,6 +26,7 @@
  */
 
 #include "hb-open-type-private.hh"
+#include "hb-ot-colr-table.hh"
 #include "hb-ot-cpal-table.hh"
 #include "hb-ot.h"
 
@@ -40,6 +41,14 @@ HB_MARK_AS_FLAG_T (hb_ot_color_palette_flags_t)
 //HB_SHAPER_DATA_ENSURE_DECLARE(ot, face) Hmm?
 
 
+static inline const OT::COLR&
+_get_colr (hb_face_t *face)
+{
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::COLR);
+  hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
+  return *(layout->colr.get ());
+}
+
 static inline const OT::CPAL&
 _get_cpal (hb_face_t *face)
 {
diff --git a/src/hb-ot-color.h b/src/hb-ot-color.h
index 8f485667..8c276e59 100644
--- a/src/hb-ot-color.h
+++ b/src/hb-ot-color.h
@@ -38,15 +38,6 @@
 HB_BEGIN_DECLS
 
 /**
- * HB_OT_TAG_CPAL:
- * a four-letter tag for identifying the CPAL table with color palettes
- *
- * Since: REPLACEME
- */
-#define HB_OT_TAG_CPAL HB_TAG('C','P','A','L')
-
-
-/**
  * hb_ot_color_t:
  * @red: the intensity of the red channel
  * @green: the intensity of the green channel
diff --git a/src/hb-ot-colr-table.hh b/src/hb-ot-colr-table.hh
new file mode 100644
index 00000000..c5bc2ccb
--- /dev/null
+++ b/src/hb-ot-colr-table.hh
@@ -0,0 +1,98 @@
+/*
+ * Copyright © 2018  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_OT_COLR_TABLE_HH
+#define HB_OT_COLR_TABLE_HH
+
+#include "hb-open-type-private.hh"
+
+/*
+ * Color Palette
+ * http://www.microsoft.com/typography/otspec/colr.htm
+ */
+
+#define HB_OT_TAG_COLR HB_TAG('C','O','L','R')
+
+namespace OT {
+
+
+struct LayerRecord
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (true);
+  }
+
+  HBUINT16 gID;			/* Glyph ID of layer glyph */
+  HBUINT16 paletteIndex;	/* Index value to use with a selected color palette */
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+struct BaseGlyphRecord
+{
+  inline bool sanitize (hb_sanitize_context_t *c, unsigned int palettes) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  HBUINT16 gID;			/* Glyph ID of reference glyph */
+  OffsetTo<LayerRecord>
+  	firstLayerIndex;	/* Index to the layer record */
+  HBUINT16 numLayers;		/* Number of color layers associated with this glyph */
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+struct COLR
+{
+  static const hb_tag_t tableTag = HB_OT_TAG_COLR;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+        c->check_array ((const void*) &baseGlyphRecords, sizeof (BaseGlyphRecord), numBaseGlyphRecords) &&
+        c->check_array ((const void*) &layerRecordsOffset, sizeof (LayerRecord), numLayerRecords));
+  }
+
+  protected:
+  HBUINT16	version;		/* Table version number */
+  HBUINT16	numBaseGlyphRecords;	/* Number of Base Glyph Records */
+  LOffsetTo<BaseGlyphRecord>
+		baseGlyphRecords;	/* Offset to Base Glyph records. */
+  LOffsetTo<LayerRecord>
+		layerRecordsOffset;	/* Offset to Layer Records */
+  HBUINT16	numLayerRecords;	/* Number of Layer Records */
+
+  public:
+  DEFINE_SIZE_STATIC (14);
+};
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_COLR_TABLE_HH */
diff --git a/src/hb-ot-cpal-table.hh b/src/hb-ot-cpal-table.hh
index 4369a7d3..aade0e73 100644
--- a/src/hb-ot-cpal-table.hh
+++ b/src/hb-ot-cpal-table.hh
@@ -30,9 +30,6 @@
 
 #include "hb-open-type-private.hh"
 
-
-namespace OT {
-
 /*
  * Color Palette
  * http://www.microsoft.com/typography/otspec/cpal.htm
@@ -40,6 +37,9 @@ namespace OT {
 
 #define HB_OT_TAG_CPAL HB_TAG('C','P','A','L')
 
+namespace OT {
+
+
 struct ColorRecord
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh
index a8f06f6a..870ba73f 100644
--- a/src/hb-ot-layout-private.hh
+++ b/src/hb-ot-layout-private.hh
@@ -123,10 +123,11 @@ hb_ot_layout_position_finish_offsets (hb_font_t    *font,
 
 namespace OT {
   struct BASE;
+  struct COLR;
+  struct CPAL;
   struct GDEF;
   struct GSUB;
   struct GPOS;
-  struct CPAL;
   struct MATH;
   struct fvar;
   struct avar;
@@ -172,8 +173,9 @@ struct hb_ot_layout_t
 
   /* TODO Move the following out of this struct. */
   OT::hb_lazy_table_loader_t<struct OT::BASE> base;
-  OT::hb_lazy_table_loader_t<struct OT::MATH> math;
+  OT::hb_lazy_table_loader_t<struct OT::COLR> colr;
   OT::hb_lazy_table_loader_t<struct OT::CPAL> cpal;
+  OT::hb_lazy_table_loader_t<struct OT::MATH> math;
   OT::hb_lazy_table_loader_t<struct OT::fvar> fvar;
   OT::hb_lazy_table_loader_t<struct OT::avar> avar;
   OT::hb_lazy_table_loader_t<struct AAT::ankr> ankr;
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index beef8419..e4cb68d8 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -37,6 +37,7 @@
 #include "hb-ot-layout-gpos-table.hh"
 #include "hb-ot-layout-jstf-table.hh" // Just so we compile it; unused otherwise.
 #include "hb-ot-name-table.hh" // Just so we compile it; unused otherwise.
+#include "hb-ot-colr-table.hh"
 #include "hb-ot-cpal-table.hh"
 
 #include "hb-ot-map-private.hh"
@@ -63,9 +64,10 @@ _hb_ot_layout_create (hb_face_t *face)
   layout->gpos_blob = OT::Sanitizer<OT::GPOS>().sanitize (face->reference_table (HB_OT_TAG_GPOS));
   layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
 
-  layout->math.init (face);
-  layout->cpal.init (face);
   layout->base.init (face);
+  layout->colr.init (face);
+  layout->cpal.init (face);
+  layout->math.init (face);
   layout->fvar.init (face);
   layout->avar.init (face);
   layout->ankr.init (face);
@@ -218,9 +220,10 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout)
   hb_blob_destroy (layout->gsub_blob);
   hb_blob_destroy (layout->gpos_blob);
 
-  layout->math.fini ();
-  layout->cpal.fini ();
   layout->base.fini ();
+  layout->colr.fini ();
+  layout->cpal.fini ();
+  layout->math.fini ();
   layout->fvar.fini ();
   layout->avar.fini ();
   layout->ankr.fini ();
commit 772274625e9f17d726f2a1da8192ec3ec24793a3
Merge: 0eec3315 5b9c2340
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Wed Feb 28 12:05:49 2018 +0330

    Merge pull request #841 from ebraminio/color
    
    Support CPAL table

commit 0eec33154a418fba97a08be7169b59e748b7e785
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Wed Feb 28 11:53:39 2018 +0330

    [cmake] cleanup (#846)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 660da5a1..defd5d6c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -63,7 +63,6 @@ if (HB_HAVE_INTROSPECTION)
   set (HB_HAVE_GLIB ON)
 endif ()
 
-option(HB_DISABLE_TEST_PROGS OFF "Do not build some of the test programs, useful for continuous builds")
 option(HB_CHECK OFF "Do a configuration suitable for testing (shared library and enable all options)")
 if (HB_CHECK)
   set (BUILD_SHARED_LIBS ON)
@@ -133,12 +132,11 @@ endif ()
 
 
 ## Detect if we are running inside a distribution or regular repository folder
-set (IN_HB_DIST FALSE)
-if (EXISTS "${PROJECT_SOURCE_DIR}/ChangeLog")
-  # perhaps we are on dist directory
-  set (IN_HB_DIST TRUE)
-  #set (HB_VERSION_H "${PROJECT_SOURCE_DIR}/src/hb-version.h")
-endif ()
+# if (EXISTS "${PROJECT_SOURCE_DIR}/ChangeLog")
+#   # perhaps we are on dist directory
+#   set (IN_HB_DIST TRUE)
+#   #set (HB_VERSION_H "${PROJECT_SOURCE_DIR}/src/hb-version.h")
+# endif ()
 
 
 ## Extract variables from Makefile files
@@ -210,31 +208,23 @@ set (HB_VERSION_MICRO ${CMAKE_MATCH_4})
 
 
 ## Define ragel tasks
-if (NOT IN_HB_DIST)
-  find_program(RAGEL "ragel" CMAKE_FIND_ROOT_PATH_BOTH)
+# if (NOT IN_HB_DIST)
+#  foreach (ragel_output IN ITEMS ${HB_BASE_RAGEL_GENERATED_sources} ${HB_OT_RAGEL_GENERATED_sources})
+#    string(REGEX MATCH "([^/]+)\\.hh" temp ${ragel_output})
+#    set (target_name ${CMAKE_MATCH_1})
+#    add_custom_command(OUTPUT ${ragel_output}
+#      COMMAND ${RAGEL} -G2 -o ${ragel_output} ${PROJECT_SOURCE_DIR}/src/${target_name}.rl -I ${PROJECT_SOURCE_DIR} ${ARGN}
+#      DEPENDS ${PROJECT_SOURCE_DIR}/src/${target_name}.rl
+#    )
+#    add_custom_target(harfbuzz_${target_name} DEPENDS ${PROJECT_BINARY_DIR}/src/${target_name})
+#  endforeach ()
 
-  if (RAGEL)
-    message(STATUS "ragel found at: ${RAGEL}")
-  else ()
-    message(FATAL_ERROR "ragel not found, get it here -- http://www.complang.org/ragel/ or, use harfbuzz releases https://github.com/harfbuzz/harfbuzz/releases")
-  endif ()
-
-  foreach (ragel_output IN ITEMS ${HB_BASE_RAGEL_GENERATED_sources} ${HB_OT_RAGEL_GENERATED_sources})
-    string(REGEX MATCH "([^/]+)\\.hh" temp ${ragel_output})
-    set (target_name ${CMAKE_MATCH_1})
-    add_custom_command(OUTPUT ${ragel_output}
-      COMMAND ${RAGEL} -G2 -o ${ragel_output} ${PROJECT_SOURCE_DIR}/src/${target_name}.rl -I ${PROJECT_SOURCE_DIR} ${ARGN}
-      DEPENDS ${PROJECT_SOURCE_DIR}/src/${target_name}.rl
-    )
-    add_custom_target(harfbuzz_${target_name} DEPENDS ${PROJECT_BINARY_DIR}/src/${target_name})
-  endforeach ()
-
-  mark_as_advanced(RAGEL)
-endif ()
+#  mark_as_advanced(RAGEL)
+# endif ()
 
 
 ## Generate hb-version.h
-#if (NOT IN_HB_DIST)
+# if (NOT IN_HB_DIST)
 #  set (HB_VERSION_H_IN "${PROJECT_SOURCE_DIR}/src/hb-version.h.in")
 #  set (HB_VERSION_H "${PROJECT_BINARY_DIR}/src/hb-version.h")
 #  set_source_files_properties("${HB_VERSION_H}" PROPERTIES GENERATED true)
@@ -244,7 +234,7 @@ endif ()
 #    "${HB_VERSION_H}"
 #  )
 #  file(REMOVE "${HB_VERSION_H}.tmp")
-#endif ()
+# endif ()
 
 
 ## Define sources and headers of the project
@@ -808,18 +798,16 @@ endif ()
 
 
 ## src/ executables
-if (NOT HB_DISABLE_TEST_PROGS)
-  foreach (prog main test test-would-substitute test-size-params test-buffer-serialize hb-ot-tag test-unicode-ranges)
-    set (prog_name ${prog})
-    if (${prog_name} STREQUAL "test")
-      # test can not be used as a valid executable name on cmake, lets special case it
-      set (prog_name test-test)
-    endif ()
-    add_executable(${prog_name} ${PROJECT_SOURCE_DIR}/src/${prog}.cc)
-    target_link_libraries(${prog_name} harfbuzz ${THIRD_PARTY_LIBS})
-  endforeach ()
-  set_target_properties(hb-ot-tag PROPERTIES COMPILE_FLAGS "-DMAIN")
-endif ()
+foreach (prog main test test-would-substitute test-size-params test-buffer-serialize hb-ot-tag test-unicode-ranges)
+  set (prog_name ${prog})
+  if (${prog_name} STREQUAL "test")
+    # test can not be used as a valid executable name on cmake, lets special case it
+    set (prog_name test-test)
+  endif ()
+  add_executable(${prog_name} ${PROJECT_SOURCE_DIR}/src/${prog}.cc)
+  target_link_libraries(${prog_name} harfbuzz ${THIRD_PARTY_LIBS})
+endforeach ()
+set_target_properties(hb-ot-tag PROPERTIES COMPILE_FLAGS "-DMAIN")
 
 ## Tests
 if (UNIX OR MINGW)
diff --git a/test/api/CMakeLists.txt b/test/api/CMakeLists.txt
index 6a62b656..f1a2300f 100644
--- a/test/api/CMakeLists.txt
+++ b/test/api/CMakeLists.txt
@@ -1,4 +1,4 @@
-if (HB_HAVE_GLIB AND NOT HB_DISABLE_TEST_PROGS)
+if (HB_HAVE_GLIB)
   file (READ "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.am" MAKEFILEAM)
   extract_make_variable (TEST_PROGS ${MAKEFILEAM})
 
commit 5b9c234043d0483e53e9da5fe4afd7743190b538
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Tue Feb 27 22:56:17 2018 +0330

    [CPAL] Refactor and address the reviews

diff --git a/NEWS b/NEWS
index 8ff1fe61..9015c4ad 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,3 @@
-=======
 Overview of changes leading to 1.7.5
 Tuesday, January 30, 2018
 ====================================
@@ -372,6 +371,7 @@ Thursday, July 21, 2016
 - Blacklist bad GDEF of more fonts (Tahoma & others).
 - Misc fixes.
 
+
 Overview of changes leading to 1.2.7
 Monday, May 2, 2016
 ====================================
@@ -383,6 +383,7 @@ Monday, May 2, 2016
 - Unbreak build on Windows CE.
 - Make 'glyf' table loading lazy in hb-ot-font.
 
+
 Overview of changes leading to 1.2.6
 Friday, April 8, 2016
 ====================================
diff --git a/src/Makefile.am b/src/Makefile.am
index 2dcaa7fb..2871f30f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -368,7 +368,6 @@ check_PROGRAMS += \
 	dump-myanmar-data \
 	dump-use-data \
 	$(NULL)
-
 dump_indic_data_SOURCES = dump-indic-data.cc hb-ot-shape-complex-indic-table.cc
 dump_indic_data_CPPFLAGS = $(HBCFLAGS)
 dump_indic_data_LDADD = libharfbuzz.la $(HBLIBS)
diff --git a/src/hb-ot-color.cc b/src/hb-ot-color.cc
index 93d5c001..f89e58ac 100644
--- a/src/hb-ot-color.cc
+++ b/src/hb-ot-color.cc
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2016  Google, Inc.
+ * Copyright © 2018  Ebrahim Byagowi
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -34,23 +35,17 @@
 #include "hb-ot-layout-private.hh"
 #include "hb-shaper-private.hh"
 
+#if 0
 HB_MARK_AS_FLAG_T (hb_ot_color_palette_flags_t)
-HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
+//HB_SHAPER_DATA_ENSURE_DECLARE(ot, face) Hmm?
 
 
 static inline const OT::CPAL&
 _get_cpal (hb_face_t *face)
 {
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
-    return OT::Null(OT::CPAL);
-
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::CPAL);
   hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
-  if (!layout->cpal) {
-    layout->cpal_blob = OT::Sanitizer<OT::CPAL>::sanitize (face->reference_table (HB_OT_TAG_CPAL));
-    layout->cpal = OT::Sanitizer<OT::CPAL>::lock_instance (layout->cpal_blob);
-  }
-
-  return *layout->cpal;
+  return *(layout->cpal.get ());
 }
 
 
@@ -61,13 +56,13 @@ _get_cpal (hb_face_t *face)
  * Returns: the number of color palettes in @face, or zero if @face has
  * no colors.
  *
- * Since: 1.2.8
+ * Since: REPLACEME
  */
 unsigned int
 hb_ot_color_get_palette_count (hb_face_t *face)
 {
-  const OT::CPAL& cpal = _get_cpal(face);
-  return &cpal != &OT::Null(OT::CPAL) ? cpal.numPalettes : 0;
+  const OT::CPAL& cpal = _get_cpal (face);
+  return cpal.get_palette_count ();
 }
 
 
@@ -85,28 +80,13 @@ hb_ot_color_get_palette_count (hb_face_t *face)
  * the result is 0xFFFF. The implementation does not check whether
  * the returned palette name id is actually in @face's `name` table.
  *
- * Since: 1.2.8
+ * Since: REPLACEME
  */
 unsigned int
 hb_ot_color_get_palette_name_id (hb_face_t *face, unsigned int palette)
 {
-  const OT::CPAL& cpal = _get_cpal(face);
-  if (unlikely (&cpal == &OT::Null(OT::CPAL) || cpal.version == 0 ||
-		palette >= cpal.numPalettes)) {
-    return 0xFFFF;
-  }
-
-  const OT::CPALV1Tail& cpal1 = OT::StructAfter<OT::CPALV1Tail>(cpal);
-  if (unlikely (&cpal1 == &OT::Null(OT::CPALV1Tail) ||
-		cpal1.paletteLabel.is_null())) {
-    return 0xFFFF;
-  }
-
-  const OT::USHORT* name_ids = &cpal1.paletteLabel (&cpal);
-  const OT::USHORT name_id = name_ids [palette];
-
-  // According to the OpenType CPAL specification, 0xFFFF means name-less.
-  return name_id;
+  const OT::CPAL& cpal = _get_cpal (face);
+  return cpal.get_palette_name_id (palette);
 }
 
 
@@ -119,26 +99,13 @@ hb_ot_color_get_palette_name_id (hb_face_t *face, unsigned int palette)
  * or if @palette is not between 0 and hb_ot_color_get_palette_count(),
  * the result is #HB_OT_COLOR_PALETTE_FLAG_DEFAULT.
  *
- * Since: 1.2.8
+ * Since: REPLACEME
  */
 hb_ot_color_palette_flags_t
 hb_ot_color_get_palette_flags (hb_face_t *face, unsigned int palette)
 {
   const OT::CPAL& cpal = _get_cpal(face);
-  if (unlikely (&cpal == &OT::Null(OT::CPAL) || cpal.version == 0 ||
-		palette >= cpal.numPalettes)) {
-    return HB_OT_COLOR_PALETTE_FLAG_DEFAULT;
-  }
-
-  const OT::CPALV1Tail& cpal1 = OT::StructAfter<OT::CPALV1Tail>(cpal);
-  if (unlikely (&cpal1 == &OT::Null(OT::CPALV1Tail) ||
-		cpal1.paletteFlags.is_null())) {
-    return HB_OT_COLOR_PALETTE_FLAG_DEFAULT;
-  }
-
-  const OT::ULONG* flags = &cpal1.paletteFlags(&cpal);
-  const uint32_t flag = static_cast<uint32_t> (flags [palette]);
-  return static_cast<hb_ot_color_palette_flags_t> (flag);
+  return cpal.get_palette_flags (palette);
 }
 
 
@@ -167,7 +134,7 @@ hb_ot_color_get_palette_flags (hb_face_t *face, unsigned int palette)
  * @palette is not between 0 and hb_ot_color_get_palette_count(),
  * the result is zero.
  *
- * Since: 1.2.8
+ * Since: REPLACEME
  */
 unsigned int
 hb_ot_color_get_palette_colors (hb_face_t       *face,
@@ -177,19 +144,13 @@ hb_ot_color_get_palette_colors (hb_face_t       *face,
 				hb_ot_color_t   *colors /* OUT */)
 {
   const OT::CPAL& cpal = _get_cpal(face);
-  if (unlikely (&cpal == &OT::Null(OT::CPAL) ||
-		palette >= cpal.numPalettes))
+  if (unlikely (palette >= cpal.numPalettes))
   {
     if (color_count) *color_count = 0;
     return 0;
   }
 
   const OT::ColorRecord* crec = &cpal.offsetFirstColorRecord (&cpal);
-  if (unlikely (crec == &OT::Null(OT::ColorRecord)))
-  {
-    if (color_count) *color_count = 0;
-    return 0;
-  }
   crec += cpal.colorRecordIndices[palette];
 
   unsigned int num_results = 0;
@@ -210,3 +171,4 @@ hb_ot_color_get_palette_colors (hb_face_t       *face,
   if (likely (color_count)) *color_count = num_results;
   return cpal.numPaletteEntries;
 }
+#endif
diff --git a/src/hb-ot-color.h b/src/hb-ot-color.h
index 2fe799f5..8f485667 100644
--- a/src/hb-ot-color.h
+++ b/src/hb-ot-color.h
@@ -41,7 +41,7 @@ HB_BEGIN_DECLS
  * HB_OT_TAG_CPAL:
  * a four-letter tag for identifying the CPAL table with color palettes
  *
- * Since: 1.2.8
+ * Since: REPLACEME
  */
 #define HB_OT_TAG_CPAL HB_TAG('C','P','A','L')
 
@@ -55,7 +55,7 @@ HB_BEGIN_DECLS
  *
  * Structure for holding color values.
  *
- * Since: 1.2.8
+ * Since: REPLACEME
  */
 typedef struct
 {
@@ -69,7 +69,7 @@ typedef struct
  * @HB_OT_COLOR_PALETTE_FLAG_FOR_LIGHT_BACKGROUND: flag indicating that the color palette is suitable for rendering text on light background.
  * @HB_OT_COLOR_PALETTE_FLAG_FOR_DARK_BACKGROUND: flag indicating that the color palette is suitable for rendering text on dark background.
  *
- * Since: 1.2.8
+ * Since: REPLACEME
  */
 typedef enum { /*< flags >*/
   HB_OT_COLOR_PALETTE_FLAG_DEFAULT = 0x00000000u,
@@ -77,22 +77,21 @@ typedef enum { /*< flags >*/
   HB_OT_COLOR_PALETTE_FLAG_FOR_DARK_BACKGROUND = 0x00000002u,
 } hb_ot_color_palette_flags_t;
 
+// HB_EXTERN unsigned int
+// hb_ot_color_get_palette_count (hb_face_t *face);
 
-HB_EXTERN unsigned int
-hb_ot_color_get_palette_count (hb_face_t *face);
+// HB_EXTERN unsigned int
+// hb_ot_color_get_palette_name_id (hb_face_t *face, unsigned int palette);
 
-HB_EXTERN unsigned int
-hb_ot_color_get_palette_name_id (hb_face_t *face, unsigned int palette);
+// HB_EXTERN hb_ot_color_palette_flags_t
+// hb_ot_color_get_palette_flags (hb_face_t *face, unsigned int palette);
 
-HB_EXTERN hb_ot_color_palette_flags_t
-hb_ot_color_get_palette_flags (hb_face_t *face, unsigned int palette);
-
-HB_EXTERN unsigned int
-hb_ot_color_get_palette_colors (hb_face_t       *face,
-				unsigned int     palette, /* default=0 */
-				unsigned int     start_offset,
-				unsigned int    *color_count /* IN/OUT */,
-				hb_ot_color_t   *colors /* OUT */);
+// HB_EXTERN unsigned int
+// hb_ot_color_get_palette_colors (hb_face_t       *face,
+// 				unsigned int     palette, /* default=0 */
+// 				unsigned int     start_offset,
+// 				unsigned int    *color_count /* IN/OUT */,
+// 				hb_ot_color_t   *colors /* OUT */);
 
 HB_END_DECLS
 
diff --git a/src/hb-ot-cpal-table.hh b/src/hb-ot-cpal-table.hh
index 3287346b..4369a7d3 100644
--- a/src/hb-ot-cpal-table.hh
+++ b/src/hb-ot-cpal-table.hh
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2016  Google, Inc.
+ * Copyright © 2018  Ebrahim Byagowi
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -43,34 +44,54 @@ struct ColorRecord
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
-    // We do not enforce alpha != 0 because zero alpha is bogus but harmless.
     TRACE_SANITIZE (this);
     return_trace (true);
   }
 
+  HBUINT8 blue;
+  HBUINT8 green;
+  HBUINT8 red;
+  HBUINT8 alpha;
   public:
-  BYTE blue;
-  BYTE green;
-  BYTE red;
-  BYTE alpha;
   DEFINE_SIZE_STATIC (4);
 };
 
 struct CPALV1Tail
 {
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  friend struct CPAL;
+
+  inline bool sanitize (hb_sanitize_context_t *c, unsigned int palettes) const
   {
     TRACE_SANITIZE (this);
-    return_trace (paletteFlags.sanitize (c, this) &&
-    		  paletteLabel.sanitize (c, this) &&
-    		  paletteEntryLabel.sanitize (c, this));
+    return_trace (
+      c->check_struct (this) &&
+      c->check_array ((const void*) &paletteFlags, sizeof (HBUINT32), palettes) &&
+      c->check_array ((const void*) &paletteLabel, sizeof (HBUINT16), palettes) &&
+      c->check_array ((const void*) &paletteEntryLabel, sizeof (HBUINT16), palettes));
+  }
+
+  private:
+  inline hb_ot_color_palette_flags_t
+  get_palette_flags (const void *base, unsigned int palette) const
+  {
+    const HBUINT32* flags = (const HBUINT32*) (const void*) &paletteFlags (base);
+    return (hb_ot_color_palette_flags_t) (uint32_t) flags[palette];
+  }
+
+  inline unsigned int
+  get_palette_name_id (const void *base, unsigned int palette) const
+  {
+    const HBUINT16* name_ids = (const HBUINT16*) (const void*) &paletteLabel (base);
+    return name_ids[palette];
   }
-  
+
+  protected:
+  LOffsetTo<HBUINT32> paletteFlags;
+  LOffsetTo<HBUINT16> paletteLabel;
+  LOffsetTo<HBUINT16> paletteEntryLabel;
+
   public:
-  OffsetTo<ULONG, ULONG> paletteFlags;
-  OffsetTo<USHORT, ULONG> paletteLabel;
-  OffsetTo<USHORT, ULONG> paletteEntryLabel;
-  DEFINE_SIZE_STATIC (12);  
+  DEFINE_SIZE_STATIC (12);
 };
 
 struct CPAL
@@ -80,36 +101,63 @@ struct CPAL
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (unlikely (!(c->check_struct (this) &&
-		    offsetFirstColorRecord.sanitize (c, this)))) {
+    if (!(c->check_struct (this) &&
+		    colorRecords.sanitize (c)))
       return_trace (false);
+
+    unsigned int palettes = numPalettes;
+    if (!c->check_array (colorRecordIndices, sizeof (HBUINT16), palettes))
+      return_trace (false);
+
+    for (unsigned int i = 0; i < palettes; ++i)
+      if (colorRecordIndices[i] + numPaletteEntries > colorRecords.get_size ())
+        return_trace (false);
+
+    if (version > 1)
+    {
+      const CPALV1Tail &v1 = StructAfter<CPALV1Tail> (*this);
+      return_trace (v1.sanitize (c, palettes));
     }
-    for (unsigned int i = 0; i < numPalettes; ++i) {
-      if (unlikely (colorRecordIndices[i] + numPaletteEntries > numColorRecords)) {
-	return_trace (false);
-      }
-    }
-    if (version > 1) {
-      const CPALV1Tail &v1 = StructAfter<CPALV1Tail>(*this);
-      return_trace (v1.sanitize (c));
-    } else {
+    else
       return_trace (true);
-    }
   }
 
-  inline unsigned int get_size (void) const {
+  inline unsigned int get_size (void) const
+  {
     return min_size + numPalettes * 2;
   }
 
-  public:
-  USHORT	version;
+  inline hb_ot_color_palette_flags_t get_palette_flags (unsigned int palette) const
+  {
+    if (version == 0 || palette >= numPalettes)
+      return HB_OT_COLOR_PALETTE_FLAG_DEFAULT;
+
+    const CPALV1Tail& cpal1 = StructAfter<CPALV1Tail> (*this);
+    return cpal1.get_palette_flags (this, palette);
+  }
+
+  inline unsigned int get_palette_name_id (unsigned int palette) const
+  {
+    if (version == 0 || palette >= numPalettes)
+      return 0xFFFF;
+
+    const CPALV1Tail& cpal1 = StructAfter<CPALV1Tail> (*this);
+    return cpal1.get_palette_name_id (this, palette);
+  }
+
+  inline unsigned int get_palette_count () const
+  {
+    return numPalettes;
+  }
+
+  protected:
+  HBUINT16	version;
 
   /* Version 0 */
-  USHORT	numPaletteEntries;
-  USHORT	numPalettes;
-  USHORT	numColorRecords;
-  OffsetTo<ColorRecord, ULONG> offsetFirstColorRecord;
-  USHORT	colorRecordIndices[VAR];  // VAR=numPalettes
+  HBUINT16	numPaletteEntries;
+  HBUINT16	numPalettes;
+  ArrayOf<ColorRecord>	colorRecords;
+  HBUINT16	colorRecordIndices[VAR];  // VAR=numPalettes
 
   public:
   DEFINE_SIZE_ARRAY (12, colorRecordIndices);
diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh
index 92aa122f..a8f06f6a 100644
--- a/src/hb-ot-layout-private.hh
+++ b/src/hb-ot-layout-private.hh
@@ -165,16 +165,15 @@ struct hb_ot_layout_t
   hb_blob_t *gdef_blob;
   hb_blob_t *gsub_blob;
   hb_blob_t *gpos_blob;
-  hb_blob_t *cpal_blob;
 
   const struct OT::GDEF *gdef;
   const struct OT::GSUB *gsub;
   const struct OT::GPOS *gpos;
-  const struct OT::CPAL *cpal;
 
   /* TODO Move the following out of this struct. */
   OT::hb_lazy_table_loader_t<struct OT::BASE> base;
   OT::hb_lazy_table_loader_t<struct OT::MATH> math;
+  OT::hb_lazy_table_loader_t<struct OT::CPAL> cpal;
   OT::hb_lazy_table_loader_t<struct OT::fvar> fvar;
   OT::hb_lazy_table_loader_t<struct OT::avar> avar;
   OT::hb_lazy_table_loader_t<struct AAT::ankr> ankr;
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index e099fd05..beef8419 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -30,6 +30,7 @@
 
 #include "hb-open-type-private.hh"
 #include "hb-ot-layout-private.hh"
+
 #include "hb-ot-layout-base-table.hh"
 #include "hb-ot-layout-gdef-table.hh"
 #include "hb-ot-layout-gsub-table.hh"
@@ -63,6 +64,7 @@ _hb_ot_layout_create (hb_face_t *face)
   layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
 
   layout->math.init (face);
+  layout->cpal.init (face);
   layout->base.init (face);
   layout->fvar.init (face);
   layout->avar.init (face);
@@ -70,7 +72,6 @@ _hb_ot_layout_create (hb_face_t *face)
   layout->kerx.init (face);
   layout->morx.init (face);
   layout->trak.init (face);
-  layout->cpal.init (face);
 
   {
     /*
@@ -218,6 +219,7 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout)
   hb_blob_destroy (layout->gpos_blob);
 
   layout->math.fini ();
+  layout->cpal.fini ();
   layout->base.fini ();
   layout->fvar.fini ();
   layout->avar.fini ();
@@ -225,7 +227,6 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout)
   layout->kerx.fini ();
   layout->morx.fini ();
   layout->trak.fini ();
-  layout->cpal.fini ();
 
   free (layout);
 }
diff --git a/test/api/hb-test.h b/test/api/hb-test.h
index 6b0df139..c851f809 100644
--- a/test/api/hb-test.h
+++ b/test/api/hb-test.h
@@ -88,6 +88,7 @@ hb_test_run (void)
 }
 
 
+#if 0
 /* Helpers for loading test fonts */
 static inline hb_face_t *
 hb_test_load_face (const char *path)
@@ -116,6 +117,7 @@ hb_test_load_face (const char *path)
   hb_blob_destroy (blob);
   return face;
 }
+#endif
 
 
 /* Bugzilla helpers */
diff --git a/test/api/test-ot-color.c b/test/api/test-ot-color.c
index 93589b16..22584d20 100644
--- a/test/api/test-ot-color.c
+++ b/test/api/test-ot-color.c
@@ -103,25 +103,26 @@ static hb_face_t *cpal_v1 = NULL;
   const hb_ot_color_t *_colors = (colors); \
   const size_t _i = (i); \
   const uint8_t red = (r), green = (g), blue = (b), alpha = (a); \
-  if (_colors[_i].red != r) { \
+  if (_colors[_i].red != red) { \
     g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
 				"colors[" #i "].red", _colors[_i].red, "==", red, 'x'); \
   } \
-  if (colors[i].green != green) { \
+  if (_colors[_i].green != green) { \
     g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
-				"colors[" #i "].green", colors[i].green, "==", green, 'x'); \
+				"colors[" #i "].green", _colors[_i].green, "==", green, 'x'); \
   } \
-  if (colors[i].blue != blue) { \
+  if (_colors[_i].blue != blue) { \
     g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
 				"colors[" #i "].blue", colors[i].blue, "==", blue, 'x'); \
   } \
-  if (colors[i].alpha != alpha) { \
+  if (_colors[_i].alpha != alpha) { \
     g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
-				"colors[" #i "].alpha", colors[i].alpha, "==", alpha, 'x'); \
+				"colors[" #i "].alpha", _colors[_i].alpha, "==", alpha, 'x'); \
   } \
 } G_STMT_END
 
 
+#if 0
 static void
 test_hb_ot_color_get_palette_count (void)
 {
@@ -291,7 +292,7 @@ test_hb_ot_color_get_palette_colors_v1 (void)
   assert_color_rgba (colors, 1, 0x77, 0x77, 0x77, 0x77);  /* untouched */
   assert_color_rgba (colors, 2, 0x77, 0x77, 0x77, 0x77);  /* untouched */
 }
-
+#endif
 
 int
 main (int argc, char **argv)
@@ -299,18 +300,18 @@ main (int argc, char **argv)
   int status = 0;
 
   hb_test_init (&argc, &argv);
-  cpal_v0 = hb_test_load_face ("../shaping/fonts/sha1sum/e90374e5e439e00725b4fe7a8d73db57c5a97f82.ttf");
-  cpal_v1 = hb_test_load_face ("../shaping/fonts/sha1sum/319f5d7ebffbefc5c5e6569f8cea73444d7a7268.ttf");
-  hb_test_add (test_hb_ot_color_get_palette_count);
-  hb_test_add (test_hb_ot_color_get_palette_name_id_empty);
-  hb_test_add (test_hb_ot_color_get_palette_name_id_v0);
-  hb_test_add (test_hb_ot_color_get_palette_name_id_v1);
-  hb_test_add (test_hb_ot_color_get_palette_flags_empty);
-  hb_test_add (test_hb_ot_color_get_palette_flags_v0);
-  hb_test_add (test_hb_ot_color_get_palette_flags_v1);
-  hb_test_add (test_hb_ot_color_get_palette_colors_empty);
-  hb_test_add (test_hb_ot_color_get_palette_colors_v0);
-  hb_test_add (test_hb_ot_color_get_palette_colors_v1);
+  // cpal_v0 = hb_test_load_face ("../shaping/data/in-house/fonts/e90374e5e439e00725b4fe7a8d73db57c5a97f82.ttf");
+  // cpal_v1 = hb_test_load_face ("../shaping/data/in-house/fonts/319f5d7ebffbefc5c5e6569f8cea73444d7a7268.ttf");
+  // hb_test_add (test_hb_ot_color_get_palette_count);
+  // hb_test_add (test_hb_ot_color_get_palette_name_id_empty);
+  // hb_test_add (test_hb_ot_color_get_palette_name_id_v0);
+  // hb_test_add (test_hb_ot_color_get_palette_name_id_v1);
+  // hb_test_add (test_hb_ot_color_get_palette_flags_empty);
+  // hb_test_add (test_hb_ot_color_get_palette_flags_v0);
+  // hb_test_add (test_hb_ot_color_get_palette_flags_v1);
+  // hb_test_add (test_hb_ot_color_get_palette_colors_empty);
+  // hb_test_add (test_hb_ot_color_get_palette_colors_v0);
+  // hb_test_add (test_hb_ot_color_get_palette_colors_v1);
   status = hb_test_run();
   hb_face_destroy (cpal_v0);
   hb_face_destroy (cpal_v1);
diff --git a/test/shaping/fonts/sha1sum/319f5d7ebffbefc5c5e6569f8cea73444d7a7268.ttf b/test/shaping/data/in-house/fonts/319f5d7ebffbefc5c5e6569f8cea73444d7a7268.ttf
similarity index 100%
rename from test/shaping/fonts/sha1sum/319f5d7ebffbefc5c5e6569f8cea73444d7a7268.ttf
rename to test/shaping/data/in-house/fonts/319f5d7ebffbefc5c5e6569f8cea73444d7a7268.ttf
diff --git a/test/shaping/fonts/sha1sum/e90374e5e439e00725b4fe7a8d73db57c5a97f82.ttf b/test/shaping/data/in-house/fonts/e90374e5e439e00725b4fe7a8d73db57c5a97f82.ttf
similarity index 100%
rename from test/shaping/fonts/sha1sum/e90374e5e439e00725b4fe7a8d73db57c5a97f82.ttf
rename to test/shaping/data/in-house/fonts/e90374e5e439e00725b4fe7a8d73db57c5a97f82.ttf
commit 6836a821428b714b9f2e95d5c4ebbd73867d9a53
Author: Rod Sheeter <rsheeter at google.com>
Date:   Tue Feb 27 20:51:12 2018 -0800

    [subset] remove WE_HAVE_INSTRUCTIONS from composites when dropping hints

diff --git a/src/hb-subset-glyf.cc b/src/hb-subset-glyf.cc
index 696a74de..03676668 100644
--- a/src/hb-subset-glyf.cc
+++ b/src/hb-subset-glyf.cc
@@ -180,7 +180,17 @@ _write_glyf_and_loca_prime (hb_subset_plan_t              *plan,
       memcpy (glyf_prime_data_next + instruction_start - start_offset, glyf_data + instruction_end, end_offset - instruction_end);
       /* if the instructions end at the end this was a composite glyph */
       if (instruction_end == end_offset)
-        ; // TODO(rsheeter) remove WE_HAVE_INSTRUCTIONS from last flags
+      {
+        /* remove WE_HAVE_INSTRUCTIONS from flags in dest */
+        OT::glyf::CompositeGlyphHeader::Iterator composite_it;
+        if (unlikely (!OT::glyf::CompositeGlyphHeader::get_iterator (glyf_prime_data_next, length, &composite_it))) return false;
+        const OT::glyf::CompositeGlyphHeader *glyph;
+        do {
+          glyph = composite_it.current;
+          OT::HBUINT16 *flags = const_cast<OT::HBUINT16 *> (&glyph->flags);
+          flags->set ( (uint16_t) *flags & ~OT::glyf::CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS);
+        } while (composite_it.move_to_next());
+      }
       else
         /* zero instruction length, which is just before instruction_start */
         memset (glyf_prime_data_next + instruction_start - start_offset - 2, 0, 2);
commit ffcb5cbf71b312cdd4606a3285e10e201ff5bccd
Author: Rod Sheeter <rsheeter at google.com>
Date:   Tue Feb 27 20:17:04 2018 -0800

    [subset] update the test file for composite, fix an offset calculation

diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh
index 53360182..e4d3ec85 100644
--- a/src/hb-ot-glyf-table.hh
+++ b/src/hb-ot-glyf-table.hh
@@ -412,7 +412,7 @@ struct glyf
         } while (composite_it.move_to_next());
 
         if ( (uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS)
-          *instruction_start = start_offset + ((char *) last - (char *) glyf_table->dataX) + last->get_size();
+          *instruction_start = ((char *) last - (char *) glyf_table->dataX) + last->get_size();
         else
           *instruction_start = end_offset;
         *instruction_end = end_offset;
diff --git a/test/api/fonts/Roboto-Regular.components.1fc.nohints.ttf b/test/api/fonts/Roboto-Regular.components.1fc.nohints.ttf
new file mode 100644
index 00000000..d36cc816
Binary files /dev/null and b/test/api/fonts/Roboto-Regular.components.1fc.nohints.ttf differ
diff --git a/test/api/test-subset-glyf.c b/test/api/test-subset-glyf.c
index 1caa5269..8e17e8d5 100644
--- a/test/api/test-subset-glyf.c
+++ b/test/api/test-subset-glyf.c
@@ -143,12 +143,11 @@ test_subset_glyf_strip_hints_simple (void)
   hb_face_destroy (face_ac);
 }
 
-// TODO(rsheeter): test strip hints from composite
 static void
 test_subset_glyf_strip_hints_composite (void)
 {
   hb_face_t *face_components = hb_subset_test_open_font ("fonts/Roboto-Regular.components.ttf");
-  hb_face_t *face_subset = hb_subset_test_open_font ("fonts/Roboto-Regular.components.subset.ttf");
+  hb_face_t *face_subset = hb_subset_test_open_font ("fonts/Roboto-Regular.components.1fc.nohints.ttf");
 
   hb_set_t *codepoints = hb_set_create();
   hb_set_add (codepoints, 0x1fc);
@@ -160,7 +159,7 @@ test_subset_glyf_strip_hints_composite (void)
 
   hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('g','l','y','f'));
   hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('l','o','c', 'a'));
-  check_maxp_num_glyphs(face_generated_subset, 4);
+  check_maxp_num_glyphs(face_generated_subset, 4, false);
 
   hb_face_destroy (face_generated_subset);
   hb_face_destroy (face_subset);
commit c8b230e4377bc8e80d37835a229511ce0e30cc47
Merge: b3790a65 904dd7be
Author: Rod Sheeter <rsheeter at google.com>
Date:   Tue Feb 27 17:25:32 2018 -0800

    Merge branch 'expand-tests' of github.com:googlefonts/harfbuzz into drophints

commit 904dd7beea756fd7429fad36f5c37321aedb4e81
Author: Garret Rieger <grieger at google.com>
Date:   Tue Feb 27 14:33:36 2018 -0800

    [subset] Add drop hinting profile to full-font.tests

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
new file mode 100644
index 00000000..98f01e19
Binary files /dev/null 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
new file mode 100644
index 00000000..ea212f03
Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf differ
diff --git a/test/subset/data/tests/full-font.tests b/test/subset/data/tests/full-font.tests
index 0ed6016b..f0a262bf 100644
--- a/test/subset/data/tests/full-font.tests
+++ b/test/subset/data/tests/full-font.tests
@@ -3,6 +3,7 @@ Roboto-Regular.ttf
 
 PROFILES:
 default.txt
+drop-hints.txt
 
 SUBSETS:
 abc
commit 70a1049b3f8dc241fcb9b524bd010f0c1606f6ad
Author: Garret Rieger <grieger at google.com>
Date:   Tue Feb 27 14:28:50 2018 -0800

    [subset] Add a drop hints profile to basics.tests

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
new file mode 100644
index 00000000..70206add
Binary files /dev/null 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
new file mode 100644
index 00000000..c74c0299
Binary files /dev/null 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
new file mode 100644
index 00000000..8ba816d7
Binary files /dev/null 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
new file mode 100644
index 00000000..837438a5
Binary files /dev/null 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
new file mode 100644
index 00000000..311737ab
Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.63.ttf differ
diff --git a/test/subset/data/profiles/drop-hints.txt b/test/subset/data/profiles/drop-hints.txt
new file mode 100644
index 00000000..e5cd9743
--- /dev/null
+++ b/test/subset/data/profiles/drop-hints.txt
@@ -0,0 +1 @@
+--no-hinting
diff --git a/test/subset/data/tests/basics.tests b/test/subset/data/tests/basics.tests
index 51dba2e7..97254454 100644
--- a/test/subset/data/tests/basics.tests
+++ b/test/subset/data/tests/basics.tests
@@ -3,6 +3,7 @@ Roboto-Regular.abc.ttf
 
 PROFILES:
 default.txt
+drop-hints.txt
 
 SUBSETS:
 abc
commit 5241d7f4b999d5457de564bd950b60d70f9d0e19
Author: Garret Rieger <grieger at google.com>
Date:   Tue Feb 27 13:15:40 2018 -0800

    [subset] apply subset profiles (flags) to the subset integration tests.

diff --git a/test/subset/generate-expected-outputs.py b/test/subset/generate-expected-outputs.py
index 1be89b75..9ebf082f 100755
--- a/test/subset/generate-expected-outputs.py
+++ b/test/subset/generate-expected-outputs.py
@@ -15,16 +15,17 @@ def usage():
 	print "Usage: generate-expected-outputs.py <test suite file> ..."
 
 
-def generate_expected_output(input_file, unicodes, output_path):
-	check_call(["fonttools", "subset",
-		    input_file,
-                    "--notdef-outline",
-                    "--name-IDs=*",
-                    "--name-languages=*",
-                    "--name-legacy",
-		    "--drop-tables+=DSIG,GPOS,GSUB,GDEF",
-		    "--unicodes=%s" % unicodes,
-		    "--output-file=%s" % output_path])
+def generate_expected_output(input_file, unicodes, profile_flags, output_path):
+	args = ["fonttools", "subset", input_file]
+	args.extend(profile_flags)
+	args.extend(["--notdef-outline",
+		     "--name-IDs=*",
+		     "--name-languages=*",
+		     "--name-legacy",
+		     "--drop-tables+=DSIG,GPOS,GSUB,GDEF",
+		     "--unicodes=%s" % unicodes,
+		     "--output-file=%s" % output_path])
+	check_call(args)
 
 
 args = sys.argv[1:]
@@ -41,6 +42,6 @@ for path in args:
 			unicodes = test.unicodes()
 			font_name = test.get_font_name()
 			print "Creating subset %s/%s" % (output_directory, font_name)
-			generate_expected_output(test.font_path, unicodes,
-															 os.path.join(output_directory,
-																						font_name))
+			generate_expected_output(test.font_path, unicodes, test.get_profile_flags(),
+						 os.path.join(output_directory,
+							      font_name))
diff --git a/test/subset/run-tests.py b/test/subset/run-tests.py
index 99f97826..f1ef4614 100755
--- a/test/subset/run-tests.py
+++ b/test/subset/run-tests.py
@@ -44,6 +44,7 @@ def run_test(test):
 		    "--font-file=" + test.font_path,
 		    "--output-file=" + out_file,
 		    "--unicodes=%s" % test.unicodes()]
+	cli_args.extend (test.get_profile_flags())
 	print (' '.join(cli_args))
 	_, return_code = cmd(cli_args)
 
@@ -78,7 +79,7 @@ def run_ttx(file):
 
 def strip_check_sum (ttx_string):
 	return re.sub ('checkSumAdjustment value=["]0x([0-9a-fA-F])+["]',
-                       'checkSumAdjustment value="0x00000000"',
+		       'checkSumAdjustment value="0x00000000"',
 		       ttx_string, count=1)
 
 args = sys.argv[1:]
diff --git a/test/subset/subset_test_suite.py b/test/subset/subset_test_suite.py
index 256e2071..35386508 100644
--- a/test/subset/subset_test_suite.py
+++ b/test/subset/subset_test_suite.py
@@ -1,5 +1,6 @@
 #!/usr/bin/env python
 
+import io
 import os
 
 # A single test in a subset test suite. Identifies a font
@@ -13,15 +14,19 @@ class Test:
 	def unicodes(self):
 		return ",".join("%X" % ord(c) for (i, c) in enumerate(self.subset))
 
+	def get_profile_flags(self):
+		with io.open(self.profile_path, mode="r", encoding="utf-8") as f:
+		    return f.read().splitlines();
+
 	def get_font_name(self):
 		font_base_name = os.path.basename(self.font_path)
 		font_base_name_parts = os.path.splitext(font_base_name)
 		profile_name = os.path.splitext(os.path.basename(self.profile_path))[0]
 
 		return "%s.%s.%s%s" % (font_base_name_parts[0],
-													 profile_name,
-													 self.unicodes(),
-													 font_base_name_parts[1])
+				       profile_name,
+				       self.unicodes(),
+				       font_base_name_parts[1])
 
 # A group of tests to perform on the subsetter. Each test
 # Identifies a font a subsetting profile, and a subset to be cut.
commit a4aca190a93f94c25c906ec0269183d8b2d0b5e8
Author: Garret Rieger <grieger at google.com>
Date:   Tue Feb 27 11:36:16 2018 -0800

    [subset] add expected/full-font to dist files.

diff --git a/test/subset/data/Makefile.am b/test/subset/data/Makefile.am
index f1234db8..0b001343 100644
--- a/test/subset/data/Makefile.am
+++ b/test/subset/data/Makefile.am
@@ -8,6 +8,7 @@ SUBDIRS =
 EXTRA_DIST = \
 	$(TESTS) \
 	expected/basics \
+	expected/full-font \
 	fonts \
 	profiles \
 	$(NULL)
commit d31ace32740b1777ebb023ffdb10cd0cfec3997e
Author: Garret Rieger <grieger at google.com>
Date:   Mon Feb 26 18:51:56 2018 -0800

    [subset] Add subset integration tests using the full roboto font.

diff --git a/test/subset/data/Makefile.sources b/test/subset/data/Makefile.sources
index 37550b63..bc813937 100644
--- a/test/subset/data/Makefile.sources
+++ b/test/subset/data/Makefile.sources
@@ -1,5 +1,6 @@
 TESTS = \
 	tests/basics.tests \
+	tests/full-font.tests \
 	$(NULL)
 
 XFAIL_TESTS = \
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
new file mode 100644
index 00000000..60e361d2
Binary files /dev/null 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
new file mode 100644
index 00000000..1fc430a4
Binary files /dev/null and b/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf differ
diff --git a/test/subset/data/fonts/Roboto-Regular.ttf b/test/subset/data/fonts/Roboto-Regular.ttf
new file mode 100644
index 00000000..2c97eead
Binary files /dev/null and b/test/subset/data/fonts/Roboto-Regular.ttf differ
diff --git a/test/subset/data/tests/full-font.tests b/test/subset/data/tests/full-font.tests
new file mode 100644
index 00000000..0ed6016b
--- /dev/null
+++ b/test/subset/data/tests/full-font.tests
@@ -0,0 +1,10 @@
+FONTS:
+Roboto-Regular.ttf
+
+PROFILES:
+default.txt
+
+SUBSETS:
+abc
+Ǽ!A bc
+
diff --git a/test/subset/generate-expected-outputs.py b/test/subset/generate-expected-outputs.py
index 6dac890e..1be89b75 100755
--- a/test/subset/generate-expected-outputs.py
+++ b/test/subset/generate-expected-outputs.py
@@ -17,10 +17,14 @@ def usage():
 
 def generate_expected_output(input_file, unicodes, output_path):
 	check_call(["fonttools", "subset",
-							input_file,
-							"--drop-tables+=DSIG,GPOS,GSUB,GDEF",
-							"--unicodes=%s" % unicodes,
-							"--output-file=%s" % output_path])
+		    input_file,
+                    "--notdef-outline",
+                    "--name-IDs=*",
+                    "--name-languages=*",
+                    "--name-legacy",
+		    "--drop-tables+=DSIG,GPOS,GSUB,GDEF",
+		    "--unicodes=%s" % unicodes,
+		    "--output-file=%s" % output_path])
 
 
 args = sys.argv[1:]
commit 33f4381314c5248b8b112e344af7548806f93a82
Author: Garret Rieger <grieger at google.com>
Date:   Mon Feb 26 18:39:09 2018 -0800

    [subset] Add some more variations of the basic test.

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
new file mode 100644
index 00000000..02cd7efb
Binary files /dev/null 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
new file mode 100644
index 00000000..4942ad0c
Binary files /dev/null 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
new file mode 100644
index 00000000..08fe7718
Binary files /dev/null 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.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf
new file mode 100644
index 00000000..0f3a934c
Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf differ
diff --git a/test/subset/data/tests/basics.tests b/test/subset/data/tests/basics.tests
index 8a7246b9..51dba2e7 100644
--- a/test/subset/data/tests/basics.tests
+++ b/test/subset/data/tests/basics.tests
@@ -5,4 +5,8 @@ PROFILES:
 default.txt
 
 SUBSETS:
+abc
 b
+c
+ac
+a
commit b3790a65a18e8402b2b09dfc24aaea40a51de569
Author: Rod Sheeter <rsheeter at google.com>
Date:   Tue Feb 27 17:23:30 2018 -0800

    [subset] add a (failing for now) test for composite glyf hint dropping

diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh
index 441d4b9e..53360182 100644
--- a/src/hb-ot-glyf-table.hh
+++ b/src/hb-ot-glyf-table.hh
@@ -402,14 +402,14 @@ struct glyf
       int16_t num_contours = (int16_t) glyph_header.numberOfContours;
       if (num_contours < 0)
       {
-        CompositeGlyphHeader::Iterator *composite_it;
+        CompositeGlyphHeader::Iterator composite_it;
         if (unlikely (!CompositeGlyphHeader::get_iterator (
             (const char*) this->glyf_table + start_offset,
-             end_offset - start_offset, composite_it))) return false;
+             end_offset - start_offset, &composite_it))) return false;
         const CompositeGlyphHeader *last;
         do {
-          last = composite_it->current;
-        } while (composite_it->move_to_next());
+          last = composite_it.current;
+        } while (composite_it.move_to_next());
 
         if ( (uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS)
           *instruction_start = start_offset + ((char *) last - (char *) glyf_table->dataX) + last->get_size();
diff --git a/test/api/test-subset-glyf.c b/test/api/test-subset-glyf.c
index f5fdf32d..54665162 100644
--- a/test/api/test-subset-glyf.c
+++ b/test/api/test-subset-glyf.c
@@ -105,7 +105,7 @@ test_subset_glyf_noop (void)
 }
 
 static void
-test_subset_glyf_strip_hints (void)
+test_subset_glyf_strip_hints_simple (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.nohints.ttf");
@@ -128,6 +128,28 @@ test_subset_glyf_strip_hints (void)
 }
 
 // TODO(rsheeter): test strip hints from composite
+static void
+test_subset_glyf_strip_hints_composite (void)
+{
+  hb_face_t *face_components = hb_subset_test_open_font ("fonts/Roboto-Regular.components.ttf");
+  hb_face_t *face_subset = hb_subset_test_open_font ("fonts/Roboto-Regular.components.subset.ttf");
+
+  hb_set_t *codepoints = hb_set_create();
+  hb_set_add (codepoints, 0x1fc);
+  hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
+  *hb_subset_input_drop_hints(input) = true;
+
+  hb_face_t *face_generated_subset = hb_subset_test_create_subset (face_components, input);
+  hb_set_destroy (codepoints);
+
+  hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('g','l','y','f'));
+  hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('l','o','c', 'a'));
+  check_maxp_num_glyphs(face_generated_subset, 4);
+
+  hb_face_destroy (face_generated_subset);
+  hb_face_destroy (face_subset);
+  hb_face_destroy (face_components);
+}
 
 // TODO(grieger): test for long loca generation.
 
@@ -138,7 +160,8 @@ main (int argc, char **argv)
 
   hb_test_add (test_subset_glyf_noop);
   hb_test_add (test_subset_glyf);
-  hb_test_add (test_subset_glyf_strip_hints);
+  hb_test_add (test_subset_glyf_strip_hints_simple);
+  hb_test_add (test_subset_glyf_strip_hints_composite);
   hb_test_add (test_subset_glyf_with_components);
 
   return hb_test_run();
commit 4c6023f861a4b87782c17ac626ffee7e93f15fc8
Merge: d7633d0a 921b65cb
Author: Garret Rieger <grieger at google.com>
Date:   Tue Feb 27 17:06:27 2018 -0700

    Merge pull request #842 from googlefonts/maxp
    
    [subset] when dropping hints, clear hint related fields in maxp.

commit 921b65cbc29f0c2c9c13e9fb272dafe4c8a14591
Author: Garret Rieger <grieger at google.com>
Date:   Tue Feb 27 14:37:18 2018 -0800

    [subset] minor fixes in hb-ot-maxp-table.hh

diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh
index 77aa4e51..881dedad 100644
--- a/src/hb-ot-maxp-table.hh
+++ b/src/hb-ot-maxp-table.hh
@@ -52,19 +52,19 @@ struct maxpV1Tail
   HBUINT16 maxCompositePoints;	  /* Maximum points in a composite glyph. */
   HBUINT16 maxCompositeContours;  /* Maximum contours in a composite glyph. */
   HBUINT16 maxZones;		  /* 1 if instructions do not use the twilight zone (Z0),
-				     or 2 if instructions do use Z0; should be set to 2 in
-				     most cases. */
+				   * or 2 if instructions do use Z0; should be set to 2 in
+				   * most cases. */
   HBUINT16 maxTwilightPoints;	  /* Maximum points used in Z0. */
   HBUINT16 maxStorage;		  /* Number of Storage Area locations. */
   HBUINT16 maxFunctionDefs;	  /* Number of FDEFs, equal to the highest function number + 1. */
   HBUINT16 maxInstructionDefs;	  /* Number of IDEFs. */
   HBUINT16 maxStackElements;	  /* Maximum stack depth. (This includes Font and CVT
-				     Programs, as well as the instructions for each glyph.) */
+				   * Programs, as well as the instructions for each glyph.) */
   HBUINT16 maxSizeOfInstructions; /* Maximum byte count for glyph instructions. */
   HBUINT16 maxComponentElements;  /* Maximum number of components referenced at
-				     "top level" for any composite glyph. */
+				   * "top level" for any composite glyph. */
   HBUINT16 maxComponentDepth;	  /* Maximum levels of recursion; 1 for simple components. */
-
+ public:
   DEFINE_SIZE_STATIC (26);
 };
 
@@ -119,9 +119,9 @@ struct maxp
 
   static inline void drop_hint_fields (hb_subset_plan_t *plan, OT::maxp *maxp_prime)
   {
-    maxpV1Tail &v1 = StructAfter<maxpV1Tail> (*maxp_prime);
     if (maxp_prime->version.major == 1)
     {
+      maxpV1Tail &v1 = StructAfter<maxpV1Tail> (*maxp_prime);
       v1.maxZones.set (1);
       v1.maxTwilightPoints.set (0);
       v1.maxStorage.set (0);
@@ -136,8 +136,7 @@ struct maxp
   FixedVersion<>version;		/* Version of the maxp table (0.5 or 1.0),
 					 * 0x00005000u or 0x00010000u. */
   HBUINT16	numGlyphs;		/* The number of glyphs in the font. */
-/*maxpV1Tail v1Tail; */
-
+/*maxpV1Tail v1Tail[VAR]; */
   public:
   DEFINE_SIZE_STATIC (6);
 };
commit b26db48bfff804e139331817a86ecc811547afcd
Author: Garret Rieger <grieger at google.com>
Date:   Tue Feb 27 14:14:05 2018 -0800

    [subset] whitespace for hb-ot-maxp-table.hh

diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh
index c8727464..77aa4e51 100644
--- a/src/hb-ot-maxp-table.hh
+++ b/src/hb-ot-maxp-table.hh
@@ -47,23 +47,23 @@ struct maxpV1Tail
     return_trace (c->check_struct (this));
   }
 
-  HBUINT16 maxPoints;             /* Maximum points in a non-composite glyph. */
-  HBUINT16 maxContours;           /* Maximum contours in a non-composite glyph. */
-  HBUINT16 maxCompositePoints;    /* Maximum points in a composite glyph. */
+  HBUINT16 maxPoints;		  /* Maximum points in a non-composite glyph. */
+  HBUINT16 maxContours;		  /* Maximum contours in a non-composite glyph. */
+  HBUINT16 maxCompositePoints;	  /* Maximum points in a composite glyph. */
   HBUINT16 maxCompositeContours;  /* Maximum contours in a composite glyph. */
-  HBUINT16 maxZones;              /* 1 if instructions do not use the twilight zone (Z0),
-                                     or 2 if instructions do use Z0; should be set to 2 in
-                                     most cases. */
-  HBUINT16 maxTwilightPoints;     /* Maximum points used in Z0. */
-  HBUINT16 maxStorage;            /* Number of Storage Area locations. */
-  HBUINT16 maxFunctionDefs;       /* Number of FDEFs, equal to the highest function number + 1. */
-  HBUINT16 maxInstructionDefs;    /* Number of IDEFs. */
-  HBUINT16 maxStackElements;      /* Maximum stack depth. (This includes Font and CVT
-                                     Programs, as well as the instructions for each glyph.) */
+  HBUINT16 maxZones;		  /* 1 if instructions do not use the twilight zone (Z0),
+				     or 2 if instructions do use Z0; should be set to 2 in
+				     most cases. */
+  HBUINT16 maxTwilightPoints;	  /* Maximum points used in Z0. */
+  HBUINT16 maxStorage;		  /* Number of Storage Area locations. */
+  HBUINT16 maxFunctionDefs;	  /* Number of FDEFs, equal to the highest function number + 1. */
+  HBUINT16 maxInstructionDefs;	  /* Number of IDEFs. */
+  HBUINT16 maxStackElements;	  /* Maximum stack depth. (This includes Font and CVT
+				     Programs, as well as the instructions for each glyph.) */
   HBUINT16 maxSizeOfInstructions; /* Maximum byte count for glyph instructions. */
   HBUINT16 maxComponentElements;  /* Maximum number of components referenced at
-                                     "top level" for any composite glyph. */
-  HBUINT16 maxComponentDepth;     /* Maximum levels of recursion; 1 for simple components. */
+				     "top level" for any composite glyph. */
+  HBUINT16 maxComponentDepth;	  /* Maximum levels of recursion; 1 for simple components. */
 
   DEFINE_SIZE_STATIC (26);
 };
@@ -71,7 +71,7 @@ struct maxpV1Tail
 
 struct maxp
 {
-  static const hb_tag_t tableTag	= HB_OT_TAG_maxp;
+  static const hb_tag_t tableTag = HB_OT_TAG_maxp;
 
   inline unsigned int get_num_glyphs (void) const
   {
commit a76344da796670f33b2fa48a9b1676545dac93c2
Author: Garret Rieger <grieger at google.com>
Date:   Tue Feb 27 14:11:36 2018 -0800

    [subset] Add maxpV1Tail instead of defining a struct inside maxp for v1 data.

diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh
index ea6b4f04..c8727464 100644
--- a/src/hb-ot-maxp-table.hh
+++ b/src/hb-ot-maxp-table.hh
@@ -39,6 +39,36 @@ namespace OT {
 
 #define HB_OT_TAG_maxp HB_TAG('m','a','x','p')
 
+struct maxpV1Tail
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  HBUINT16 maxPoints;             /* Maximum points in a non-composite glyph. */
+  HBUINT16 maxContours;           /* Maximum contours in a non-composite glyph. */
+  HBUINT16 maxCompositePoints;    /* Maximum points in a composite glyph. */
+  HBUINT16 maxCompositeContours;  /* Maximum contours in a composite glyph. */
+  HBUINT16 maxZones;              /* 1 if instructions do not use the twilight zone (Z0),
+                                     or 2 if instructions do use Z0; should be set to 2 in
+                                     most cases. */
+  HBUINT16 maxTwilightPoints;     /* Maximum points used in Z0. */
+  HBUINT16 maxStorage;            /* Number of Storage Area locations. */
+  HBUINT16 maxFunctionDefs;       /* Number of FDEFs, equal to the highest function number + 1. */
+  HBUINT16 maxInstructionDefs;    /* Number of IDEFs. */
+  HBUINT16 maxStackElements;      /* Maximum stack depth. (This includes Font and CVT
+                                     Programs, as well as the instructions for each glyph.) */
+  HBUINT16 maxSizeOfInstructions; /* Maximum byte count for glyph instructions. */
+  HBUINT16 maxComponentElements;  /* Maximum number of components referenced at
+                                     "top level" for any composite glyph. */
+  HBUINT16 maxComponentDepth;     /* Maximum levels of recursion; 1 for simple components. */
+
+  DEFINE_SIZE_STATIC (26);
+};
+
+
 struct maxp
 {
   static const hb_tag_t tableTag	= HB_OT_TAG_maxp;
@@ -56,9 +86,15 @@ struct maxp
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-		  likely ((version.major == 1 && c->check_range (this, sizeof (maxp))) ||
-			  (version.major == 0 && version.minor == 0x5000u)));
+    if (unlikely (!c->check_struct (this)))
+      return_trace (false);
+
+    if (version.major == 1)
+    {
+      const maxpV1Tail &v1 = StructAfter<maxpV1Tail> (*this);
+      return v1.sanitize (c);
+    }
+    return_trace (likely (version.major == 0 && version.minor == 0x5000u));
   }
 
   inline bool subset (hb_subset_plan_t *plan) const
@@ -83,15 +119,16 @@ struct maxp
 
   static inline void drop_hint_fields (hb_subset_plan_t *plan, OT::maxp *maxp_prime)
   {
+    maxpV1Tail &v1 = StructAfter<maxpV1Tail> (*maxp_prime);
     if (maxp_prime->version.major == 1)
     {
-      maxp_prime->version_1_data.maxZones.set (1);
-      maxp_prime->version_1_data.maxTwilightPoints.set (0);
-      maxp_prime->version_1_data.maxStorage.set (0);
-      maxp_prime->version_1_data.maxFunctionDefs.set (0);
-      maxp_prime->version_1_data.maxInstructionDefs.set (0);
-      maxp_prime->version_1_data.maxStackElements.set (0);
-      maxp_prime->version_1_data.maxSizeOfInstructions.set (0);
+      v1.maxZones.set (1);
+      v1.maxTwilightPoints.set (0);
+      v1.maxStorage.set (0);
+      v1.maxFunctionDefs.set (0);
+      v1.maxInstructionDefs.set (0);
+      v1.maxStackElements.set (0);
+      v1.maxSizeOfInstructions.set (0);
     }
   }
 
@@ -99,30 +136,10 @@ struct maxp
   FixedVersion<>version;		/* Version of the maxp table (0.5 or 1.0),
 					 * 0x00005000u or 0x00010000u. */
   HBUINT16	numGlyphs;		/* The number of glyphs in the font. */
-
-  struct
-  {
-    HBUINT16 maxPoints;             /* Maximum points in a non-composite glyph. */
-    HBUINT16 maxContours;           /* Maximum contours in a non-composite glyph. */
-    HBUINT16 maxCompositePoints;    /* Maximum points in a composite glyph. */
-    HBUINT16 maxCompositeContours;  /* Maximum contours in a composite glyph. */
-    HBUINT16 maxZones;              /* 1 if instructions do not use the twilight zone (Z0),
-                                       or 2 if instructions do use Z0; should be set to 2 in
-                                       most cases. */
-    HBUINT16 maxTwilightPoints;     /* Maximum points used in Z0. */
-    HBUINT16 maxStorage;            /* Number of Storage Area locations. */
-    HBUINT16 maxFunctionDefs;       /* Number of FDEFs, equal to the highest function number + 1. */
-    HBUINT16 maxInstructionDefs;    /* Number of IDEFs. */
-    HBUINT16 maxStackElements;      /* Maximum stack depth. (This includes Font and CVT
-                                       Programs, as well as the instructions for each glyph.) */
-    HBUINT16 maxSizeOfInstructions; /* Maximum byte count for glyph instructions. */
-    HBUINT16 maxComponentElements;  /* Maximum number of components referenced at
-                                       "top level" for any composite glyph. */
-    HBUINT16 maxComponentDepth;     /* Maximum levels of recursion; 1 for simple components. */
-  } version_1_data;
+/*maxpV1Tail v1Tail; */
 
   public:
-  DEFINE_SIZE_MIN (6);
+  DEFINE_SIZE_STATIC (6);
 };
 
 
commit f14d1b64c2d148ffdec95c17adbee3f185d5d436
Author: Garret Rieger <grieger at google.com>
Date:   Tue Feb 27 13:49:00 2018 -0800

    [subset] when dropping hints, clear hint related fields in maxp.

diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh
index 12929229..ea6b4f04 100644
--- a/src/hb-ot-maxp-table.hh
+++ b/src/hb-ot-maxp-table.hh
@@ -57,7 +57,7 @@ struct maxp
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
-		  likely (version.major == 1 ||
+		  likely ((version.major == 1 && c->check_range (this, sizeof (maxp))) ||
 			  (version.major == 0 && version.minor == 0x5000u)));
   }
 
@@ -73,19 +73,56 @@ struct maxp
     OT::maxp *maxp_prime = (OT::maxp *) hb_blob_get_data (maxp_prime_blob, nullptr);
 
     maxp_prime->set_num_glyphs (plan->gids_to_retain_sorted.len);
+    if (plan->drop_hints)
+      drop_hint_fields (plan, maxp_prime);
 
     bool result = hb_subset_plan_add_table(plan, HB_OT_TAG_maxp, maxp_prime_blob);
     hb_blob_destroy (maxp_prime_blob);
     return result;
   }
 
-  /* We only implement version 0.5 as none of the extra fields in version 1.0 are useful. */
+  static inline void drop_hint_fields (hb_subset_plan_t *plan, OT::maxp *maxp_prime)
+  {
+    if (maxp_prime->version.major == 1)
+    {
+      maxp_prime->version_1_data.maxZones.set (1);
+      maxp_prime->version_1_data.maxTwilightPoints.set (0);
+      maxp_prime->version_1_data.maxStorage.set (0);
+      maxp_prime->version_1_data.maxFunctionDefs.set (0);
+      maxp_prime->version_1_data.maxInstructionDefs.set (0);
+      maxp_prime->version_1_data.maxStackElements.set (0);
+      maxp_prime->version_1_data.maxSizeOfInstructions.set (0);
+    }
+  }
+
   protected:
   FixedVersion<>version;		/* Version of the maxp table (0.5 or 1.0),
 					 * 0x00005000u or 0x00010000u. */
   HBUINT16	numGlyphs;		/* The number of glyphs in the font. */
+
+  struct
+  {
+    HBUINT16 maxPoints;             /* Maximum points in a non-composite glyph. */
+    HBUINT16 maxContours;           /* Maximum contours in a non-composite glyph. */
+    HBUINT16 maxCompositePoints;    /* Maximum points in a composite glyph. */
+    HBUINT16 maxCompositeContours;  /* Maximum contours in a composite glyph. */
+    HBUINT16 maxZones;              /* 1 if instructions do not use the twilight zone (Z0),
+                                       or 2 if instructions do use Z0; should be set to 2 in
+                                       most cases. */
+    HBUINT16 maxTwilightPoints;     /* Maximum points used in Z0. */
+    HBUINT16 maxStorage;            /* Number of Storage Area locations. */
+    HBUINT16 maxFunctionDefs;       /* Number of FDEFs, equal to the highest function number + 1. */
+    HBUINT16 maxInstructionDefs;    /* Number of IDEFs. */
+    HBUINT16 maxStackElements;      /* Maximum stack depth. (This includes Font and CVT
+                                       Programs, as well as the instructions for each glyph.) */
+    HBUINT16 maxSizeOfInstructions; /* Maximum byte count for glyph instructions. */
+    HBUINT16 maxComponentElements;  /* Maximum number of components referenced at
+                                       "top level" for any composite glyph. */
+    HBUINT16 maxComponentDepth;     /* Maximum levels of recursion; 1 for simple components. */
+  } version_1_data;
+
   public:
-  DEFINE_SIZE_STATIC (6);
+  DEFINE_SIZE_MIN (6);
 };
 
 
diff --git a/test/api/test-subset-glyf.c b/test/api/test-subset-glyf.c
index f5fdf32d..df343220 100644
--- a/test/api/test-subset-glyf.c
+++ b/test/api/test-subset-glyf.c
@@ -31,14 +31,30 @@
 
 /* Unit tests for hb-subset-glyf.h */
 
-static void check_maxp_num_glyphs (hb_face_t *face, uint16_t expected_num_glyphs)
+static void check_maxp_field (uint8_t *raw_maxp, unsigned int offset, uint16_t expected_value)
+{
+  uint16_t actual_value = (raw_maxp[offset] << 8) + raw_maxp[offset + 1];
+  g_assert_cmpuint(expected_value, ==, actual_value);
+}
+
+static void check_maxp_num_glyphs (hb_face_t *face, uint16_t expected_num_glyphs, bool hints)
 {
   hb_blob_t *maxp_blob = hb_face_reference_table (face, HB_TAG ('m','a','x', 'p'));
 
   unsigned int maxp_len;
   uint8_t *raw_maxp = (uint8_t *) hb_blob_get_data(maxp_blob, &maxp_len);
-  uint16_t num_glyphs = (raw_maxp[4] << 8) + raw_maxp[5];
-  g_assert_cmpuint(expected_num_glyphs, ==, num_glyphs);
+
+  check_maxp_field (raw_maxp, 4, expected_num_glyphs); // numGlyphs
+  if (!hints)
+  {
+    check_maxp_field (raw_maxp, 14, 1); // maxZones
+    check_maxp_field (raw_maxp, 16, 0); // maxTwilightPoints
+    check_maxp_field (raw_maxp, 18, 0); // maxStorage
+    check_maxp_field (raw_maxp, 20, 0); // maxFunctionDefs
+    check_maxp_field (raw_maxp, 22, 0); // maxInstructionDefs
+    check_maxp_field (raw_maxp, 24, 0); // maxStackElements
+    check_maxp_field (raw_maxp, 26, 0); // maxSizeOfInstructions
+  }
 
   hb_blob_destroy (maxp_blob);
 }
@@ -57,7 +73,7 @@ test_subset_glyf (void)
 
   hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f'));
   hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a'));
-  check_maxp_num_glyphs(face_abc_subset, 3);
+  check_maxp_num_glyphs(face_abc_subset, 3, true);
 
   hb_face_destroy (face_abc_subset);
   hb_face_destroy (face_abc);
@@ -77,7 +93,7 @@ test_subset_glyf_with_components (void)
 
   hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('g','l','y','f'));
   hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('l','o','c', 'a'));
-  check_maxp_num_glyphs(face_generated_subset, 4);
+  check_maxp_num_glyphs(face_generated_subset, 4, true);
 
   hb_face_destroy (face_generated_subset);
   hb_face_destroy (face_subset);
@@ -98,7 +114,7 @@ test_subset_glyf_noop (void)
 
   hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('g','l','y','f'));
   hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('l','o','c', 'a'));
-  check_maxp_num_glyphs(face_abc_subset, 4);
+  check_maxp_num_glyphs(face_abc_subset, 4, true);
 
   hb_face_destroy (face_abc_subset);
   hb_face_destroy (face_abc);
@@ -120,7 +136,7 @@ test_subset_glyf_strip_hints (void)
 
   hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a'));
   hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f'));
-  check_maxp_num_glyphs(face_abc_subset, 3);
+  check_maxp_num_glyphs(face_abc_subset, 3, false);
 
   hb_face_destroy (face_abc_subset);
   hb_face_destroy (face_abc);
commit 101850f9e6b9e0932fe1dd4169f88d6764c669c1
Merge: 5967eaba f110c0c8
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Tue Feb 27 20:15:54 2018 +0330

    Merge with master

diff --cc NEWS
index 992c64bc,9015c4ad..8ff1fe61
--- a/NEWS
+++ b/NEWS
@@@ -1,8 -1,377 +1,377 @@@
- Overview of changes leading to 1.2.8
- Not yet released
++=======
+ Overview of changes leading to 1.7.5
+ Tuesday, January 30, 2018
  ====================================
- - Implemented 'CPAL' table in hb-ot-color.
+ 
+ - Separate Khmer shaper from Indic.
+ - First stab at AAT morx. Not hooked up.
+ - Misc bug fixes.
+ 
+ 
+ Overview of changes leading to 1.7.4
+ Wednesday, December 20, 2017
+ ====================================
+ 
+ - Fix collect_glyphs() regression caused by hb_set_t changes.
+ 
+ 
+ Overview of changes leading to 1.7.3
+ Monday, December 18, 2017
+ ====================================
+ 
+ - hb_set_t performance tuning and optimizations.
+ - Speed up collect_glyphs() and reject garbage data.
+ - In hb_coretext_font_create() set font point-size (ptem).
+ - Misc fixes.
+ 
+ 
+ Overview of changes leading to 1.7.2
+ Monday, December 4, 2017
+ ====================================
+ 
+ - Optimize hb_set_add_range().
+ - Misc fixes.
+ - New API:
+ hb_coretext_font_create()
+ 
+ 
+ Overview of changes leading to 1.7.1
+ Tuesday, November 14, 2017
+ ====================================
+ 
+ - Fix atexit object destruction regression.
+ - Fix minor integer-overflow.
+ 
+ 
+ Overview of changes leading to 1.7.0
+ Monday, November 13, 2017
+ ====================================
+ 
+ - Minor Indic fixes.
+ - Implement kerning and glyph names in hb-ot-font.
+ - Various DSO optimization re .data and .bss sizes.
+ - Make C++11 optional; build fixes.
+ - Mark all other backends "unsafe-to-break".
+ - Graphite fix.
+ 
+ 
+ Overview of changes leading to 1.6.3
+ Thursday, October 26th, 2017
+ ====================================
+ 
+ - Fix hb_set_t some more.  Should be solid now.
+ - Implement get_glyph_name() for hb-ot-font.
+ - Misc fixes.
+ 
+ 
+ Overview of changes leading to 1.6.2
+ Monday, October 23nd, 2017
+ ====================================
+ 
+ - Yesterday's release had a bad crasher; don't use it.  That's what
+   happens when one works on Sunday...
+   https://github.com/harfbuzz/harfbuzz/issues/578
+ - Build fixes for FreeBSD and Chrome Android.
+ 
+ 
+ Overview of changes leading to 1.6.1
+ Sunday, October 22nd, 2017
+ ====================================
+ 
+ - Don't skip over COMBINING GRAPHEME JOINER when ligating, etc.
+   To be refined: https://github.com/harfbuzz/harfbuzz/issues/554
+ - Faster hb_set_t implementation.
+ - Don't use deprecated ICU API.
+ - Fix undefined-behavior in Myanmar shaper, introduced in 1.6.0
+ - Deprecated API:
+   hb_set_invert()
+ 
+ 
+ Overview of changes leading to 1.6.0
+ Friday, October the 13th, 2017
+ ====================================
+ 
+ - Update to Unicode 10.
+ 
+ - Various Indic and Universal Shaping Engine fixes as a result of
+   HarfBuzz Hackfest with Jonathan Kew at Web Engines Hackfest at
+   the Igalia offices in A Coruña, Spain.  Thanks Igalia for having
+   us!
+ 
+ - Implement Unicode Arabic Mark Ordering Algorithm UTR#53.
+ 
+ - Implement optical sizing / tracking in CoreText backend, using
+   new API hb_font_set_ptem().
+ 
+ - Allow notifying hb_font_t that underlying FT_Face changed sizing,
+   using new API hb_ft_font_changed().
+ 
+ - More Graphite backend RTL fixes.
+ 
+ - Fix caching of variable font shaping plans.
+ 
+ - hb-view / hb-shape now accept following new arguments:
+ 
+   o --unicodes: takes a list of hex numbers that represent Unicode
+     codepoints.
+ 
+ New API:
+ +hb_face_get_table_tags()
+ +hb_font_set_ptem()
+ +hb_font_get_ptem()
+ +hb_ft_font_changed()
+ 
+ 
+ Overview of changes leading to 1.5.1
+ Tuesday, September 5, 2017
+ ====================================
+ 
+ - Fix "unsafe-to-break" in fallback shaping and other corner cases.
+   All our tests pass with --verify now, meaning unsafe-to-break API
+   works as expected.
+ - Add --unicodes to hb-view / hb-shape.
+ - [indic] Treat Consonant_With_Stacker as consonant.  This will need
+   further tweaking.
+ - hb_buffer_diff() tweaks.
+ 
+ 
+ Overview of changes leading to 1.5.0
+ Wednesday, August 23, 2017
+ ====================================
+ 
+ - Misc new API, for appending a buffer to another, and for comparing
+   contents of two buffers for types of differences.
+ 
+ - New "unsafe-to-break" API.  Can be used to speed up reshaping
+   in line-breaking situations.  Essentially, after shaping, it returns
+   positions in the input string (some of the cluster boundaries) that
+   are "safe to break" in that if the text is segmented at that position
+   and two sides reshaped and concatenated, the shaping result is
+   exactly the same as shaping the text in one piece.
+ 
+   hb-view and hb-shape and hb-shape now take --verify, which verifies
+   the above property.
+ 
+   Some corner cases of the implementation are still not quite working.
+   Those will be fixed in subsequent releases.
+ 
+ - New API:
+ 
+ hb_buffer_append()
+ 
+ hb_glyph_flags_t
+ HB_GLYPH_FLAG_UNSAFE_TO_BREAK
+ HB_GLYPH_FLAG_DEFINED
+ hb_glyph_info_get_glyph_flags()
+ 
+ HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS
+ 
+ hb_buffer_diff_flags_t
+ HB_BUFFER_DIFF_FLAG_EQUAL
+ HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH
+ HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH
+ HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT
+ HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
+ HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH
+ HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH
+ HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH
+ HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH
+ hb_buffer_diff
+ 
+ 
+ Overview of changes leading to 1.4.8
+ Tuesday, August 8, 2017
+ ====================================
+ 
+ - Major fix to avar table handling.
+ - Rename hb-shape --show-message to --trace.
+ - Build fixes.
+ 
+ 
+ Overview of changes leading to 1.4.7
+ Tuesday, July 18, 2017
+ ====================================
+ 
+ - Multiple Indic, Tibetan, and Cham fixes.
+ - CoreText: Allow disabling kerning.
+ - Adjust Arabic feature order again.
+ - Misc build fixes.
+ 
+ 
+ Overview of changes leading to 1.4.6
+ Sunday, April 23, 2017
+ ====================================
+ 
+ - Graphite2: Fix RTL positioning issue.
+ - Backlist GDEF of more versions of Padauk and Tahoma.
+ - New, experimental, cmake alternative build system.
+ 
+ 
+ Overview of changes leading to 1.4.5
+ Friday, March 10, 2017
+ ====================================
+ 
+ - Revert "Fix Context lookup application when moving back after a glyph..."
+   This introduced memory access problems.  To be fixed properly soon.
+ 
+ 
+ Overview of changes leading to 1.4.4
+ Sunday, March 5, 2017
+ ====================================
+ 
+ - Fix Context lookup application when moving back after a glyph deletion.
+ - Fix buffer-overrun in Bengali.
+ 
+ 
+ Overview of changes leading to 1.4.3
+ Saturday, February 25, 2017
+ ====================================
+ 
+ - Route Adlam script to Arabic shaper.
+ - Misc fixes.
+ - New API:
+   hb_font_set_face()
+ - Deprecate API:
+   hb_graphite2_font_get_gr_font()
+ 
+ 
+ Overview of changes leading to 1.4.2
+ Monday, January 23, 2017
+ ====================================
+ 
+ - Implement OpenType Font Variation tables avar/fvar/HVAR/VVAR.
+ - hb-shape and hb-view now accept --variations.
+ - New API:
+ 
+ hb_variation_t
+ hb_variation_from_string()
+ hb_variation_to_string()
+ 
+ hb_font_set_variations()
+ hb_font_set_var_coords_design()
+ hb_font_get_var_coords_normalized()
+ 
+ hb-ot-var.h:
+ hb_ot_var_axis_t
+ hb_ot_var_has_data()
+ hb_ot_var_get_axis_count()
+ hb_ot_var_get_axes()
+ hb_ot_var_find_axis()
+ hb_ot_var_normalize_variations()
+ hb_ot_var_normalize_coords()
+ 
+ - MVAR to be implemented later.  Access to named instances to be
+   implemented later as well.
+ 
+ - Misc fixes.
+ 
+ 
+ Overview of changes leading to 1.4.1
+ Thursday, January 5, 2017
+ ====================================
+ 
+ - Always build and use UCDN for Unicode data by default.
+   Reduces dependence on version of Unicode data in glib,
+   specially in the Windows bundles we are shipping, which
+   have very old glib.
+ 
+ 
+ Overview of changes leading to 1.4.0
+ Thursday, January 5, 2017
+ ====================================
+ 
+ - Merged "OpenType GX" branch which adds core of support for
+   OpenType 1.8 Font Variations.  To that extent, the relevant
+   new API is:
+ 
+ New API:
+ hb_font_set_var_coords_normalized()
+ 
+   with supporting API:
+ 
+ New API:
+ HB_OT_LAYOUT_NO_VARIATIONS_INDEX
+ hb_ot_layout_table_find_feature_variations()
+ hb_ot_layout_feature_with_variations_get_lookups()
+ hb_shape_plan_create2()
+ hb_shape_plan_create_cached2()
+ 
+   Currently variations in GSUB/GPOS/GDEF are fully supported,
+   and no other tables are supported.  In particular, fvar/avar
+   are NOT supported, hence the hb_font_set_var_coords_normalized()
+   taking normalized coordinates.  API to take design coordinates
+   will be added in the future.
+ 
+   HVAR/VVAR/MVAR support will also be added to hb-ot-font in the
+   future.
+ 
+ - Fix regression in GDEF glyph class processing.
+ - Add decompositions for Chakma, Limbu, and Balinese in USE shaper.
+ - Misc fixes.
+ 
+ 
+ Overview of changes leading to 1.3.4
+ Monday, December 5, 2016
+ ====================================
+ 
+ - Fix vertical glyph origin in hb-ot-font.
+ - Implement CBDT/CBLC color font glyph extents in hb-ot-font.
+ 
+ 
+ Overview of changes leading to 1.3.3
+ Wednesday, September 28, 2016
+ ====================================
+ 
+ - Implement parsing of OpenType MATH table.
+ New API:
+ HB_OT_TAG_MATH
+ HB_OT_MATH_SCRIPT
+ hb_ot_math_constant_t
+ hb_ot_math_kern_t
+ hb_ot_math_glyph_variant_t
+ hb_ot_math_glyph_part_flags_t
+ hb_ot_math_glyph_part_t
+ hb_ot_math_has_data
+ hb_ot_math_get_constant
+ hb_ot_math_get_glyph_italics_correction
+ hb_ot_math_get_glyph_top_accent_attachment
+ hb_ot_math_get_glyph_kerning
+ hb_ot_math_is_glyph_extended_shape
+ hb_ot_math_get_glyph_variants
+ hb_ot_math_get_min_connector_overlap
+ hb_ot_math_get_glyph_assembly
+ 
+ 
+ Overview of changes leading to 1.3.2
+ Wednesday, September 27, 2016
+ ====================================
+ 
+ - Fix build of hb-coretext on older OS X versions.
+ 
+ 
+ Overview of changes leading to 1.3.1
+ Wednesday, September 7, 2016
+ ====================================
+ 
+ - Blacklist bad GDEF of more fonts (Padauk).
+ - More CoreText backend crash fixes with OS X 10.9.5.
+ - Misc fixes.
+ 
+ 
+ Overview of changes leading to 1.3.0
+ Thursday, July 21, 2016
+ ====================================
+ 
+ - Update to Unicode 9.0.0
+ - Move Javanese from Indic shaper to Universal Shaping Engine.
+ - Allow MultipleSubst to delete a glyph (matching Windows engine).
+ - Update Universal Shaping Engine to latest draft from Microsoft.
+ - DirectWrite backend improvements.  Note: this backend is for testing ONLY.
+ - CoreText backend improvements with unreachable fonts.
+ - Implement symbol fonts (cmap 3.0.0) in hb-ft and hb-ot-font.
+ - Blacklist bad GDEF of more fonts (Tahoma & others).
+ - Misc fixes.
  
 -
  Overview of changes leading to 1.2.7
  Monday, May 2, 2016
  ====================================
diff --cc src/Makefile.am
index 49e349bf,2871f30f..2dcaa7fb
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@@ -307,14 -354,36 +354,37 @@@ dist_check_SCRIPTS = 
  	check-static-inits.sh \
  	check-symbols.sh \
  	$(NULL)
+ TESTS += $(dist_check_SCRIPTS)
+ 
+ if !WITH_LIBSTDCXX
+ dist_check_SCRIPTS += \
+ 	check-libstdc++.sh \
+ 	$(NULL)
+ endif
  
- check_PROGRAMS = \
- 	test-ot-tag \
+ check_PROGRAMS += \
+ 	dump-indic-data \
+ 	dump-khmer-data \
+ 	dump-myanmar-data \
+ 	dump-use-data \
  	$(NULL)
- test_ot_color_SOURCES = hb-ot-color.cc
- test_ot_color_CPPFLAGS = $(HBCFLAGS) -DMAIN
- test_ot_color_LDADD = libharfbuzz.la $(HBLIBS)
++
+ dump_indic_data_SOURCES = dump-indic-data.cc hb-ot-shape-complex-indic-table.cc
+ dump_indic_data_CPPFLAGS = $(HBCFLAGS)
+ dump_indic_data_LDADD = libharfbuzz.la $(HBLIBS)
+ dump_khmer_data_SOURCES = dump-khmer-data.cc hb-ot-shape-complex-indic-table.cc
+ dump_khmer_data_CPPFLAGS = $(HBCFLAGS)
+ dump_khmer_data_LDADD = libharfbuzz.la $(HBLIBS)
+ dump_myanmar_data_SOURCES = dump-myanmar-data.cc hb-ot-shape-complex-indic-table.cc
+ dump_myanmar_data_CPPFLAGS = $(HBCFLAGS)
+ dump_myanmar_data_LDADD = libharfbuzz.la $(HBLIBS)
+ dump_use_data_SOURCES = dump-use-data.cc hb-ot-shape-complex-use-table.cc
+ dump_use_data_CPPFLAGS = $(HBCFLAGS)
+ dump_use_data_LDADD = libharfbuzz.la $(HBLIBS)
+ 
+ check_PROGRAMS += test-ot-tag test-unicode-ranges
+ TESTS += test-ot-tag test-unicode-ranges
+ 
  test_ot_tag_SOURCES = hb-ot-tag.cc
  test_ot_tag_CPPFLAGS = $(HBCFLAGS) -DMAIN
  test_ot_tag_LDADD = libharfbuzz.la $(HBLIBS)
diff --cc src/Makefile.sources
index a40de858,b45cd927..fc3383b8
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@@ -78,8 -96,10 +96,12 @@@ HB_OT_sources = 
  	hb-ot-layout-gsub-table.hh \
  	hb-ot-layout-jstf-table.hh \
  	hb-ot-layout-private.hh \
++	hb-ot-color.cc \
++	hb-ot-cpal-table.hh \
  	hb-ot-map.cc \
  	hb-ot-map-private.hh \
+ 	hb-ot-math.cc \
+ 	hb-ot-math-table.hh \
  	hb-ot-shape.cc \
  	hb-ot-shape-complex-arabic.cc \
  	hb-ot-shape-complex-arabic-fallback.hh \
@@@ -111,11 -149,13 +151,14 @@@ HB_OT_RAGEL_sources = 
  
  HB_OT_headers = \
  	hb-ot.h \
 +	hb-ot-color.h \
  	hb-ot-font.h \
  	hb-ot-layout.h \
+ 	hb-ot-math.h \
+ 	hb-ot-base.h \
  	hb-ot-shape.h \
  	hb-ot-tag.h \
+ 	hb-ot-var.h \
  	$(NULL)
  
  # Optional Sources and Headers with external deps
diff --cc src/hb-ot-layout-private.hh
index 30c8717a,fdaa41ee..92aa122f
--- a/src/hb-ot-layout-private.hh
+++ b/src/hb-ot-layout-private.hh
@@@ -124,7 -126,16 +126,17 @@@ namespace OT 
    struct GDEF;
    struct GSUB;
    struct GPOS;
 +  struct CPAL;
+   struct MATH;
+   struct fvar;
+   struct avar;
+ }
+ 
+ namespace AAT {
+   struct ankr;
+   struct kerx;
+   struct morx;
+   struct trak;
  }
  
  struct hb_ot_layout_lookup_accelerator_t
@@@ -158,8 -168,17 +170,18 @@@ struct hb_ot_layout_
    const struct OT::GDEF *gdef;
    const struct OT::GSUB *gsub;
    const struct OT::GPOS *gpos;
 +  const struct OT::CPAL *cpal;
  
+   /* TODO Move the following out of this struct. */
+   OT::hb_lazy_table_loader_t<struct OT::BASE> base;
+   OT::hb_lazy_table_loader_t<struct OT::MATH> math;
+   OT::hb_lazy_table_loader_t<struct OT::fvar> fvar;
+   OT::hb_lazy_table_loader_t<struct OT::avar> avar;
+   OT::hb_lazy_table_loader_t<struct AAT::ankr> ankr;
+   OT::hb_lazy_table_loader_t<struct AAT::kerx> kerx;
+   OT::hb_lazy_table_loader_t<struct AAT::morx> morx;
+   OT::hb_lazy_table_loader_t<struct AAT::trak> trak;
+ 
    unsigned int gsub_lookup_count;
    unsigned int gpos_lookup_count;
  
diff --cc src/hb-ot-layout.cc
index 73f993be,42802e2b..e099fd05
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@@ -30,12 -30,13 +30,13 @@@
  
  #include "hb-open-type-private.hh"
  #include "hb-ot-layout-private.hh"
--
- #include "hb-ot-cpal-table.hh"
+ #include "hb-ot-layout-base-table.hh"
  #include "hb-ot-layout-gdef-table.hh"
  #include "hb-ot-layout-gsub-table.hh"
  #include "hb-ot-layout-gpos-table.hh"
- #include "hb-ot-layout-jstf-table.hh"
+ #include "hb-ot-layout-jstf-table.hh" // Just so we compile it; unused otherwise.
+ #include "hb-ot-name-table.hh" // Just so we compile it; unused otherwise.
++#include "hb-ot-cpal-table.hh"
  
  #include "hb-ot-map-private.hh"
  
@@@ -50,20 -51,25 +51,26 @@@ _hb_ot_layout_create (hb_face_t *face
  {
    hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
    if (unlikely (!layout))
-     return NULL;
+     return nullptr;
  
-   layout->gdef_blob = OT::Sanitizer<OT::GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF));
+   layout->gdef_blob = OT::Sanitizer<OT::GDEF>().sanitize (face->reference_table (HB_OT_TAG_GDEF));
    layout->gdef = OT::Sanitizer<OT::GDEF>::lock_instance (layout->gdef_blob);
  
-   layout->gsub_blob = OT::Sanitizer<OT::GSUB>::sanitize (face->reference_table (HB_OT_TAG_GSUB));
+   layout->gsub_blob = OT::Sanitizer<OT::GSUB>().sanitize (face->reference_table (HB_OT_TAG_GSUB));
    layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob);
  
-   layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
+   layout->gpos_blob = OT::Sanitizer<OT::GPOS>().sanitize (face->reference_table (HB_OT_TAG_GPOS));
    layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
  
-   // The CPAL table is rarely accessed, so we only try to load it in _get_cpal.
-   layout->cpal_blob = NULL;
-   layout->cpal = NULL;
+   layout->math.init (face);
+   layout->base.init (face);
+   layout->fvar.init (face);
+   layout->avar.init (face);
+   layout->ankr.init (face);
+   layout->kerx.init (face);
+   layout->morx.init (face);
+   layout->trak.init (face);
++  layout->cpal.init (face);
  
    {
      /*
@@@ -136,7 -216,14 +217,15 @@@ _hb_ot_layout_destroy (hb_ot_layout_t *
    hb_blob_destroy (layout->gsub_blob);
    hb_blob_destroy (layout->gpos_blob);
  
-   if (layout->cpal_blob) hb_blob_destroy (layout->cpal_blob);
+   layout->math.fini ();
+   layout->base.fini ();
+   layout->fvar.fini ();
+   layout->avar.fini ();
+   layout->ankr.fini ();
+   layout->kerx.fini ();
+   layout->morx.fini ();
+   layout->trak.fini ();
++  layout->cpal.fini ();
  
    free (layout);
  }
diff --cc src/hb-ot.h
index 0c0cf8d9,272208e3..d1979b81
--- a/src/hb-ot.h
+++ b/src/hb-ot.h
@@@ -30,11 -30,13 +30,14 @@@
  
  #include "hb.h"
  
 +#include "hb-ot-color.h"
  #include "hb-ot-font.h"
  #include "hb-ot-layout.h"
+ #include "hb-ot-math.h"
+ #include "hb-ot-base.h"
  #include "hb-ot-tag.h"
  #include "hb-ot-shape.h"
+ #include "hb-ot-var.h"
  
  HB_BEGIN_DECLS
  
diff --cc test/api/Makefile.am
index 895d1543,e2e6166c..a6ebc57a
--- a/test/api/Makefile.am
+++ b/test/api/Makefile.am
@@@ -43,11 -59,20 +59,21 @@@ endi
  
  
  if HAVE_OT
+ 
  TEST_PROGS += \
 +	test-ot-color \
  	test-ot-tag \
  	$(NULL)
- endif
+ 
+ if HAVE_FREETYPE
+ TEST_PROGS += \
+ 	test-ot-math \
+ 	$(NULL)
+ test_ot_math_LDADD = $(LDADD) $(FREETYPE_LIBS)
+ test_ot_math_CPPFLAGS = $(AM_CPPFLAGS) $(FREETYPE_CFLAGS)
+ endif # HAVE_FREETYPE
+ 
+ endif # HAVE_OT
  
  # Tests for header compilation
  TEST_PROGS += \
commit 5967eaba728ca3e4f5026142c25d455fa3a59764
Author: Sascha Brawer <sascha at brawer.ch>
Date:   Fri Jun 24 16:42:27 2016 +0200

    [CPAL] Return 0xFFFF as name id for unnamed palettes
    
    The name id 0 is used as Copyright notice. It's quite unlikely that a
    font supplies a color palette with the exact same name as the font's
    copyright notice, but the API should not prevent this.
    
    Also, try to fix a problem with GObject introspection, where the
    auto-generated Python bindings could not return palette colors.

diff --git a/src/hb-ot-color.cc b/src/hb-ot-color.cc
index 58aa412d..93d5c001 100644
--- a/src/hb-ot-color.cc
+++ b/src/hb-ot-color.cc
@@ -82,7 +82,8 @@ hb_ot_color_get_palette_count (hb_face_t *face)
  * Returns: an identifier within @face's `name` table.
  * If the requested palette has no name, or if @face has no colors,
  * or if @palette is not between 0 and hb_ot_color_get_palette_count(),
- * the result is zero.
+ * the result is 0xFFFF. The implementation does not check whether
+ * the returned palette name id is actually in @face's `name` table.
  *
  * Since: 1.2.8
  */
@@ -92,22 +93,20 @@ hb_ot_color_get_palette_name_id (hb_face_t *face, unsigned int palette)
   const OT::CPAL& cpal = _get_cpal(face);
   if (unlikely (&cpal == &OT::Null(OT::CPAL) || cpal.version == 0 ||
 		palette >= cpal.numPalettes)) {
-    return 0;
+    return 0xFFFF;
   }
 
   const OT::CPALV1Tail& cpal1 = OT::StructAfter<OT::CPALV1Tail>(cpal);
   if (unlikely (&cpal1 == &OT::Null(OT::CPALV1Tail) ||
 		cpal1.paletteLabel.is_null())) {
-    return 0;
+    return 0xFFFF;
   }
 
   const OT::USHORT* name_ids = &cpal1.paletteLabel (&cpal);
   const OT::USHORT name_id = name_ids [palette];
 
   // According to the OpenType CPAL specification, 0xFFFF means name-less.
-  // We map 0xFFFF to 0 because zero is far more commonly used to indicate
-  // "no value".
-  return likely (name_id != 0xffff) ? name_id : 0;
+  return name_id;
 }
 
 
@@ -152,7 +151,7 @@ hb_ot_color_get_palette_flags (hb_face_t *face, unsigned int palette)
  * @color_count:  (inout) (optional): on input, how many colors
  *                can be maximally stored into the @colors array;
  *                on output, how many colors were actually stored.
- * @colors: (out caller-allocates) (array length=color_count) (optional):
+ * @colors: (array length=color_count) (optional):
  *                an array of #hb_ot_color_t records. After calling
  *                this function, @colors will be filled with
  *                the palette colors. If @colors is NULL, the function
diff --git a/test/api/test-ot-color.c b/test/api/test-ot-color.c
index 7378a59e..93589b16 100644
--- a/test/api/test-ot-color.c
+++ b/test/api/test-ot-color.c
@@ -135,19 +135,19 @@ static void
 test_hb_ot_color_get_palette_name_id_empty (void)
 {
   /* numPalettes=0, so all calls are for out-of-bounds palette indices */
-  g_assert_cmpint (hb_ot_color_get_palette_name_id (hb_face_get_empty(), 0), ==, 0);
-  g_assert_cmpint (hb_ot_color_get_palette_name_id (hb_face_get_empty(), 1), ==, 0);
+  g_assert_cmpint (hb_ot_color_get_palette_name_id (hb_face_get_empty(), 0), ==, 0xffff);
+  g_assert_cmpint (hb_ot_color_get_palette_name_id (hb_face_get_empty(), 1), ==, 0xffff);
 }
 
 
 static void
 test_hb_ot_color_get_palette_name_id_v0 (void)
 {
-  g_assert_cmpint (hb_ot_color_get_palette_name_id (cpal_v0, 0), ==, 0);
-  g_assert_cmpint (hb_ot_color_get_palette_name_id (cpal_v0, 1), ==, 0);
+  g_assert_cmpint (hb_ot_color_get_palette_name_id (cpal_v0, 0), ==, 0xffff);
+  g_assert_cmpint (hb_ot_color_get_palette_name_id (cpal_v0, 1), ==, 0xffff);
 
   /* numPalettes=2, so palette #2 is out of bounds */
-  g_assert_cmpint (hb_ot_color_get_palette_name_id (cpal_v0, 2), ==, 0);
+  g_assert_cmpint (hb_ot_color_get_palette_name_id (cpal_v0, 2), ==, 0xffff);
 }
 
 
@@ -155,11 +155,11 @@ static void
 test_hb_ot_color_get_palette_name_id_v1 (void)
 {
   g_assert_cmpint (hb_ot_color_get_palette_name_id (cpal_v1, 0), ==, 257);
-  g_assert_cmpint (hb_ot_color_get_palette_name_id (cpal_v1, 1), ==, 0);
+  g_assert_cmpint (hb_ot_color_get_palette_name_id (cpal_v1, 1), ==, 0xffff);
   g_assert_cmpint (hb_ot_color_get_palette_name_id (cpal_v1, 2), ==, 258);
 
   /* numPalettes=3, so palette #3 is out of bounds */
-  g_assert_cmpint (hb_ot_color_get_palette_name_id (cpal_v1, 3), ==, 0);
+  g_assert_cmpint (hb_ot_color_get_palette_name_id (cpal_v1, 3), ==, 0xffff);
 }
 
 static void
commit d34d3ac985a6c8c848ae49635b648a72e0c8f30d
Author: Sascha Brawer <sascha at brawer.ch>
Date:   Mon Apr 25 18:20:57 2016 +0200

    Support CPAL table

diff --git a/NEWS b/NEWS
index e62b1989..992c64bc 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,8 @@
+Overview of changes leading to 1.2.8
+Not yet released
+====================================
+- Implemented 'CPAL' table in hb-ot-color.
+
 Overview of changes leading to 1.2.7
 Monday, May 2, 2016
 ====================================
@@ -9,7 +14,6 @@ Monday, May 2, 2016
 - Unbreak build on Windows CE.
 - Make 'glyf' table loading lazy in hb-ot-font.
 
-
 Overview of changes leading to 1.2.6
 Friday, April 8, 2016
 ====================================
diff --git a/src/Makefile.am b/src/Makefile.am
index 8cfe4ac7..49e349bf 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -312,6 +312,9 @@ dist_check_SCRIPTS = \
 check_PROGRAMS = \
 	test-ot-tag \
 	$(NULL)
+test_ot_color_SOURCES = hb-ot-color.cc
+test_ot_color_CPPFLAGS = $(HBCFLAGS) -DMAIN
+test_ot_color_LDADD = libharfbuzz.la $(HBLIBS)
 test_ot_tag_SOURCES = hb-ot-tag.cc
 test_ot_tag_CPPFLAGS = $(HBCFLAGS) -DMAIN
 test_ot_tag_LDADD = libharfbuzz.la $(HBLIBS)
diff --git a/src/Makefile.sources b/src/Makefile.sources
index ac806838..a40de858 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -67,6 +67,8 @@ HB_NODIST_headers = \
 HB_FALLBACK_sources = hb-fallback-shape.cc
 
 HB_OT_sources = \
+	hb-ot-color.cc \
+	hb-ot-cpal-table.hh \
 	hb-ot-font.cc \
 	hb-ot-layout.cc \
 	hb-ot-layout-common-private.hh \
@@ -109,6 +111,7 @@ HB_OT_sources = \
 
 HB_OT_headers = \
 	hb-ot.h \
+	hb-ot-color.h \
 	hb-ot-font.h \
 	hb-ot-layout.h \
 	hb-ot-shape.h \
diff --git a/src/hb-ot-color.cc b/src/hb-ot-color.cc
new file mode 100644
index 00000000..58aa412d
--- /dev/null
+++ b/src/hb-ot-color.cc
@@ -0,0 +1,213 @@
+/*
+ * Copyright © 2016  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Sascha Brawer
+ */
+
+#include "hb-open-type-private.hh"
+#include "hb-ot-cpal-table.hh"
+#include "hb-ot.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "hb-ot-layout-private.hh"
+#include "hb-shaper-private.hh"
+
+HB_MARK_AS_FLAG_T (hb_ot_color_palette_flags_t)
+HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
+
+
+static inline const OT::CPAL&
+_get_cpal (hb_face_t *face)
+{
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
+    return OT::Null(OT::CPAL);
+
+  hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
+  if (!layout->cpal) {
+    layout->cpal_blob = OT::Sanitizer<OT::CPAL>::sanitize (face->reference_table (HB_OT_TAG_CPAL));
+    layout->cpal = OT::Sanitizer<OT::CPAL>::lock_instance (layout->cpal_blob);
+  }
+
+  return *layout->cpal;
+}
+
+
+/**
+ * hb_ot_color_get_palette_count:
+ * @face: a font face.
+ *
+ * Returns: the number of color palettes in @face, or zero if @face has
+ * no colors.
+ *
+ * Since: 1.2.8
+ */
+unsigned int
+hb_ot_color_get_palette_count (hb_face_t *face)
+{
+  const OT::CPAL& cpal = _get_cpal(face);
+  return &cpal != &OT::Null(OT::CPAL) ? cpal.numPalettes : 0;
+}
+
+
+/**
+ * hb_ot_color_get_palette_name_id:
+ * @face: a font face.
+ * @palette: the index of the color palette whose name is being requested.
+ *
+ * Retrieves the name id of a color palette. For example, a color font can
+ * have themed palettes like "Spring", "Summer", "Fall", and "Winter".
+ *
+ * Returns: an identifier within @face's `name` table.
+ * If the requested palette has no name, or if @face has no colors,
+ * or if @palette is not between 0 and hb_ot_color_get_palette_count(),
+ * the result is zero.
+ *
+ * Since: 1.2.8
+ */
+unsigned int
+hb_ot_color_get_palette_name_id (hb_face_t *face, unsigned int palette)
+{
+  const OT::CPAL& cpal = _get_cpal(face);
+  if (unlikely (&cpal == &OT::Null(OT::CPAL) || cpal.version == 0 ||
+		palette >= cpal.numPalettes)) {
+    return 0;
+  }
+
+  const OT::CPALV1Tail& cpal1 = OT::StructAfter<OT::CPALV1Tail>(cpal);
+  if (unlikely (&cpal1 == &OT::Null(OT::CPALV1Tail) ||
+		cpal1.paletteLabel.is_null())) {
+    return 0;
+  }
+
+  const OT::USHORT* name_ids = &cpal1.paletteLabel (&cpal);
+  const OT::USHORT name_id = name_ids [palette];
+
+  // According to the OpenType CPAL specification, 0xFFFF means name-less.
+  // We map 0xFFFF to 0 because zero is far more commonly used to indicate
+  // "no value".
+  return likely (name_id != 0xffff) ? name_id : 0;
+}
+
+
+/**
+ * hb_ot_color_get_palette_flags:
+ * @face: a font face
+ * @palette: the index of the color palette whose flags are being requested
+ *
+ * Returns: the flags for the requested color palette.  If @face has no colors,
+ * or if @palette is not between 0 and hb_ot_color_get_palette_count(),
+ * the result is #HB_OT_COLOR_PALETTE_FLAG_DEFAULT.
+ *
+ * Since: 1.2.8
+ */
+hb_ot_color_palette_flags_t
+hb_ot_color_get_palette_flags (hb_face_t *face, unsigned int palette)
+{
+  const OT::CPAL& cpal = _get_cpal(face);
+  if (unlikely (&cpal == &OT::Null(OT::CPAL) || cpal.version == 0 ||
+		palette >= cpal.numPalettes)) {
+    return HB_OT_COLOR_PALETTE_FLAG_DEFAULT;
+  }
+
+  const OT::CPALV1Tail& cpal1 = OT::StructAfter<OT::CPALV1Tail>(cpal);
+  if (unlikely (&cpal1 == &OT::Null(OT::CPALV1Tail) ||
+		cpal1.paletteFlags.is_null())) {
+    return HB_OT_COLOR_PALETTE_FLAG_DEFAULT;
+  }
+
+  const OT::ULONG* flags = &cpal1.paletteFlags(&cpal);
+  const uint32_t flag = static_cast<uint32_t> (flags [palette]);
+  return static_cast<hb_ot_color_palette_flags_t> (flag);
+}
+
+
+/**
+ * hb_ot_color_get_palette_colors:
+ * @face:         a font face.
+ * @palette:      the index of the color palette whose colors
+ *                are being requested.
+ * @start_offset: the index of the first color being requested.
+ * @color_count:  (inout) (optional): on input, how many colors
+ *                can be maximally stored into the @colors array;
+ *                on output, how many colors were actually stored.
+ * @colors: (out caller-allocates) (array length=color_count) (optional):
+ *                an array of #hb_ot_color_t records. After calling
+ *                this function, @colors will be filled with
+ *                the palette colors. If @colors is NULL, the function
+ *                will just return the number of total colors
+ *                without storing any actual colors; this can be used
+ *                for allocating a buffer of suitable size before calling
+ *                hb_ot_color_get_palette_colors() a second time.
+ *
+ * Retrieves the colors in a color palette.
+ *
+ * Returns: the total number of colors in the palette. All palettes in
+ * a font have the same number of colors. If @face has no colors, or if
+ * @palette is not between 0 and hb_ot_color_get_palette_count(),
+ * the result is zero.
+ *
+ * Since: 1.2.8
+ */
+unsigned int
+hb_ot_color_get_palette_colors (hb_face_t       *face,
+				unsigned int     palette, /* default=0 */
+				unsigned int     start_offset,
+				unsigned int    *color_count /* IN/OUT */,
+				hb_ot_color_t   *colors /* OUT */)
+{
+  const OT::CPAL& cpal = _get_cpal(face);
+  if (unlikely (&cpal == &OT::Null(OT::CPAL) ||
+		palette >= cpal.numPalettes))
+  {
+    if (color_count) *color_count = 0;
+    return 0;
+  }
+
+  const OT::ColorRecord* crec = &cpal.offsetFirstColorRecord (&cpal);
+  if (unlikely (crec == &OT::Null(OT::ColorRecord)))
+  {
+    if (color_count) *color_count = 0;
+    return 0;
+  }
+  crec += cpal.colorRecordIndices[palette];
+
+  unsigned int num_results = 0;
+  if (likely (color_count && colors))
+  {
+    for (unsigned int i = start_offset;
+	 i < cpal.numPaletteEntries && num_results < *color_count; ++i)
+    {
+      hb_ot_color_t* result = &colors[num_results];
+      result->red = crec[i].red;
+      result->green = crec[i].green;
+      result->blue = crec[i].blue;
+      result->alpha = crec[i].alpha;
+      ++num_results;
+    }
+  }
+
+  if (likely (color_count)) *color_count = num_results;
+  return cpal.numPaletteEntries;
+}
diff --git a/src/hb-ot-color.h b/src/hb-ot-color.h
new file mode 100644
index 00000000..2fe799f5
--- /dev/null
+++ b/src/hb-ot-color.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright © 2016  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Sascha Brawer
+ */
+
+#ifndef HB_OT_H_IN
+#error "Include <hb-ot.h> instead."
+#endif
+
+#ifndef HB_OT_COLOR_H
+#define HB_OT_COLOR_H
+
+#include "hb.h"
+
+#include "hb-ot-tag.h"
+
+HB_BEGIN_DECLS
+
+/**
+ * HB_OT_TAG_CPAL:
+ * a four-letter tag for identifying the CPAL table with color palettes
+ *
+ * Since: 1.2.8
+ */
+#define HB_OT_TAG_CPAL HB_TAG('C','P','A','L')
+
+
+/**
+ * hb_ot_color_t:
+ * @red: the intensity of the red channel
+ * @green: the intensity of the green channel
+ * @blue: the intensity of the blue channel
+ * @alpha: the transparency
+ *
+ * Structure for holding color values.
+ *
+ * Since: 1.2.8
+ */
+typedef struct
+{
+  uint8_t red, green, blue, alpha;
+} hb_ot_color_t;
+
+
+/**
+ * hb_ot_color_palette_flags_t:
+ * @HB_OT_COLOR_PALETTE_FLAG_DEFAULT: default indicating that there is nothing special to note about a color palette.
+ * @HB_OT_COLOR_PALETTE_FLAG_FOR_LIGHT_BACKGROUND: flag indicating that the color palette is suitable for rendering text on light background.
+ * @HB_OT_COLOR_PALETTE_FLAG_FOR_DARK_BACKGROUND: flag indicating that the color palette is suitable for rendering text on dark background.
+ *
+ * Since: 1.2.8
+ */
+typedef enum { /*< flags >*/
+  HB_OT_COLOR_PALETTE_FLAG_DEFAULT = 0x00000000u,
+  HB_OT_COLOR_PALETTE_FLAG_FOR_LIGHT_BACKGROUND = 0x00000001u,
+  HB_OT_COLOR_PALETTE_FLAG_FOR_DARK_BACKGROUND = 0x00000002u,
+} hb_ot_color_palette_flags_t;
+
+
+HB_EXTERN unsigned int
+hb_ot_color_get_palette_count (hb_face_t *face);
+
+HB_EXTERN unsigned int
+hb_ot_color_get_palette_name_id (hb_face_t *face, unsigned int palette);
+
+HB_EXTERN hb_ot_color_palette_flags_t
+hb_ot_color_get_palette_flags (hb_face_t *face, unsigned int palette);
+
+HB_EXTERN unsigned int
+hb_ot_color_get_palette_colors (hb_face_t       *face,
+				unsigned int     palette, /* default=0 */
+				unsigned int     start_offset,
+				unsigned int    *color_count /* IN/OUT */,
+				hb_ot_color_t   *colors /* OUT */);
+
+HB_END_DECLS
+
+#endif /* HB_OT_COLOR_H */
diff --git a/src/hb-ot-cpal-table.hh b/src/hb-ot-cpal-table.hh
new file mode 100644
index 00000000..3287346b
--- /dev/null
+++ b/src/hb-ot-cpal-table.hh
@@ -0,0 +1,121 @@
+/*
+ * Copyright © 2016  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Sascha Brawer
+ */
+
+#ifndef HB_OT_CPAL_TABLE_HH
+#define HB_OT_CPAL_TABLE_HH
+
+#include "hb-open-type-private.hh"
+
+
+namespace OT {
+
+/*
+ * Color Palette
+ * http://www.microsoft.com/typography/otspec/cpal.htm
+ */
+
+#define HB_OT_TAG_CPAL HB_TAG('C','P','A','L')
+
+struct ColorRecord
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    // We do not enforce alpha != 0 because zero alpha is bogus but harmless.
+    TRACE_SANITIZE (this);
+    return_trace (true);
+  }
+
+  public:
+  BYTE blue;
+  BYTE green;
+  BYTE red;
+  BYTE alpha;
+  DEFINE_SIZE_STATIC (4);
+};
+
+struct CPALV1Tail
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (paletteFlags.sanitize (c, this) &&
+    		  paletteLabel.sanitize (c, this) &&
+    		  paletteEntryLabel.sanitize (c, this));
+  }
+  
+  public:
+  OffsetTo<ULONG, ULONG> paletteFlags;
+  OffsetTo<USHORT, ULONG> paletteLabel;
+  OffsetTo<USHORT, ULONG> paletteEntryLabel;
+  DEFINE_SIZE_STATIC (12);  
+};
+
+struct CPAL
+{
+  static const hb_tag_t tableTag = HB_OT_TAG_CPAL;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!(c->check_struct (this) &&
+		    offsetFirstColorRecord.sanitize (c, this)))) {
+      return_trace (false);
+    }
+    for (unsigned int i = 0; i < numPalettes; ++i) {
+      if (unlikely (colorRecordIndices[i] + numPaletteEntries > numColorRecords)) {
+	return_trace (false);
+      }
+    }
+    if (version > 1) {
+      const CPALV1Tail &v1 = StructAfter<CPALV1Tail>(*this);
+      return_trace (v1.sanitize (c));
+    } else {
+      return_trace (true);
+    }
+  }
+
+  inline unsigned int get_size (void) const {
+    return min_size + numPalettes * 2;
+  }
+
+  public:
+  USHORT	version;
+
+  /* Version 0 */
+  USHORT	numPaletteEntries;
+  USHORT	numPalettes;
+  USHORT	numColorRecords;
+  OffsetTo<ColorRecord, ULONG> offsetFirstColorRecord;
+  USHORT	colorRecordIndices[VAR];  // VAR=numPalettes
+
+  public:
+  DEFINE_SIZE_ARRAY (12, colorRecordIndices);
+};
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_CPAL_TABLE_HH */
diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh
index 778b2c44..30c8717a 100644
--- a/src/hb-ot-layout-private.hh
+++ b/src/hb-ot-layout-private.hh
@@ -124,6 +124,7 @@ namespace OT {
   struct GDEF;
   struct GSUB;
   struct GPOS;
+  struct CPAL;
 }
 
 struct hb_ot_layout_lookup_accelerator_t
@@ -152,10 +153,12 @@ struct hb_ot_layout_t
   hb_blob_t *gdef_blob;
   hb_blob_t *gsub_blob;
   hb_blob_t *gpos_blob;
+  hb_blob_t *cpal_blob;
 
   const struct OT::GDEF *gdef;
   const struct OT::GSUB *gsub;
   const struct OT::GPOS *gpos;
+  const struct OT::CPAL *cpal;
 
   unsigned int gsub_lookup_count;
   unsigned int gpos_lookup_count;
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index 29749bce..73f993be 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -31,6 +31,7 @@
 #include "hb-open-type-private.hh"
 #include "hb-ot-layout-private.hh"
 
+#include "hb-ot-cpal-table.hh"
 #include "hb-ot-layout-gdef-table.hh"
 #include "hb-ot-layout-gsub-table.hh"
 #include "hb-ot-layout-gpos-table.hh"
@@ -60,6 +61,10 @@ _hb_ot_layout_create (hb_face_t *face)
   layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
   layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
 
+  // The CPAL table is rarely accessed, so we only try to load it in _get_cpal.
+  layout->cpal_blob = NULL;
+  layout->cpal = NULL;
+
   {
     /*
      * The ugly business of blacklisting individual fonts' tables happen here!
@@ -131,6 +136,8 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout)
   hb_blob_destroy (layout->gsub_blob);
   hb_blob_destroy (layout->gpos_blob);
 
+  if (layout->cpal_blob) hb_blob_destroy (layout->cpal_blob);
+
   free (layout);
 }
 
diff --git a/src/hb-ot.h b/src/hb-ot.h
index 47c92a58..0c0cf8d9 100644
--- a/src/hb-ot.h
+++ b/src/hb-ot.h
@@ -30,6 +30,7 @@
 
 #include "hb.h"
 
+#include "hb-ot-color.h"
 #include "hb-ot-font.h"
 #include "hb-ot-layout.h"
 #include "hb-ot-tag.h"
diff --git a/test/api/Makefile.am b/test/api/Makefile.am
index d7d40af3..895d1543 100644
--- a/test/api/Makefile.am
+++ b/test/api/Makefile.am
@@ -44,6 +44,7 @@ endif
 
 if HAVE_OT
 TEST_PROGS += \
+	test-ot-color \
 	test-ot-tag \
 	$(NULL)
 endif
diff --git a/test/api/hb-test.h b/test/api/hb-test.h
index 4d41218b..9ce6adc6 100644
--- a/test/api/hb-test.h
+++ b/test/api/hb-test.h
@@ -86,6 +86,36 @@ hb_test_run (void)
 }
 
 
+/* Helpers for loading test fonts */
+static inline hb_face_t *
+hb_test_load_face (const char *path)
+{
+  const char *font_data = NULL;
+  unsigned int len = 0;
+  hb_blob_t *blob = NULL;
+  hb_face_t *face = NULL;
+
+  FILE *f = fopen (path, "rb");
+  if (!f) {
+    perror (path);
+    exit (1);
+  }
+
+  fseek (f, 0, SEEK_END);
+  len = ftell (f);
+  fseek (f, 0, SEEK_SET);
+  font_data = (const char *) malloc (len);
+  if (!font_data) len = 0;
+  len = fread ((char *) font_data, 1, len, f);
+  fclose (f);
+
+  blob = hb_blob_create (font_data, len, HB_MEMORY_MODE_READONLY, 0, free);
+  face = hb_face_create (blob, 0 /* first face */);
+  hb_blob_destroy (blob);
+  return face;
+}
+
+
 /* Bugzilla helpers */
 
 static inline void
diff --git a/test/api/test-ot-color.c b/test/api/test-ot-color.c
new file mode 100644
index 00000000..7378a59e
--- /dev/null
+++ b/test/api/test-ot-color.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright © 2016  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Sascha Brawer
+ */
+
+#include "hb-test.h"
+
+#include <hb-ot.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/* Unit tests for hb-ot-color.h */
+
+/* Test font with the following CPAL v0 table, as TTX and manual disassembly:
+
+  <CPAL>
+    <version value="0"/>
+    <numPaletteEntries value="2"/>
+    <palette index="0">
+      <color index="0" value="#000000FF"/>
+      <color index="1" value="#66CCFFFF"/>
+    </palette>
+    <palette index="1">
+      <color index="0" value="#000000FF"/>
+      <color index="1" value="#800000FF"/>
+    </palette>
+  </CPAL>
+
+   0 | 0000                           # version=0
+   2 | 0002                           # numPaletteEntries=2
+   4 | 0002                           # numPalettes=2
+   6 | 0004                           # numColorRecords=4
+   8 | 00000010                       # offsetToFirstColorRecord=16
+  12 | 0000 0002                      # colorRecordIndex=[0, 2]
+  16 | 000000ff ffcc66ff              # colorRecord #0, #1 (BGRA)
+  24 | 000000ff 000080ff              # colorRecord #2, #3 (BGRA)
+ */
+static hb_face_t *cpal_v0 = NULL;
+
+/* Test font with the following CPAL v1 table, as TTX and manual disassembly:
+
+  <CPAL>
+    <version value="1"/>
+    <numPaletteEntries value="2"/>
+    <palette index="0" label="257" type="2">
+      <color index="0" value="#000000FF"/>
+      <color index="1" value="#66CCFFFF"/>
+    </palette>
+    <palette index="1" label="65535" type="1">
+      <color index="0" value="#000000FF"/>
+      <color index="1" value="#FFCC66FF"/>
+    </palette>
+    <palette index="2" label="258" type="0">
+      <color index="0" value="#000000FF"/>
+      <color index="1" value="#800000FF"/>
+    </palette>
+    <paletteEntryLabels>
+      <label index="0" value="65535"/>
+      <label index="1" value="256"/>
+    </paletteEntryLabels>
+  </CPAL>
+
+   0 | 0001                           # version=1
+   2 | 0002                           # numPaletteEntries=2
+   4 | 0003                           # numPalettes=3
+   6 | 0006                           # numColorRecords=6
+   8 | 0000001e                       # offsetToFirstColorRecord=30
+  12 | 0000 0002 0004                 # colorRecordIndex=[0, 2, 4]
+  18 | 00000036                       # offsetToPaletteTypeArray=54
+  22 | 00000042                       # offsetToPaletteLabelArray=66
+  26 | 00000048                       # offsetToPaletteEntryLabelArray=72
+  30 | 000000ff ffcc66ff 000000ff     # colorRecord #0, #1, #2 (BGRA)
+  42 | 66ccffff 000000ff 000080ff     # colorRecord #3, #4, #5 (BGRA)
+  54 | 00000002 00000001 00000000     # paletteFlags=[2, 1, 0]
+  66 | 0101 ffff 0102                 # paletteName=[257, 0xffff, 258]
+  72 | ffff 0100                      # paletteEntryLabel=[0xffff, 256]
+*/
+static hb_face_t *cpal_v1 = NULL;
+
+
+#define assert_color_rgba(colors, i, r, g, b, a) G_STMT_START {	\
+  const hb_ot_color_t *_colors = (colors); \
+  const size_t _i = (i); \
+  const uint8_t red = (r), green = (g), blue = (b), alpha = (a); \
+  if (_colors[_i].red != r) { \
+    g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
+				"colors[" #i "].red", _colors[_i].red, "==", red, 'x'); \
+  } \
+  if (colors[i].green != green) { \
+    g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
+				"colors[" #i "].green", colors[i].green, "==", green, 'x'); \
+  } \
+  if (colors[i].blue != blue) { \
+    g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
+				"colors[" #i "].blue", colors[i].blue, "==", blue, 'x'); \
+  } \
+  if (colors[i].alpha != alpha) { \
+    g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
+				"colors[" #i "].alpha", colors[i].alpha, "==", alpha, 'x'); \
+  } \
+} G_STMT_END
+
+
+static void
+test_hb_ot_color_get_palette_count (void)
+{
+  g_assert_cmpint (hb_ot_color_get_palette_count (hb_face_get_empty()), ==, 0);
+  g_assert_cmpint (hb_ot_color_get_palette_count (cpal_v0), ==, 2);
+  g_assert_cmpint (hb_ot_color_get_palette_count (cpal_v1), ==, 3);
+}
+
+
+static void
+test_hb_ot_color_get_palette_name_id_empty (void)
+{
+  /* numPalettes=0, so all calls are for out-of-bounds palette indices */
+  g_assert_cmpint (hb_ot_color_get_palette_name_id (hb_face_get_empty(), 0), ==, 0);
+  g_assert_cmpint (hb_ot_color_get_palette_name_id (hb_face_get_empty(), 1), ==, 0);
+}
+
+
+static void
+test_hb_ot_color_get_palette_name_id_v0 (void)
+{
+  g_assert_cmpint (hb_ot_color_get_palette_name_id (cpal_v0, 0), ==, 0);
+  g_assert_cmpint (hb_ot_color_get_palette_name_id (cpal_v0, 1), ==, 0);
+
+  /* numPalettes=2, so palette #2 is out of bounds */
+  g_assert_cmpint (hb_ot_color_get_palette_name_id (cpal_v0, 2), ==, 0);
+}
+
+
+static void
+test_hb_ot_color_get_palette_name_id_v1 (void)
+{
+  g_assert_cmpint (hb_ot_color_get_palette_name_id (cpal_v1, 0), ==, 257);
+  g_assert_cmpint (hb_ot_color_get_palette_name_id (cpal_v1, 1), ==, 0);
+  g_assert_cmpint (hb_ot_color_get_palette_name_id (cpal_v1, 2), ==, 258);
+
+  /* numPalettes=3, so palette #3 is out of bounds */
+  g_assert_cmpint (hb_ot_color_get_palette_name_id (cpal_v1, 3), ==, 0);
+}
+
+static void
+test_hb_ot_color_get_palette_flags_empty (void)
+{
+  /* numPalettes=0, so all calls are for out-of-bounds palette indices */
+  g_assert_cmpint (hb_ot_color_get_palette_flags (hb_face_get_empty(), 0), ==, HB_OT_COLOR_PALETTE_FLAG_DEFAULT);
+  g_assert_cmpint (hb_ot_color_get_palette_flags (hb_face_get_empty(), 1), ==, HB_OT_COLOR_PALETTE_FLAG_DEFAULT);
+}
+
+
+static void
+test_hb_ot_color_get_palette_flags_v0 (void)
+{
+  g_assert_cmpint (hb_ot_color_get_palette_flags (cpal_v0, 0), ==, HB_OT_COLOR_PALETTE_FLAG_DEFAULT);
+  g_assert_cmpint (hb_ot_color_get_palette_flags (cpal_v0, 1), ==, HB_OT_COLOR_PALETTE_FLAG_DEFAULT);
+
+  /* numPalettes=2, so palette #2 is out of bounds */
+  g_assert_cmpint (hb_ot_color_get_palette_flags (cpal_v0, 2), ==, HB_OT_COLOR_PALETTE_FLAG_DEFAULT);
+}
+
+
+static void
+test_hb_ot_color_get_palette_flags_v1 (void)
+{
+  g_assert_cmpint (hb_ot_color_get_palette_flags (cpal_v1, 0), ==, HB_OT_COLOR_PALETTE_FLAG_FOR_DARK_BACKGROUND);
+  g_assert_cmpint (hb_ot_color_get_palette_flags (cpal_v1, 1), ==, HB_OT_COLOR_PALETTE_FLAG_FOR_LIGHT_BACKGROUND);
+  g_assert_cmpint (hb_ot_color_get_palette_flags (cpal_v0, 2), ==, HB_OT_COLOR_PALETTE_FLAG_DEFAULT);
+
+  /* numPalettes=3, so palette #3 is out of bounds */
+  g_assert_cmpint (hb_ot_color_get_palette_flags (cpal_v0, 3), ==, HB_OT_COLOR_PALETTE_FLAG_DEFAULT);
+}
+
+
+static void
+test_hb_ot_color_get_palette_colors_empty (void)
+{
+  hb_face_t *empty = hb_face_get_empty ();
+  g_assert_cmpint (hb_ot_color_get_palette_colors (empty, 0, 0, NULL, NULL), ==, 0);
+}
+
+
+static void
+test_hb_ot_color_get_palette_colors_v0 (void)
+{
+  unsigned int num_colors = hb_ot_color_get_palette_colors (cpal_v0, 0, 0, NULL, NULL);
+  hb_ot_color_t *colors = (hb_ot_color_t*) alloca (num_colors * sizeof (hb_ot_color_t));
+  size_t colors_size = num_colors * sizeof(*colors);
+  g_assert_cmpint (num_colors, ==, 2);
+
+  /* Palette #0, start_index=0 */
+  g_assert_cmpint (hb_ot_color_get_palette_colors (cpal_v0, 0, 0, &num_colors, colors), ==, 2);
+  g_assert_cmpint (num_colors, ==, 2);
+  assert_color_rgba (colors, 0, 0x00, 0x00, 0x00, 0xff);
+  assert_color_rgba (colors, 1, 0x66, 0xcc, 0xff, 0xff);
+
+  /* Palette #1, start_index=0 */
+  g_assert_cmpint (hb_ot_color_get_palette_colors (cpal_v0, 1, 0, &num_colors, colors), ==, 2);
+  g_assert_cmpint (num_colors, ==, 2);
+  assert_color_rgba (colors, 0, 0x00, 0x00, 0x00, 0xff);
+  assert_color_rgba (colors, 1, 0x80, 0x00, 0x00, 0xff);
+
+  /* Palette #2 (there are only #0 and #1 in the font, so this is out of bounds) */
+  g_assert_cmpint (hb_ot_color_get_palette_colors (cpal_v0, 2, 0, &num_colors, colors), ==, 0);
+
+  /* Palette #0, start_index=1 */
+  memset(colors, 0x33, colors_size);
+  num_colors = 2;
+  g_assert_cmpint (hb_ot_color_get_palette_colors (cpal_v0, 0, 1, &num_colors, colors), ==, 2);
+  g_assert_cmpint (num_colors, ==, 1);
+  assert_color_rgba (colors, 0, 0x66, 0xcc, 0xff, 0xff);
+  assert_color_rgba (colors, 1, 0x33, 0x33, 0x33, 0x33);  /* untouched */
+
+  /* Palette #0, start_index=0, pretend that we have only allocated space for 1 color */
+  memset(colors, 0x44, colors_size);
+  num_colors = 1;
+  g_assert_cmpint (hb_ot_color_get_palette_colors (cpal_v0, 0, 0, &num_colors, colors), ==, 2);
+  g_assert_cmpint (num_colors, ==, 1);
+  assert_color_rgba (colors, 0, 0x00, 0x00, 0x00, 0xff);
+  assert_color_rgba (colors, 1, 0x44, 0x44, 0x44, 0x44);  /* untouched */
+
+  /* start_index > numPaletteEntries */
+  memset(colors, 0x44, colors_size);
+  num_colors = 2;
+  g_assert_cmpint (hb_ot_color_get_palette_colors (cpal_v0, 0, 9876, &num_colors, colors), ==, 2);
+  g_assert_cmpint (num_colors, ==, 0);
+  assert_color_rgba (colors, 0, 0x44, 0x44, 0x44, 0x44);  /* untouched */
+  assert_color_rgba (colors, 1, 0x44, 0x44, 0x44, 0x44);  /* untouched */
+}
+
+
+static void
+test_hb_ot_color_get_palette_colors_v1 (void)
+{
+  hb_ot_color_t colors[3];
+  unsigned int num_colors = hb_ot_color_get_palette_colors (cpal_v1, 0, 0, NULL, NULL);
+  size_t colors_size = 3 * sizeof(*colors);
+  g_assert_cmpint (num_colors, ==, 2);
+
+  /* Palette #0, start_index=0 */
+  memset(colors, 0x77, colors_size);
+  g_assert_cmpint (hb_ot_color_get_palette_colors (cpal_v1, 0, 0, &num_colors, colors), ==, 2);
+  g_assert_cmpint (num_colors, ==, 2);
+  assert_color_rgba (colors, 0, 0x00, 0x00, 0x00, 0xff);
+  assert_color_rgba (colors, 1, 0x66, 0xcc, 0xff, 0xff);
+  assert_color_rgba (colors, 2, 0x77, 0x77, 0x77, 0x77);  /* untouched */
+
+  /* Palette #1, start_index=0 */
+  memset(colors, 0x77, colors_size);
+  g_assert_cmpint (hb_ot_color_get_palette_colors (cpal_v1, 1, 0, &num_colors, colors), ==, 2);
+  g_assert_cmpint (num_colors, ==, 2);
+  assert_color_rgba (colors, 0, 0x00, 0x00, 0x00, 0xff);
+  assert_color_rgba (colors, 1, 0xff, 0xcc, 0x66, 0xff);
+  assert_color_rgba (colors, 2, 0x77, 0x77, 0x77, 0x77);  /* untouched */
+
+  /* Palette #2, start_index=0 */
+  memset(colors, 0x77, colors_size);
+  g_assert_cmpint (hb_ot_color_get_palette_colors (cpal_v1, 2, 0, &num_colors, colors), ==, 2);
+  g_assert_cmpint (num_colors, ==, 2);
+  assert_color_rgba (colors, 0, 0x00, 0x00, 0x00, 0xff);
+  assert_color_rgba (colors, 1, 0x80, 0x00, 0x00, 0xff);
+  assert_color_rgba (colors, 2, 0x77, 0x77, 0x77, 0x77);  /* untouched */
+
+  /* Palette #3 (out of bounds), start_index=0 */
+  memset(colors, 0x77, colors_size);
+  g_assert_cmpint (hb_ot_color_get_palette_colors (cpal_v1, 3, 0, &num_colors, colors), ==, 0);
+  g_assert_cmpint (num_colors, ==, 0);
+  assert_color_rgba (colors, 0, 0x77, 0x77, 0x77, 0x77);  /* untouched */
+  assert_color_rgba (colors, 1, 0x77, 0x77, 0x77, 0x77);  /* untouched */
+  assert_color_rgba (colors, 2, 0x77, 0x77, 0x77, 0x77);  /* untouched */
+}
+
+
+int
+main (int argc, char **argv)
+{
+  int status = 0;
+
+  hb_test_init (&argc, &argv);
+  cpal_v0 = hb_test_load_face ("../shaping/fonts/sha1sum/e90374e5e439e00725b4fe7a8d73db57c5a97f82.ttf");
+  cpal_v1 = hb_test_load_face ("../shaping/fonts/sha1sum/319f5d7ebffbefc5c5e6569f8cea73444d7a7268.ttf");
+  hb_test_add (test_hb_ot_color_get_palette_count);
+  hb_test_add (test_hb_ot_color_get_palette_name_id_empty);
+  hb_test_add (test_hb_ot_color_get_palette_name_id_v0);
+  hb_test_add (test_hb_ot_color_get_palette_name_id_v1);
+  hb_test_add (test_hb_ot_color_get_palette_flags_empty);
+  hb_test_add (test_hb_ot_color_get_palette_flags_v0);
+  hb_test_add (test_hb_ot_color_get_palette_flags_v1);
+  hb_test_add (test_hb_ot_color_get_palette_colors_empty);
+  hb_test_add (test_hb_ot_color_get_palette_colors_v0);
+  hb_test_add (test_hb_ot_color_get_palette_colors_v1);
+  status = hb_test_run();
+  hb_face_destroy (cpal_v0);
+  hb_face_destroy (cpal_v1);
+  return status;
+}
diff --git a/test/shaping/fonts/sha1sum/319f5d7ebffbefc5c5e6569f8cea73444d7a7268.ttf b/test/shaping/fonts/sha1sum/319f5d7ebffbefc5c5e6569f8cea73444d7a7268.ttf
new file mode 100644
index 00000000..53044b71
Binary files /dev/null and b/test/shaping/fonts/sha1sum/319f5d7ebffbefc5c5e6569f8cea73444d7a7268.ttf differ
diff --git a/test/shaping/fonts/sha1sum/e90374e5e439e00725b4fe7a8d73db57c5a97f82.ttf b/test/shaping/fonts/sha1sum/e90374e5e439e00725b4fe7a8d73db57c5a97f82.ttf
new file mode 100644
index 00000000..66a9001b
Binary files /dev/null and b/test/shaping/fonts/sha1sum/e90374e5e439e00725b4fe7a8d73db57c5a97f82.ttf differ


More information about the HarfBuzz mailing list