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

Behdad Esfahbod behdad at kemper.freedesktop.org
Wed Mar 28 17:45:32 UTC 2018


 CMakeLists.txt                                                                  |    2 
 src/Makefile.am                                                                 |   18 -
 src/dump-emoji.cc                                                               |  141 ++++++++++
 src/gen-use-table.py                                                            |  105 +++----
 src/hb-ot-color-cbdt-table.hh                                                   |   71 +++++
 src/hb-ot-color-sbix-table.hh                                                   |   79 +++--
 src/hb-ot-color-svg-table.hh                                                    |   56 ++-
 src/hb-ot-hdmx-table.hh                                                         |    1 
 src/hb-subset-glyf.cc                                                           |    6 
 src/hb-subset.cc                                                                |    8 
 src/hb-uniscribe.cc                                                             |    2 
 test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5521982557782016 |binary
 test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016 |binary
 test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6651660668502016 |binary
 test/api/test-subset-hdmx.c                                                     |   23 +
 test/api/test-subset.c                                                          |   23 +
 16 files changed, 424 insertions(+), 111 deletions(-)

New commits:
commit b17e1a40885245df690a14c7528939b3881e1fe4
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Mar 28 10:44:52 2018 -0700

    [uniscribe] Fix assertion fail in checksum calc
    
    Program: Z:\Users\ebrahim\Desktop\harfbuzz\winbuild\util\.libs\hb-shape.exe
    File: ../../src/hb-open-type-private.hh, Line 769
    
    Expression: 0 == (Length & 3)
    
    abnormal program termination

diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index cd25769d..f027222d 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -410,7 +410,7 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name)
     if (face.find_table_index (HB_OT_TAG_name, &index))
     {
       OT::TableRecord &record = const_cast<OT::TableRecord &> (face.get_table (index));
-      record.checkSum.set_for_data (&name, name_table_length);
+      record.checkSum.set_for_data (&name, new_length);
       record.offset.set (name_table_offset);
       record.length.set (name_table_length);
     }
