Commit 5367e0ca016bc79096cb3b57217fc1326dc3b997

Nikhil Ramakrishnan 2019-08-05T01:53:00

[sfnt] Support `face->num_faces' for WOFF2 fonts. Set correct value of `face->num_faces' for WOFF2 fonts. This is being handled separately because we only load the tables for the requested font face in `woff2_open_font' and create a single-face sfnt stream. The full discussion is at: https://lists.gnu.org/archive/html/freetype-devel/2019-08/msg00000.html * src/sfnt/sfobjs.c (sfnt_open_font): Add parameter `woff2_num_faces'. (sfnt_init_face): Introduce variable `woff2_num_faces', and change `face->root.num_faces' if `woff2_num_faces' is set. * src/sfnt/sfwoff2.c (woff2_open_font): Validate requested face index and handle negative face indices. * src/sfnt/sfwoff2.h (woff2_open_font): Add parameter `num_faces' to declaration.

diff --git a/ChangeLog b/ChangeLog
index 52087be..1a3e190 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,29 @@
 2019-08-27  Nikhil Ramakrishnan  <ramakrishnan.nikhil@gmail.com>
 
+	[sfnt] Support `face->num_faces' for WOFF2 fonts.
+
+	Set correct value of `face->num_faces' for WOFF2 fonts.  This is
+	being handled separately because we only load the tables for the
+	requested font face in `woff2_open_font' and create a single-face
+	sfnt stream.
+
+	The full discussion is at:
+
+	  https://lists.gnu.org/archive/html/freetype-devel/2019-08/msg00000.html
+
+	* src/sfnt/sfobjs.c (sfnt_open_font): Add parameter
+	`woff2_num_faces'.
+	(sfnt_init_face): Introduce variable `woff2_num_faces', and change
+	`face->root.num_faces' if `woff2_num_faces' is set.
+
+	* src/sfnt/sfwoff2.c (woff2_open_font): Validate requested face
+	index and handle negative face indices.
+
+	* src/sfnt/sfwoff2.h (woff2_open_font): Add parameter `num_faces' to
+	declaration.
+
+2019-08-27  Nikhil Ramakrishnan  <ramakrishnan.nikhil@gmail.com>
+
 	[woff2] Improve memory and error handling.
 
 	Free up memory after use, and improve error handling.
diff --git a/src/sfnt/sfobjs.c b/src/sfnt/sfobjs.c
index 7fe25ac..f6da955 100644
--- a/src/sfnt/sfobjs.c
+++ b/src/sfnt/sfobjs.c
@@ -343,7 +343,8 @@
   static FT_Error
   sfnt_open_font( FT_Stream  stream,
                   TT_Face    face,
-                  FT_Int*    face_instance_index )
+                  FT_Int*    face_instance_index,
+                  FT_Long*   woff2_num_faces )
   {
     FT_Memory  memory = stream->memory;
     FT_Error   error;
@@ -394,7 +395,10 @@
       if ( FT_STREAM_SEEK( offset ) )
         return error;
 
-      error = woff2_open_font( stream, face, face_instance_index );
+      error = woff2_open_font( stream,
+                               face,
+                               face_instance_index,
+                               woff2_num_faces );
       if ( error )
         return error;
 
@@ -479,9 +483,10 @@
                   FT_Parameter*  params )
   {
     FT_Error      error;
-    FT_Library    library = face->root.driver->root.library;
+    FT_Library    library         = face->root.driver->root.library;
     SFNT_Service  sfnt;
     FT_Int        face_index;
+    FT_Long       woff2_num_faces = 0;
 
 
     /* for now, parameters are unused */
@@ -532,7 +537,10 @@
 
     FT_TRACE2(( "SFNT driver\n" ));
 
-    error = sfnt_open_font( stream, face, &face_instance_index );
+    error = sfnt_open_font( stream,
+                            face,
+                            &face_instance_index,
+                            &woff2_num_faces );
     if ( error )
       return error;
 
@@ -707,6 +715,10 @@
     face->root.num_faces  = face->ttc_header.count;
     face->root.face_index = face_instance_index;
 
+    /* `num_faces' for a WOFF2 needs to be handled separately. */
+    if( woff2_num_faces )
+      face->root.num_faces = woff2_num_faces;
+
     return error;
   }
 
