shithub: freetype+ttf2subf

Download patch

ref: 27fee7f8c6ae75e066b5a23472b33925c6e8b1e0
parent: f27992f295a5f84e9aae45fb07fb649f5d2516f3
author: Werner Lemberg <[email protected]>
date: Mon Mar 6 15:45:44 EST 2017

[sfnt, truetype] Always provide default instance.

As documented in the OpenType specification, an entry for the
default instance may be omitted in the named instance table.  In
particular this means that even if there is no named instance table
in the font we actually do have a named instance, namely the default
instance.

For consistency, we always want the default instance in our list of
named instances.  If it is missing, we try to synthesize it.

* src/sfnt/sfobjs.c (sfnt_init_face): Check whether the default
instance is in the table of named instances.  Otherwise adjust
number of instances.

* src/truetype/ttgxvar.c: Include FT_TRUETYPE_IDS_H.
(TT_Get_MM_Var): Use `face->root.style_flags' as the number of named
instances.
Sythesize a named instance entry if necessary.
(tt_done_blend): Free `normalized_stylecoords'.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2017-03-06  Werner Lemberg  <[email protected]>
+
+	[sfnt, truetype] Always provide default instance.
+
+	As documented in the OpenType specification, an entry for the
+	default instance may be omitted in the named instance table.  In
+	particular this means that even if there is no named instance table
+	in the font we actually do have a named instance, namely the default
+	instance.
+
+	For consistency, we always want the default instance in our list of
+	named instances.  If it is missing, we try to synthesize it.
+
+	* src/sfnt/sfobjs.c (sfnt_init_face): Check whether the default
+	instance is in the table of named instances.  Otherwise adjust
+	number of instances.
+
+	* src/truetype/ttgxvar.c: Include FT_TRUETYPE_IDS_H.
+	(TT_Get_MM_Var): Use `face->root.style_flags' as the number of named
+	instances.
+	Sythesize a named instance entry if necessary.
+	(tt_done_blend): Free `normalized_stylecoords'.
+
 2017-03-05  Werner Lemberg  <[email protected]>
 
 	[sfnt] Remove redundant code.