commit a48dd6ef235d569d4b6f6f213ba93a54e142458d
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Wed Mar 28 19:08:19 2018 +0430

    Make gen-use-table.py py3 compatible (#932)

diff --git a/src/gen-use-table.py b/src/gen-use-table.py
index 06817255..ecbdfb95 100755
--- a/src/gen-use-table.py
+++ b/src/gen-use-table.py
@@ -1,9 +1,10 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
+from __future__ import print_function
 import sys
 
 if len (sys.argv) != 5:
-	print >>sys.stderr, "usage: ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt"
+	print ("usage: ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt", file=sys.stderr)
 	sys.exit (1)
 
 BLACKLISTED_BLOCKS = ["Thai", "Lao", "Tibetan"]
@@ -352,21 +353,21 @@ def map_to_use(data):
 defaults = ('O', 'No_Block')
 data = map_to_use(data)
 
-print "/* == Start of generated table == */"
-print "/*"
-print " * The following table is generated by running:"
-print " *"
-print " *   ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt"
-print " *"
-print " * on files with these headers:"
-print " *"
+print ("/* == Start of generated table == */")
+print ("/*")
+print (" * The following table is generated by running:")
+print (" *")
+print (" *   ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt")
+print (" *")
+print (" * on files with these headers:")
+print (" *")
 for h in headers:
 	for l in h:
-		print " * %s" % (l.strip())
-print " */"
-print
-print '#include "hb-ot-shape-complex-use-private.hh"'
-print
+		print (" * %s" % (l.strip()))
+print (" */")
+print ()
+print ('#include "hb-ot-shape-complex-use-private.hh"')
+print ()
 
 total = 0
 used = 0
@@ -374,22 +375,22 @@ last_block = None
 def print_block (block, start, end, data):
 	global total, used, last_block
 	if block and block != last_block:
-		print
-		print
-		print "  /* %s */" % block
+		print ()
+		print ()
+		print ("  /* %s */" % block)
 		if start % 16:
-			print ' ' * (20 + (start % 16 * 6)),
+			print (' ' * (20 + (start % 16 * 6)), end='')
 	num = 0
 	assert start % 8 == 0
 	assert (end+1) % 8 == 0
 	for u in range (start, end+1):
 		if u % 16 == 0:
-			print
-			print "  /* %04X */" % u,
+			print ()
+			print ("  /* %04X */" % u, end='')
 		if u in data:
 			num += 1
 		d = data.get (u, defaults)
-		sys.stdout.write ("%6s," % d[0])
+		print ("%6s," % d[0], end='')
 
 	total += end - start + 1
 	used += num
@@ -406,14 +407,14 @@ starts = []
 ends = []
 for k,v in sorted(use_mapping.items()):
 	if k in use_positions and use_positions[k]: continue
-	print "#define %s	USE_%s	/* %s */" % (k, k, v.__name__[3:])
+	print ("#define %s	USE_%s	/* %s */" % (k, k, v.__name__[3:]))
 for k,v in sorted(use_positions.items()):
 	if not v: continue
 	for suf in v.keys():
 		tag = k + suf
-		print "#define %s	USE_%s" % (tag, tag)
-print ""
-print "static const USE_TABLE_ELEMENT_TYPE use_table[] = {"
+		print ("#define %s	USE_%s" % (tag, tag))
+print ("")
+print ("static const USE_TABLE_ELEMENT_TYPE use_table[] = {")
 for u in uu:
 	if u <= last:
 		continue
@@ -433,51 +434,51 @@ for u in uu:
 			if last >= 0:
 				ends.append (last + 1)
 				offset += ends[-1] - starts[-1]
-			print
-			print
-			print "#define use_offset_0x%04xu %d" % (start, offset)
+			print ()
+			print ()
+			print ("#define use_offset_0x%04xu %d" % (start, offset))
 			starts.append (start)
 
 	print_block (block, start, end, data)
 	last = end
 ends.append (last + 1)
 offset += ends[-1] - starts[-1]
-print
-print
+print ()
+print ()
 occupancy = used * 100. / total
 page_bits = 12
-print "}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy)
-print
-print "USE_TABLE_ELEMENT_TYPE"
-print "hb_use_get_category (hb_codepoint_t u)"
-print "{"
-print "  switch (u >> %d)" % page_bits
-print "  {"
+print ("}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy))
+print ()
+print ("USE_TABLE_ELEMENT_TYPE")
+print ("hb_use_get_category (hb_codepoint_t u)")
+print ("{")
+print ("  switch (u >> %d)" % page_bits)
+print ("  {")
 pages = set([u>>page_bits for u in starts+ends])
 for p in sorted(pages):
-	print "    case 0x%0Xu:" % p
+	print ("    case 0x%0Xu:" % p)
 	for (start,end) in zip (starts, ends):
 		if p not in [start>>page_bits, end>>page_bits]: continue
 		offset = "use_offset_0x%04xu" % start
-		print "      if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return use_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset)
-	print "      break;"
-	print ""
-print "    default:"
-print "      break;"
-print "  }"
-print "  return USE_O;"
-print "}"
-print
+		print ("      if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return use_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset))
+	print ("      break;")
+	print ("")
+print ("    default:")
+print ("      break;")
+print ("  }")
+print ("  return USE_O;")
+print ("}")
+print ()
 for k in sorted(use_mapping.keys()):
 	if k in use_positions and use_positions[k]: continue
-	print "#undef %s" % k
+	print ("#undef %s" % k)
 for k,v in sorted(use_positions.items()):
 	if not v: continue
 	for suf in v.keys():
 		tag = k + suf
-		print "#undef %s" % tag
-print
-print "/* == End of generated table == */"
+		print ("#undef %s" % tag)
+print ()
+print ("/* == End of generated table == */")
 
 # Maintain at least 50% occupancy in the table */
 if occupancy < 50:
commit 1c3372786c503f3f9108971dfa8956e4cb95f65d
Author: Garret Rieger <grieger at google.com>
Date:   Tue Mar 27 10:42:19 2018 -0700

    [subset] fix infinite loop bug in looping through tables for subsetting.

diff --git a/src/hb-subset.cc b/src/hb-subset.cc
index 2a2f8557..b253817e 100644
--- a/src/hb-subset.cc
+++ b/src/hb-subset.cc
@@ -363,8 +363,8 @@ hb_subset (hb_face_t *source,
         continue;
       }
       success = success && _subset_table (plan, tag);
-      offset += count;
     }
+    offset += count;
   } while (count == ARRAY_LENGTH (table_tags));
 
   hb_face_t *result = success ? hb_face_reference(plan->dest) : hb_face_get_empty();
diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5521982557782016 b/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5521982557782016
new file mode 100644
index 00000000..55541f74
Binary files /dev/null and b/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5521982557782016 differ
diff --git a/test/api/test-subset.c b/test/api/test-subset.c
index 6bf5c066..6d2bf06e 100644
--- a/test/api/test-subset.c
+++ b/test/api/test-subset.c
@@ -52,6 +52,28 @@ test_subset_32_tables (void)
 }
 
 static void