diff --git a/src/sfnt/sfwoff2.c b/src/sfnt/sfwoff2.c
index cda2b59..cbdaa8b 100644
--- a/src/sfnt/sfwoff2.c
+++ b/src/sfnt/sfwoff2.c
@@ -1535,11 +1535,12 @@
   FT_LOCAL_DEF( FT_Error )
   woff2_open_font( FT_Stream  stream,
                    TT_Face    face,
-                   FT_Int*    face_instance_index )
+                   FT_Int*    face_instance_index,
+                   FT_Long*   num_faces )
   {
     FT_Memory        memory     = stream->memory;
     FT_Error         error      = FT_Err_Ok;
-    FT_Int           face_index = *face_instance_index;
+    FT_Int           face_index;
 
     WOFF2_HeaderRec  woff2;
     WOFF2_InfoRec    info;
@@ -1594,6 +1595,7 @@
     FT_ASSERT( stream == face->root.stream );
     FT_ASSERT( FT_STREAM_POS() == 0 );
 
+    face_index = FT_ABS( *face_instance_index ) & 0xFFFF;
     /* DEBUG - Remove later. */
     FT_TRACE2(( "Face index = %ld\n", face_index ));
 
@@ -1734,6 +1736,7 @@
     FT_TRACE2(( "Table directory successfully parsed.\n" ));
 
     /* Check for and read collection directory. */
+    woff2.num_fonts      = 1;
     woff2.header_version = 0;
     if( woff2.flavor == TTAG_ttcf ){
       FT_TRACE2(( "Font is a TTC, reading collection directory.\n" ));
@@ -1848,12 +1851,28 @@
       goto Exit;
     }
 
+    /* Validate requested face index. */
+    *num_faces = woff2.num_fonts;
+    /* value -(N+1) requests information on index N */
+    if ( *face_instance_index < 0 )
+      face_index--;
+
+    if( face_index >= woff2.num_fonts )
+    {
+      if ( *face_instance_index >= 0 )
+      {
+        error = FT_THROW( Invalid_Argument );
+        goto Exit;
+      }
+      else
+        face_index = 0;
+    }
+
     /* Only retain tables of the requested face in a TTC. */
-    /* TODO Check whether it is OK for rest of the code to be unaware of the
-       fact that we're working with a TTC. */
     if( woff2.header_version )
     {
       WOFF2_TtcFont  ttc_font = woff2.ttc_fonts + face_index;
+
       /* Create a temporary array. */
       if( FT_NEW_ARRAY( temp_indices,
                         ttc_font->num_tables ) )
@@ -1989,8 +2008,11 @@
 
     face->root.face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
 
-    /* Set face_index to 0. */
-    *face_instance_index = 0;
+    /* Set face_index. */
+    if( *face_instance_index < 0 )
+      *face_instance_index = -1;
+    else
+      *face_instance_index = 0;
 
     /* error = FT_THROW( Unimplemented_Feature ); */
     /* DEBUG - Remove later */
diff --git a/src/sfnt/sfwoff2.h b/src/sfnt/sfwoff2.h
index b4f1ac5..b1d46ad 100644
--- a/src/sfnt/sfwoff2.h
+++ b/src/sfnt/sfwoff2.h
@@ -64,7 +64,8 @@ FT_BEGIN_HEADER
   FT_LOCAL( FT_Error )
   woff2_open_font( FT_Stream  stream,
                    TT_Face    face,
-                   FT_Int*    face_index );
+                   FT_Int*    face_index,
+                   FT_Long*   num_faces );
 
 
 FT_END_HEADER