Commit a960be9e5e9846e1e4e8d2254e0b405fbf84346b

Ben Wagner 2022-03-18T17:41:01

[woff2] Support overlap flag for simple glyphs. In the woff2 spec it has been proposed to allow the OVERLAP_SIMPLE flag to be retained through the woff2 format [0]. [0] https://www.w3.org/TR/WOFF2/#glyf_table_format * src/sfnt/sfwoff2.h (GLYF_OVERLAP_SIMPLE): add glyf flag. * src/sfnt/sfwoff2.c (reconstruct_glyf): parse optionFlags and overlapSimpleBitmap[]. (store_points): set OVERLAP_SIMPLE on first point's flag if the overlap bit is set.

diff --git a/src/sfnt/sfwoff2.c b/src/sfnt/sfwoff2.c
index 165b875..4939647 100644
--- a/src/sfnt/sfwoff2.c
+++ b/src/sfnt/sfwoff2.c
@@ -84,6 +84,8 @@
 #define BBOX_STREAM         5
 #define INSTRUCTION_STREAM  6
 
+#define HAVE_OVERLAP_SIMPLE_BITMAP  0x1
+
 
   static void
   stream_close( FT_Stream  stream )
@@ -522,6 +524,7 @@
                 const WOFF2_Point  points,
                 FT_UShort          n_contours,
                 FT_UShort          instruction_len,
+                FT_Bool            have_overlap,
                 FT_Byte*           dst,
                 FT_ULong           dst_size,
                 FT_ULong*          glyph_size )
@@ -549,6 +552,9 @@
       FT_Int   dy   = point.y - last_y;
 
 
+      if ( i == 0 && have_overlap )
+        flag |= GLYF_OVERLAP_SIMPLE;
+
       if ( dx == 0 )
         flag |= GLYF_THIS_X_IS_SAME;
       else if ( dx > -256 && dx < 256 )
@@ -833,15 +839,18 @@
 
     FT_UInt  num_substreams = 7;
 
+    FT_UShort  option_flags;
     FT_UShort  num_glyphs;
     FT_UShort  index_format;
     FT_ULong   expected_loca_length;
     FT_UInt    offset;
     FT_UInt    i;
     FT_ULong   points_size;
-    FT_ULong   bitmap_length;
     FT_ULong   glyph_buf_size;
     FT_ULong   bbox_bitmap_offset;
+    FT_ULong   bbox_bitmap_length;
+    FT_ULong   overlap_bitmap_offset = 0;
+    FT_ULong   overlap_bitmap_length = 0;
 
     const FT_ULong  glyf_start  = *out_offset;
     FT_ULong        dest_offset = *out_offset;
@@ -857,15 +866,17 @@
     if ( FT_NEW_ARRAY( substreams, num_substreams ) )
       goto Fail;
 
-    if ( FT_STREAM_SKIP( 4 ) )
+    if ( FT_STREAM_SKIP( 2 ) )
+      goto Fail;
+    if ( FT_READ_USHORT( option_flags ) )
       goto Fail;
     if ( FT_READ_USHORT( num_glyphs ) )
       goto Fail;
     if ( FT_READ_USHORT( index_format ) )
       goto Fail;
 
-    FT_TRACE4(( "num_glyphs = %u; index_format = %u\n",
-                num_glyphs, index_format ));
+    FT_TRACE4(( "option_flags = %u; num_glyphs = %u; index_format = %u\n",
+                option_flags, num_glyphs, index_format ));
 
     info->num_glyphs = num_glyphs;
 
@@ -878,7 +889,7 @@
     if ( info->loca_table->dst_length != expected_loca_length )
       goto Fail;
 
-    offset = ( 2 + num_substreams ) * 4;
+    offset = 2 + 2 + 2 + 2 + ( num_substreams * 4 );
     if ( offset > info->glyf_table->TransformLength )
       goto Fail;
 