+test_subset_no_inf_loop (void)
+{
+  hb_face_t *face = hb_subset_test_open_font("fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5521982557782016");
+
+  hb_subset_input_t *input = hb_subset_input_create_or_fail ();
+  hb_set_t *codepoints = hb_subset_input_unicode_set (input);
+  hb_set_add (codepoints, 'a');
+  hb_set_add (codepoints, 'b');
+  hb_set_add (codepoints, 'c');
+
+  hb_subset_profile_t *profile = hb_subset_profile_create();
+  hb_face_t *subset = hb_subset (face, profile, input);
+  g_assert (subset);
+  g_assert (subset == hb_face_get_empty ());
+
+  hb_subset_input_destroy (input);
+  hb_subset_profile_destroy (profile);
+  hb_face_destroy (subset);
+  hb_face_destroy (face);
+}
+
+static void
 test_subset_crash (void)
 {
   hb_face_t *face = hb_subset_test_open_font("fonts/crash-4b60576767ee4d9fe1cc10959d89baf73d4e8249");
@@ -79,6 +101,7 @@ main (int argc, char **argv)
   hb_test_init (&argc, &argv);
 
   hb_test_add (test_subset_32_tables);
+  hb_test_add (test_subset_no_inf_loop);
   hb_test_add (test_subset_crash);
 
   return hb_test_run();
commit 8fd55422c3fa2279991d93875d912fca4ee89cf5
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Tue Mar 27 16:57:09 2018 +0430

    Implement an internal emojis dumper tool (#909)
    
    Later to be expanded to a more general tool but for now it only supports CBDT, SVG and CBDT.

diff --git a/CMakeLists.txt b/CMakeLists.txt
index a41afc4a..da6ae8b3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -543,7 +543,7 @@ if (UNIX OR MINGW)
   check_cxx_compiler_flag(-Bsymbolic-functions CXX_SUPPORTS_FLAG_BSYMB_FUNCS)
   if(CXX_SUPPORTS_FLAG_BSYMB_FUNCS)
     link_libraries(-Bsymbolic-functions)
-  endif()  
+  endif()
 
   if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
     # Make sure we don't link to libstdc++
diff --git a/src/Makefile.am b/src/Makefile.am
index 2aa3dc4f..df45f73b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -368,11 +368,15 @@ dist_check_SCRIPTS += \
 endif
 
 check_PROGRAMS += \
+	dump-emoji \
 	dump-indic-data \
 	dump-khmer-data \
 	dump-myanmar-data \
 	dump-use-data \
 	$(NULL)
+dump_emoji_SOURCES = dump-emoji.cc
+dump_emoji_CPPFLAGS = $(HBCFLAGS)
+dump_emoji_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)
diff --git a/src/dump-emoji.cc b/src/dump-emoji.cc
new file mode 100644
index 00000000..a9595e41
--- /dev/null
+++ b/src/dump-emoji.cc
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+#include "hb.h"
+#include "hb-private.hh"
+#include "hb-ot-color-cbdt-table.hh"
+#include "hb-ot-color-sbix-table.hh"
+#include "hb-ot-color-svg-table.hh"
+
+#ifdef HAVE_GLIB
+#include <glib.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifndef HB_NO_VISIBILITY
+const void * const OT::_hb_NullPool[HB_NULL_POOL_SIZE / sizeof (void *)] = {};
+#endif
+
+void cbdt_callback (const uint8_t* data, unsigned int length,
+                    unsigned int group, unsigned int gid)
+{
+  char outName[255];
+  sprintf (outName, "out/cbdt-%d-%d.png", group, gid);
+  FILE *f = fopen (outName, "wb");
+  fwrite (data, 1, length, f);
+  fclose (f);
+}
+
+void sbix_callback (const uint8_t* data, unsigned int length,
+                    unsigned int group, unsigned int gid)
+{
+  char outName[255];
+  sprintf (outName, "out/sbix-%d-%d.png", group, gid);
+  FILE *f = fopen (outName, "wb");
+  fwrite (data, 1, length, f);
+  fclose (f);
+}
+
+void svg_callback (const uint8_t* data, unsigned int length,
+                   unsigned int start_glyph, unsigned int end_glyph)
+{
+  char outName[255];
+  if (start_glyph == end_glyph)
+    sprintf (outName, "out/svg-%d.svg", start_glyph);
+  else
+    sprintf (outName, "out/svg-%d-%d.svg", start_glyph, end_glyph);
+
+  // append "z" if the content is gzipped
+  if ((data[0] == 0x1F) && (data[1] == 0x8B))
+    strcat (outName, "z");
+
+  FILE *f = fopen (outName, "wb");
+  fwrite (data, 1, length, f);
+  fclose (f);
+}
+
+int main(int argc, char **argv)
+{
+  if (argc != 2) {
+    fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
+    exit (1);
+  }
+
+  hb_blob_t *blob = nullptr;
+  {
+    const char *font_data;
+    unsigned int len;
+    hb_destroy_func_t destroy;
+    void *user_data;
+    hb_memory_mode_t mm;
+
+#ifdef HAVE_GLIB
+    GMappedFile *mf = g_mapped_file_new (argv[1], false, nullptr);
+    font_data = g_mapped_file_get_contents (mf);
+    len = g_mapped_file_get_length (mf);
+    destroy = (hb_destroy_func_t) g_mapped_file_unref;
+    user_data = (void *) mf;
+    mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE;
+#else
+    FILE *f = fopen (argv[1], "rb");
+    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);
+    destroy = free;
+    user_data = (void *) font_data;
+    fclose (f);
+    mm = HB_MEMORY_MODE_WRITABLE;
+#endif
+
+    blob = hb_blob_create (font_data, len, mm, user_data, destroy);
+  }
+
+  hb_face_t *face = hb_face_create (blob, 0);
+  hb_font_t *font = hb_font_create (face);
+
+  OT::CBDT::accelerator_t cbdt;
+  cbdt.init (face);
+  cbdt.dump (cbdt_callback);
+  cbdt.fini ();
+
+  OT::sbix::accelerator_t sbix;
+  sbix.init (face);
+  sbix.dump (sbix_callback);
+  sbix.fini ();
+
+  OT::SVG::accelerator_t svg;
+  svg.init (face);
+  svg.dump (svg_callback);
+  svg.fini ();
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+  hb_blob_destroy (blob);
+
+  return 0;
+}
diff --git a/src/hb-ot-color-cbdt-table.hh b/src/hb-ot-color-cbdt-table.hh
index b4971bda..cf1c69c1 100644
--- a/src/hb-ot-color-cbdt-table.hh
+++ b/src/hb-ot-color-cbdt-table.hh
@@ -223,6 +223,8 @@ struct IndexSubtableRecord
 
 struct IndexSubtableArray
 {
+  friend struct CBDT;
+
   inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
   {
     TRACE_SANITIZE (this);
@@ -257,6 +259,7 @@ struct IndexSubtableArray
 struct BitmapSizeTable
 {
   friend struct CBLC;
+  friend struct CBDT;
 
   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
@@ -304,6 +307,21 @@ struct GlyphBitmapDataFormat17
   DEFINE_SIZE_ARRAY(9, data);
 };
 
+struct GlyphBitmapDataFormat18
+{
+  BigGlyphMetrics		glyphMetrics;
+  ArrayOf<HBUINT8, HBUINT32>	data;
+  public:
+  DEFINE_SIZE_ARRAY(12, data);
+};
+
+struct GlyphBitmapDataFormat19
+{
+  ArrayOf<HBUINT8, HBUINT32>	data;
+  public:
+  DEFINE_SIZE_ARRAY(4, data);
+};
+
 
 /*
  * CBLC -- Color Bitmap Location Table
@@ -444,6 +462,59 @@ struct CBDT
       return true;
     }
 
+    inline void dump (void (*callback) (const uint8_t* data, unsigned int length,
+        unsigned int group, unsigned int gid)) const
+    {
+      if (!cblc)
+	return;  // Not a color bitmap font.
+
+      for (unsigned int i = 0; i < cblc->sizeTables.len; ++i)
+      {
+        const BitmapSizeTable &sizeTable = cblc->sizeTables[i];
+        const IndexSubtableArray &subtable_array = cblc+sizeTable.indexSubtableArrayOffset;
+        for (unsigned int j = 0; j < sizeTable.numberOfIndexSubtables; ++j)
+        {
+          const IndexSubtableRecord &subtable_record = subtable_array.indexSubtablesZ[j];
+          for (unsigned int gid = subtable_record.firstGlyphIndex;
+                gid <= subtable_record.lastGlyphIndex; ++gid)
+          {
+            unsigned int image_offset = 0, image_length = 0, image_format = 0;
+
+            if (!subtable_record.get_image_data (gid,
+                  &image_offset, &image_length, &image_format))
+              continue;
+
+            switch (image_format)
+            {
+            case 17: {
+              const GlyphBitmapDataFormat17& glyphFormat17 =
+                StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
+              callback ((const uint8_t *) &glyphFormat17.data.array,
+                glyphFormat17.data.len, i, gid);
+            }
+            break;
+            case 18: {
+              const GlyphBitmapDataFormat18& glyphFormat18 =
+                StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
+              callback ((const uint8_t *) &glyphFormat18.data.array,
+                glyphFormat18.data.len, i, gid);
+            }
+            break;
+            case 19: {
+              const GlyphBitmapDataFormat19& glyphFormat19 =
+                StructAtOffset<GlyphBitmapDataFormat19> (this->cbdt, image_offset);
+              callback ((const uint8_t *) &glyphFormat19.data.array,
+                glyphFormat19.data.len, i, gid);
+            }
+            break;
+            default:
+              continue;
+            }
+          }
+        }
+      }
+    }
+
     private:
     hb_blob_t *cblc_blob;
     hb_blob_t *cbdt_blob;
diff --git a/src/hb-ot-color-sbix-table.hh b/src/hb-ot-color-sbix-table.hh
index c0d8f9b3..bc3956d8 100644
--- a/src/hb-ot-color-sbix-table.hh
+++ b/src/hb-ot-color-sbix-table.hh
@@ -27,7 +27,7 @@
 
 #include "hb-open-type-private.hh"
 
-#define HB_OT_TAG_SBIX HB_TAG('s','b','i','x')
+#define HB_OT_TAG_sbix HB_TAG('s','b','i','x')
 
 namespace OT {
 
@@ -55,6 +55,8 @@ struct SBIXGlyph
 
 struct SBIXStrike
 {
+  friend struct sbix;
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -77,22 +79,12 @@ struct SBIXStrike
 
 /*
  * sbix -- Standard Bitmap Graphics Table
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/sbix
  */
-// It should be called with something like this so it can have
-// access to num_glyph while sanitizing.
-//
-//   static inline const OT::sbix*
-//   _get_sbix (hb_face_t *face)
-//   {
-//     OT::Sanitizer<OT::sbix> sanitizer;
-//     sanitizer.set_num_glyphs (face->get_num_glyphs ());
-//     hb_blob_t *sbix_blob = sanitizer.sanitize (face->reference_table (HB_OT_TAG_SBIX));
-//     return OT::Sanitizer<OT::sbix>::lock_instance (sbix_blob);
-//   }
-//
+
 struct sbix
 {
-  static const hb_tag_t tableTag = HB_OT_TAG_SBIX;
+  static const hb_tag_t tableTag = HB_OT_TAG_sbix;
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -100,21 +92,50 @@ struct sbix
     return_trace (c->check_struct (this) && strikes.sanitize (c, this));
   }
 
-  // inline void dump (unsigned int num_glyphs, unsigned int group) const
-  // {
-  //   const SBIXStrike &strike = strikes[group](this);
-  //   for (unsigned int i = 0; i < num_glyphs; ++i)
-  //     if (strike.imageOffsetsZ[i + 1] - strike.imageOffsetsZ[i] > 0)
-  //     {
-  //       const SBIXGlyph &sbixGlyph = strike.imageOffsetsZ[i]((const void *) &strike);
-  //       char outName[255];
-  //       sprintf (outName, "out/%d-%d.png", group, i);
-  //       FILE *f = fopen (outName, "wb");
-  //       fwrite (sbixGlyph.data, 1,
-  //         strike.imageOffsetsZ[i + 1] - strike.imageOffsetsZ[i] - 8, f);
-  //       fclose (f);
-  //     }
-  // }
+  struct accelerator_t
+  {
+    inline void init (hb_face_t *face)
+    {
+      num_glyphs = hb_face_get_glyph_count (face);
+
+      OT::Sanitizer<OT::sbix> sanitizer;
+      sanitizer.set_num_glyphs (num_glyphs);
+      sbix_blob = sanitizer.sanitize (face->reference_table (HB_OT_TAG_sbix));
+      sbix_len = hb_blob_get_length (sbix_blob);
+      sbix_table = OT::Sanitizer<OT::sbix>::lock_instance (sbix_blob);
+
+    }
+
+    inline void fini (void)
+    {
+      hb_blob_destroy (sbix_blob);
+    }
+
+    inline void dump (void (*callback) (const uint8_t* data, unsigned int length,
+        unsigned int group, unsigned int gid)) const
+    {
+      for (unsigned group = 0; group < sbix_table->strikes.len; ++group)
+      {
+        const SBIXStrike &strike = sbix_table->strikes[group](sbix_table);
+        for (unsigned int glyph = 0; glyph < num_glyphs; ++glyph)
+          if (strike.imageOffsetsZ[glyph + 1] - strike.imageOffsetsZ[glyph] > 0)
+          {
+            const SBIXGlyph &sbixGlyph = strike.imageOffsetsZ[glyph]((const void *) &strike);
+            callback ((const uint8_t*) sbixGlyph.data,
+              strike.imageOffsetsZ[glyph + 1] - strike.imageOffsetsZ[glyph] - 8,
+              group, glyph);
+          }
+      }
+    }
+
+    private:
+    hb_blob_t *sbix_blob;
+    const sbix *sbix_table;
+
+    unsigned int sbix_len;
+    unsigned int num_glyphs;
+
+  };
 
   protected:
   HBUINT16	version;	/* Table version number — set to 1 */
diff --git a/src/hb-ot-color-svg-table.hh b/src/hb-ot-color-svg-table.hh
index 3dc24e99..6d0d9c4f 100644
--- a/src/hb-ot-color-svg-table.hh
+++ b/src/hb-ot-color-svg-table.hh
@@ -39,7 +39,7 @@ namespace OT {
 
 struct SVGDocumentIndexEntry
 {
-  // friend struct SVGDocumentIndex;
+  friend struct SVG;
 
   inline bool sanitize (hb_sanitize_context_t *c, const void* base) const
   {
@@ -64,27 +64,15 @@ struct SVGDocumentIndexEntry
 
 struct SVGDocumentIndex
 {
+  friend struct SVG;
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    // dump ();
     return_trace (c->check_struct (this) &&
       entries.sanitize (c, this));
   }
 
-  // inline void dump () const
-  // {
-  //   for (unsigned int i = 0; i < entries.len; ++i)
-  //   {
-  //     char outName[255];
-  //     sprintf (outName, "out/%d.svg", i);
-  //     const SVGDocumentIndexEntry &entry = entries[i];
-  //     FILE *f = fopen (outName, "wb");
-  //     fwrite (&entry.svgDoc (this), 1, entry.svgDocLength, f);
-  //     fclose (f);
-  //   }
-  // }
-
   protected:
   ArrayOf<SVGDocumentIndexEntry>
     entries;			/* Array of SVG Document Index Entries. */
@@ -100,9 +88,45 @@ struct SVG
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
-      svgDocIndex(this).sanitize (c));
+      svgDocIndex (this).sanitize (c));
   }
 
+  struct accelerator_t
+  {
+    inline void init (hb_face_t *face)
+    {
+      OT::Sanitizer<OT::SVG> sanitizer;
+      svg_blob = sanitizer.sanitize (face->reference_table (HB_OT_TAG_SVG));
+      svg_len = hb_blob_get_length (svg_blob);
+      svg = OT::Sanitizer<OT::SVG>::lock_instance (svg_blob);
+
+    }
+
+    inline void fini (void)
+    {
+      hb_blob_destroy (svg_blob);
+    }
+
+    inline void dump (void (*callback) (const uint8_t* data, unsigned int length,
+        unsigned int start_glyph, unsigned int end_glyph)) const
+    {
+      const SVGDocumentIndex &index = svg->svgDocIndex (svg);
+      const ArrayOf<SVGDocumentIndexEntry> &entries = index.entries;
+      for (unsigned int i = 0; i < entries.len; ++i)
+      {
+        const SVGDocumentIndexEntry &entry = entries[i];
+        callback ((const uint8_t*) &entry.svgDoc (&index), entry.svgDocLength,
+          entry.startGlyphID, entry.endGlyphID);
+      }
+    }
+
+    private:
+    hb_blob_t *svg_blob;
+    const SVG *svg;
+
+    unsigned int svg_len;
+  };
+
   protected:
   HBUINT16	version;	/* Table version (starting at 0). */
   LOffsetTo<SVGDocumentIndex>
commit 430f82817d048ac917f1956e07d9089b9fd7e695
Author: Ebrahim Byagowi <ebrahim at gnu.org>
Date:   Tue Mar 27 13:59:56 2018 +0430

    [ci] Fix coverage build fail (#925)

diff --git a/src/Makefile.am b/src/Makefile.am
index af7a4bdd..2aa3dc4f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -141,10 +141,10 @@ endif
 @CODE_COVERAGE_RULES@
 
 base_link_flags = $(AM_LDFLAGS) -lm -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
-libharfbuzz_la_LINK = $(chosen_linker) $(libharfbuzz_la_LDFLAGS) $(CODE_COVERAGE_LDFLAGS)
+libharfbuzz_la_LINK = $(chosen_linker) $(libharfbuzz_la_LDFLAGS)
 libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS)
 libharfbuzz_la_CPPFLAGS = $(HBCFLAGS) $(CODE_COVERAGE_CFLAGS)
-libharfbuzz_la_LDFLAGS = $(base_link_flags) $(export_symbols)
+libharfbuzz_la_LDFLAGS = $(base_link_flags) $(export_symbols) $(CODE_COVERAGE_LDFLAGS)
 libharfbuzz_la_LIBADD = $(HBLIBS)
 EXTRA_libharfbuzz_la_DEPENDENCIES = $(harfbuzz_def_dependency)
 pkginclude_HEADERS = $(HBHEADERS)
@@ -158,7 +158,7 @@ EXTRA_DIST += harfbuzz.pc.in harfbuzz-config.cmake.in
 lib_LTLIBRARIES += libharfbuzz-subset.la
 libharfbuzz_subset_la_SOURCES = $(HB_SUBSET_sources)
 libharfbuzz_subset_la_CPPFLAGS = $(HBCFLAGS) $(CODE_COVERAGE_CFLAGS)
-libharfbuzz_subset_la_LDFLAGS = $(base_link_flags) $(export_symbols_subset)
+libharfbuzz_subset_la_LDFLAGS = $(base_link_flags) $(export_symbols_subset) $(CODE_COVERAGE_LDFLAGS)
 libharfbuzz_subset_la_LIBADD = libharfbuzz.la
 EXTRA_libharfbuzz_subset_la_DEPENDENCIES = $(harfbuzz_subset_def_dependency)
 pkginclude_HEADERS += $(HB_SUBSET_headers)
@@ -205,8 +205,8 @@ HBHEADERS += $(HB_ICU_headers)
 else
 lib_LTLIBRARIES += libharfbuzz-icu.la
 libharfbuzz_icu_la_SOURCES = $(HB_ICU_sources)
-libharfbuzz_icu_la_CPPFLAGS = $(HBCFLAGS) $(ICU_CFLAGS)  $(CODE_COVERAGE_CFLAGS)
-libharfbuzz_icu_la_LDFLAGS = $(base_link_flags) $(export_symbols_icu)
+libharfbuzz_icu_la_CPPFLAGS = $(HBCFLAGS) $(ICU_CFLAGS) $(CODE_COVERAGE_CFLAGS)
+libharfbuzz_icu_la_LDFLAGS = $(base_link_flags) $(export_symbols_icu) $(CODE_COVERAGE_LDFLAGS)
 libharfbuzz_icu_la_LIBADD = $(ICU_LIBS) libharfbuzz.la
 EXTRA_libharfbuzz_icu_la_DEPENDENCIES = $(harfbuzz_icu_def_dependency)
 pkginclude_HEADERS += $(HB_ICU_headers)
@@ -220,8 +220,8 @@ lib_LTLIBRARIES += libharfbuzz-gobject.la
 libharfbuzz_gobject_la_LINK = $(chosen_linker) $(libharfbuzz_gobject_la_LDFLAGS)
 libharfbuzz_gobject_la_SOURCES = $(HB_GOBJECT_DIST_sources)
 nodist_libharfbuzz_gobject_la_SOURCES = $(HB_GOBJECT_NODIST_sources)
-libharfbuzz_gobject_la_CPPFLAGS = $(HBCFLAGS) $(GOBJECT_CFLAGS) $(CODE_COVERAGE_LDFLAGS)
-libharfbuzz_gobject_la_LDFLAGS = $(base_link_flags)
+libharfbuzz_gobject_la_CPPFLAGS = $(HBCFLAGS) $(GOBJECT_CFLAGS) $(CODE_COVERAGE_CFLAGS)
+libharfbuzz_gobject_la_LDFLAGS = $(base_link_flags) $(CODE_COVERAGE_LDFLAGS)
 libharfbuzz_gobject_la_LIBADD = $(GOBJECT_LIBS) libharfbuzz.la
 EXTRA_libharfbuzz_gobject_la_DEPENDENCIES = $(harfbuzz_gobject_def_dependency)
 pkginclude_HEADERS += $(HB_GOBJECT_DIST_headers)
commit 07851aae9d28fed751663c543799f2b59369f892
Author: Garret Rieger <grieger at google.com>
Date:   Mon Mar 26 20:56:56 2018 -0600

    [subset] Couple of fixes for fuzzer discovered issues. (#924)
    
    * [subset] sanitize individual DeviceRecord's as part of hdmx sanitization.
    
    * [subset] Fix out of bounds read with non-two byte align glyphs.
    
    * [subset] Just use size_device_record >= DeviceRecord::min_size.
    
    * [subset] Add TODO.
    
    * [subset] Re-order checks in hdmx sanitize.

diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh
index 6ad57af2..c0b22b28 100644
--- a/src/hb-ot-hdmx-table.hh
+++ b/src/hb-ot-hdmx-table.hh
@@ -198,6 +198,7 @@ struct hdmx
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && version == 0 &&
 		  !_hb_unsigned_int_mul_overflows (num_records, size_device_record) &&
+		  size_device_record >= DeviceRecord::min_size &&
 		  c->check_range (this, get_size()));
   }
 
diff --git a/src/hb-subset-glyf.cc b/src/hb-subset-glyf.cc
index 1bbcbdcd..b9e6355c 100644
--- a/src/hb-subset-glyf.cc
+++ b/src/hb-subset-glyf.cc
@@ -121,7 +121,6 @@ static void
 _update_components (hb_subset_plan_t * plan,
 		    char * glyph_start,
 		    unsigned int length)
-
 {
   OT::glyf::CompositeGlyphHeader::Iterator iterator;
   if (OT::glyf::CompositeGlyphHeader::get_iterator (glyph_start,
@@ -176,11 +175,11 @@ _write_glyf_and_loca_prime (hb_subset_plan_t              *plan,
     if (unlikely (!(glyf.get_offsets (glyph_ids[i], &start_offset, &end_offset)
                     && glyf.remove_padding(start_offset, &end_offset))))
       end_offset = start_offset = 0;
+
     unsigned int instruction_start = instruction_ranges[i * 2];
     unsigned int instruction_end = instruction_ranges[i * 2 + 1];
 
     int length = end_offset - start_offset - (instruction_end - instruction_start);
-    length += length % 2;
 
     if (glyf_prime_data_next + length > glyf_prime_data + glyf_prime_size)
     {
@@ -214,7 +213,8 @@ _write_glyf_and_loca_prime (hb_subset_plan_t              *plan,
                                             loca_prime_size);
     _update_components (plan, glyf_prime_data_next, length);
 
-    glyf_prime_data_next += length;
+    // TODO: don't align to two bytes if using long loca.
+    glyf_prime_data_next += length + (length % 2); // Align to 2 bytes for short loca.
   }
 
   success = success && _write_loca_entry (glyph_ids.len,
diff --git a/src/hb-subset.cc b/src/hb-subset.cc
index 4062c9b4..2a2f8557 100644
--- a/src/hb-subset.cc
+++ b/src/hb-subset.cc
@@ -89,12 +89,16 @@ _subset (hb_subset_plan_t *plan)
   hb_blob_t *source_blob = sanitizer.sanitize (plan->source->reference_table (TableType::tableTag));
   const TableType *table = OT::Sanitizer<TableType>::lock_instance (source_blob);
 
+  hb_tag_t tag = TableType::tableTag;
   hb_bool_t result = false;
   if (table != &OT::Null(TableType))
+  {
     result = table->subset(plan);
+  } else {
+    DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG(tag));
+  }
 
   hb_blob_destroy (source_blob);
-  hb_tag_t tag = TableType::tableTag;
   DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG(tag), result ? "success" : "FAILED!");
   return result;
 }
diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016 b/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016
new file mode 100644
index 00000000..8c647a8a
Binary files /dev/null and b/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016 differ
diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6651660668502016 b/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6651660668502016
new file mode 100644
index 00000000..6206f077
Binary files /dev/null and b/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6651660668502016 differ
diff --git a/test/api/test-subset-hdmx.c b/test/api/test-subset-hdmx.c
index dd20b2a2..c78009b6 100644
--- a/test/api/test-subset-hdmx.c
+++ b/test/api/test-subset-hdmx.c
@@ -73,6 +73,28 @@ test_subset_hdmx_invalid (void)
 }
 
 static void
+test_subset_hdmx_fails_sanitize (void)
+{
+  hb_face_t *face = hb_subset_test_open_font("fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016");
+
+  hb_subset_input_t *input = hb_subset_input_create_or_fail ();
+  hb_set_t *codepoints = hb_subset_input_unicode_set (input);
+  hb_set_add (codepoints, 'a');
+  hb_set_add (codepoints, 'b');
+  hb_set_add (codepoints, 'c');
+
+  hb_subset_profile_t *profile = hb_subset_profile_create();
+  hb_face_t *subset = hb_subset (face, profile, input);
+  g_assert (subset);
+  g_assert (subset == hb_face_get_empty ());
+
+  hb_subset_input_destroy (input);
+  hb_subset_profile_destroy (profile);
+  hb_face_destroy (subset);
+  hb_face_destroy (face);
+}
+
+static void
 test_subset_hdmx_noop (void)
 {
   hb_face_t *face_abc = hb_subset_test_open_font("fonts/Roboto-Regular.abc.ttf");
@@ -98,6 +120,7 @@ main (int argc, char **argv)
 
   hb_test_add (test_subset_hdmx_simple_subset);
   hb_test_add (test_subset_hdmx_invalid);
+  hb_test_add (test_subset_hdmx_fails_sanitize);
   hb_test_add (test_subset_hdmx_noop);
 
   return hb_test_run();


More information about the HarfBuzz mailing list