--- a/src/sfnt/sfobjs.c
+++ b/src/sfnt/sfobjs.c
@@ -856,6 +856,7 @@
                   FT_Parameter*  params )
   {
     FT_Error      error;
+    FT_Memory     memory = face->root.memory;
     FT_Library    library = face->root.driver->root.library;
     SFNT_Service  sfnt;
     FT_Int        face_index;
@@ -954,7 +955,10 @@
 
       FT_Int  instance_index;
 
+      FT_Byte*  default_values  = NULL;
+      FT_Byte*  instance_values = NULL;
 
+
       face->is_default_instance = 1;
 
       instance_index = FT_ABS( face_instance_index ) >> 16;
@@ -998,6 +1002,65 @@
       /* we don't support Multiple Master CFFs yet */
       if ( !face->goto_table( face, TTAG_CFF, stream, 0 ) )
         num_instances = 0;
+
+      /*
+       *  As documented in the OpenType specification, an entry for the
+       *  default instance may be omitted in the named instance table.  In
+       *  particular this means that even if there is no named instance
+       *  table in the font we actually do have a named instance, namely the
+       *  default instance.
+       *
+       *  For consistency, we always want the default instance in our list
+       *  of named instances.  If it is missing, we try to synthesize it
+       *  later on.  Here, we have to adjust `num_instances' accordingly.
+       */
+
+      if ( !( FT_ALLOC( default_values, num_axes * 2 )  ||
+              FT_ALLOC( instance_values, num_axes * 2 ) ) )
+      {
+        /* the current stream position is 16 bytes after the table start */
+        FT_ULong  array_start = FT_STREAM_POS() - 16 + offset;
+        FT_ULong  default_value_offset, instance_offset;
+
+        FT_Byte*  p;
+        FT_UInt   i;
+
+
+        default_value_offset = array_start + 8;
+        p                    = default_values;
+
+        for ( i = 0; i < num_axes; i++ )
+        {
+          (void)FT_STREAM_READ_AT( default_value_offset, p, 2 );
+
+          default_value_offset += axis_size;
+          p                    += 2;
+        }
+
+        instance_offset = array_start + axis_size * num_axes + 4;
+
+        for ( i = 0; i < num_instances; i++ )
+        {
+          (void)FT_STREAM_READ_AT( instance_offset,
+                                   instance_values,
+                                   num_axes * 2 );
+
+          if ( !ft_memcmp( default_values, instance_values, num_axes * 2 ) )
+            break;
+
+          instance_offset += instance_size;
+        }
+
+        if ( i == num_instances )
+        {
+          /* no default instance in named instance table; */
+          /* we thus have to synthesize it                */
+          num_instances++;
+        }
+      }
+
+      FT_FREE( default_values );
+      FT_FREE( instance_values );
 
       /* instance indices in `face_instance_index' start with index 1, */
       /* thus `>' and not `>='                                         */
--- a/src/truetype/ttgxvar.c
+++ b/src/truetype/ttgxvar.c
@@ -45,6 +45,7 @@
 #include FT_INTERNAL_STREAM_H
 #include FT_INTERNAL_SFNT_H
 #include FT_TRUETYPE_TAGS_H
+#include FT_TRUETYPE_IDS_H
 #include FT_MULTIPLE_MASTERS_H
 #include FT_LIST_H
 
@@ -1930,15 +1931,17 @@
     FT_ULong             table_len;
     FT_Error             error  = FT_Err_Ok;
     FT_ULong             fvar_start;
-    FT_Int               i, j;
+    FT_UInt              i, j;
     FT_MM_Var*           mmvar = NULL;
     FT_Fixed*            next_coords;
     FT_Fixed*            nsc;
     FT_String*           next_name;
     FT_Var_Axis*         a;
+    FT_Fixed*            c;
     FT_Var_Named_Style*  ns;
     GX_FVar_Head         fvar_head;
     FT_Bool              usePsName;
+    FT_UInt              num_instances;
 
     static const FT_Frame_Field  fvar_fields[] =
     {
@@ -2019,12 +2022,18 @@
       if ( FT_NEW( face->blend ) )
         goto Exit;
 
-      /* cannot overflow 32-bit arithmetic because of the validity check */
+      /* `num_instances' holds the number of all named instances, */
+      /* including the default instance which might be missing    */
+      /* in fvar's table of named instances                       */
+      num_instances = face->root.style_flags >> 16;
+
+      /* cannot overflow 32-bit arithmetic because of the size limits */
+      /* used in the `fvar' table validity check in `sfnt_init_face'  */
       face->blend->mmvar_len =
         sizeof ( FT_MM_Var ) +
         fvar_head.axisCount * sizeof ( FT_Var_Axis ) +
-        fvar_head.instanceCount * sizeof ( FT_Var_Named_Style ) +
-        fvar_head.instanceCount * fvar_head.axisCount * sizeof ( FT_Fixed ) +
+        num_instances * sizeof ( FT_Var_Named_Style ) +
+        num_instances * fvar_head.axisCount * sizeof ( FT_Fixed ) +
         5 * fvar_head.axisCount;
 
       if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
@@ -2041,7 +2050,7 @@
                                /* may have a different number of designs  */
                                /* (or tuples, as called by Apple)         */
       mmvar->num_namedstyles =
-        fvar_head.instanceCount;
+        num_instances;
       mmvar->axis =
         (FT_Var_Axis*)&( mmvar[1] );
       mmvar->namedstyle =
@@ -2048,8 +2057,8 @@
         (FT_Var_Named_Style*)&( mmvar->axis[fvar_head.axisCount] );
 
       next_coords =
-        (FT_Fixed*)&( mmvar->namedstyle[fvar_head.instanceCount] );
-      for ( i = 0; i < fvar_head.instanceCount; i++ )
+        (FT_Fixed*)&( mmvar->namedstyle[num_instances] );
+      for ( i = 0; i < num_instances; i++ )
       {
         mmvar->namedstyle[i].coords  = next_coords;
         next_coords                 += fvar_head.axisCount;
@@ -2109,17 +2118,14 @@
 
       FT_TRACE5(( "\n" ));
 
-      if ( fvar_head.instanceCount )
-      {
-        /* named instance coordinates are stored as design coordinates; */
-        /* we have to convert them to normalized coordinates also       */
-        if ( FT_NEW_ARRAY( face->blend->normalized_stylecoords,
-                           fvar_head.axisCount * fvar_head.instanceCount ) )
-          goto Exit;
+      /* named instance coordinates are stored as design coordinates; */
+      /* we have to convert them to normalized coordinates also       */
+      if ( FT_NEW_ARRAY( face->blend->normalized_stylecoords,
+                         fvar_head.axisCount * num_instances ) )
+        goto Exit;
 
-        if ( !face->blend->avar_checked )
-          ft_var_load_avar( face );
-      }
+      if ( fvar_head.instanceCount && !face->blend->avar_checked )
+        ft_var_load_avar( face );
 
       ns  = mmvar->namedstyle;
       nsc = face->blend->normalized_stylecoords;
@@ -2133,8 +2139,9 @@
         ns->strid       =    FT_GET_USHORT();
         (void) /* flags = */ FT_GET_USHORT();
 
-        for ( j = 0; j < fvar_head.axisCount; j++ )
-          ns->coords[j] = FT_GET_LONG();
+        c = ns->coords;
+        for ( j = 0; j < fvar_head.axisCount; j++, c++ )
+          *c = FT_GET_LONG();
 
         if ( usePsName )
           ns->psid = FT_GET_USHORT();
@@ -2148,6 +2155,55 @@
         FT_FRAME_EXIT();
       }
 
+      if ( num_instances != fvar_head.instanceCount )
+      {
+        SFNT_Service  sfnt = (SFNT_Service)face->sfnt;
+
+        FT_Int  found, win, apple;
+
+
+        /* the default instance is missing in array the   */
+        /* of named instances; try to synthesize an entry */
+        found = sfnt->get_name_id( face,
+                                   TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY,
+                                   &win,
+                                   &apple );
+        if ( !found )
+          found = sfnt->get_name_id( face,
+                                     TT_NAME_ID_FONT_SUBFAMILY,
+                                     &win,
+                                     &apple );
+
+        if ( found )
+        {
+          FT_Int  strid = win >= 0 ? win : apple;
+
+
+          found = sfnt->get_name_id( face,
+                                     TT_NAME_ID_PS_NAME,
+                                     &win,
+                                     &apple );
+          if ( found )
+          {
+            FT_Int  psid = win >= 0 ? win : apple;
+
+
+            FT_TRACE5(( "TT_Get_MM_Var:"
+                        " Adding default instance to named instances\n" ));
+
+            ns = &mmvar->namedstyle[fvar_head.instanceCount];
+
+            ns->strid = strid;
+            ns->psid  = psid;
+
+            a = mmvar->axis;
+            c = ns->coords;
+            for ( j = 0; j < fvar_head.axisCount; j++, a++, c++ )
+              *c = a->def;
+          }
+        }
+      }
+
       ft_var_load_mvar( face );
     }
 
@@ -3528,6 +3584,7 @@
       num_axes = blend->mmvar->num_axis;
 
       FT_FREE( blend->normalizedcoords );
+      FT_FREE( blend->normalized_stylecoords );
       FT_FREE( blend->mmvar );
 
       if ( blend->avar_segment )