@@ -901,6 +912,20 @@
       offset += substream_size;
     }
 
+    if ( option_flags & HAVE_OVERLAP_SIMPLE_BITMAP )
+    {
+      /* Size of overlapBitmap = floor((numGlyphs + 7) / 8) */
+      overlap_bitmap_length = ( num_glyphs + 7U ) >> 3;
+      if ( overlap_bitmap_length > info->glyf_table->TransformLength - offset )
+        goto Fail;
+
+      overlap_bitmap_offset = pos + offset;
+
+      FT_TRACE5(( "  Overlap bitmap: offset = %lu; size = %lu;\n",
+                  overlap_bitmap_offset, overlap_bitmap_length ));
+      offset += overlap_bitmap_length;
+    }
+
     if ( FT_NEW_ARRAY( loca_values, num_glyphs + 1 ) )
       goto Fail;
 
@@ -908,8 +933,9 @@
     bbox_bitmap_offset = substreams[BBOX_STREAM].offset;
 
     /* Size of bboxBitmap = 4 * floor((numGlyphs + 31) / 32) */
-    bitmap_length                   = ( ( num_glyphs + 31U ) >> 5 ) << 2;
-    substreams[BBOX_STREAM].offset += bitmap_length;
+    bbox_bitmap_length              = ( ( num_glyphs + 31U ) >> 5 ) << 2;
+    /* bboxStreamSize is the combined size of bboxBitmap and bboxStream. */
+    substreams[BBOX_STREAM].offset += bbox_bitmap_length;
 
     glyph_buf_size = WOFF2_DEFAULT_GLYPH_BUF;
     if ( FT_NEW_ARRAY( glyph_buf, glyph_buf_size ) )
@@ -1025,8 +1051,11 @@
         FT_ULong   flag_size;
         FT_ULong   triplet_size;
         FT_ULong   triplet_bytes_used;
-        FT_Byte*   flags_buf   = NULL;
-        FT_Byte*   triplet_buf = NULL;
+        FT_Bool    have_overlap  = FALSE;
+        FT_Byte    overlap_bitmap;
+        FT_ULong   overlap_offset;
+        FT_Byte*   flags_buf     = NULL;
+        FT_Byte*   triplet_buf   = NULL;
         FT_UShort  instruction_size;
         FT_ULong   size_needed;
         FT_Int     end_point;
@@ -1035,6 +1064,17 @@
         FT_Byte*   pointer = NULL;
 
 
+        /* Set `have_overlap`. */
+        if ( overlap_bitmap_offset )
+        {
+          overlap_offset = overlap_bitmap_offset + ( i >> 3 );
+          if ( FT_STREAM_SEEK( overlap_offset ) ||
+               FT_READ_BYTE( overlap_bitmap )   )
+            goto Fail;
+          if ( overlap_bitmap & ( 0x80 >> ( i & 7 ) ) )
+            have_overlap = TRUE;
+        }
+
         if ( FT_NEW_ARRAY( n_points_arr, n_contours ) )
           goto Fail;
 
@@ -1155,6 +1195,7 @@
                            points,
                            n_contours,
                            instruction_size,
+                           have_overlap,
                            glyph_buf,
                            glyph_buf_size,
                            &glyph_size ) )
diff --git a/src/sfnt/sfwoff2.h b/src/sfnt/sfwoff2.h
index 51b2740..e84982e 100644
--- a/src/sfnt/sfwoff2.h
+++ b/src/sfnt/sfwoff2.h
@@ -56,6 +56,7 @@ FT_BEGIN_HEADER
 #define GLYF_REPEAT          1 << 3
 #define GLYF_THIS_X_IS_SAME  1 << 4
 #define GLYF_THIS_Y_IS_SAME  1 << 5
+#define GLYF_OVERLAP_SIMPLE  1 << 6
 
   /* Other constants */
 #define CONTOUR_OFFSET_END_POINT  10