freetype-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[freetype2] master 097cd87 1/3: [truetype] Add `HVAR' table parsing.


From: Werner LEMBERG
Subject: [freetype2] master 097cd87 1/3: [truetype] Add `HVAR' table parsing.
Date: Thu, 15 Dec 2016 13:39:17 +0000 (UTC)

branch: master
commit 097cd874ee26ef254e6782b528c460a6f9b7d812
Author: Dave Arnold <address@hidden>
Commit: Werner Lemberg <address@hidden>

    [truetype] Add `HVAR' table parsing.
    
    Note that this is not complete yet; it only handles advance width
    variation.
    
    Activation of the code follows in another commit.
    
    * include/freetype/ftmm.h (FT_Var_Named_Style): Add `psid' member.
    
    * src/truetype/ttgxvar.h (GX_HVarData, GX_AxisCoords, GX_HVarRegion,
    GX_HVStore, GX_WidthMap): New auxiliary structures for...
    (GX_HVarTable): ... HVAR main structure.
    (GX_BlendRec): Add data for HVAR loading.
    
    * src/truetype/ttgxvar.c (FT_FIXED_ONE, FT_fdot14ToFixed,
    FT_intToFixed, FT_fixedToInt): New macros.
    (ft_var_load_hvar): New function.
    (TT_Get_MM_Var): Updated.
    (tt_done_blend): Deallocate HVAR data.
---
 ChangeLog               |   23 +++
 include/freetype/ftmm.h |    1 +
 src/truetype/ttgxvar.c  |  401 ++++++++++++++++++++++++++++++++++++++++++++++-
 src/truetype/ttgxvar.h  |   76 +++++++++
 4 files changed, 498 insertions(+), 3 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index d585d36..26abc08 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,27 @@
 2016-12-15  Dave Arnold  <address@hidden>
+           Werner Lemberg  <address@hidden>
+
+       [truetype] Add `HVAR' table parsing.
+
+       Note that this is not complete yet; it only handles advance width
+       variation.
+
+       Activation of the code follows in another commit.
+
+       * include/freetype/ftmm.h (FT_Var_Named_Style): Add `psid' member.
+
+       * src/truetype/ttgxvar.h (GX_HVarData, GX_AxisCoords, GX_HVarRegion,
+       GX_HVStore, GX_WidthMap): New auxiliary structures for...
+       (GX_HVarTable): ... HVAR main structure.
+       (GX_BlendRec): Add data for HVAR loading.
+
+       * src/truetype/ttgxvar.c (FT_FIXED_ONE, FT_fdot14ToFixed,
+       FT_intToFixed, FT_fixedToInt): New macros.
+       (ft_var_load_hvar): New function.
+       (TT_Get_MM_Var): Updated.
+       (tt_done_blend): Deallocate HVAR data.
+
+2016-12-15  Dave Arnold  <address@hidden>
 
        [cff] Extend number parsing.
 
diff --git a/include/freetype/ftmm.h b/include/freetype/ftmm.h
index 882bdbb..a0238c5 100644
--- a/include/freetype/ftmm.h
+++ b/include/freetype/ftmm.h
@@ -171,6 +171,7 @@ FT_BEGIN_HEADER
   {
     FT_Fixed*  coords;
     FT_UInt    strid;
+    FT_UInt    psid;   /* since 2.7.1 */
 
   } FT_Var_Named_Style;
 
diff --git a/src/truetype/ttgxvar.c b/src/truetype/ttgxvar.c
index 6213bfc..8eb6454 100644
--- a/src/truetype/ttgxvar.c
+++ b/src/truetype/ttgxvar.c
@@ -393,6 +393,361 @@
   }
 
 
+  /* some macros we need */
+  #define FT_FIXED_ONE  ( (FT_Fixed)0x10000 )
+
+  #define FT_fdot14ToFixed( x )                    \
+          ( ( (FT_Fixed)( (FT_Int16)(x) ) ) << 2 )
+  #define FT_intToFixed( i )                     \
+          ( (FT_Fixed)( (FT_UInt32)(i) << 16 ) )
+  #define FT_fixedToInt( x )                                   \
+          ( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) )
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    ft_var_load_hvar                                                   */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Parse the `HVAR' table and set `blend->hvar_loaded' to TRUE.       */
+  /*                                                                       */
+  /*    On success, `blend->hvar_checked' is set to TRUE.                  */
+  /*                                                                       */
+  /*    Some memory may remain allocated on error; it is always freed in   */
+  /*    `tt_done_blend', however.                                          */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    face :: The font face.                                             */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  static FT_Error
+  ft_var_load_hvar( TT_Face  face )
+  {
+    FT_Stream  stream = FT_FACE_STREAM( face );
+    FT_Memory  memory = stream->memory;
+
+    GX_Blend  blend = face->blend;
+
+    FT_Error   error;
+    FT_UShort  majorVersion;
+    FT_UShort  minorVersion;
+    FT_ULong   table_len;
+    FT_ULong   table_offset;
+    FT_ULong   store_offset;
+    FT_ULong   map_offset;
+
+    FT_ULong*  dataOffsetArray = NULL;
+
+
+    blend->hvar_loaded = TRUE;
+
+    FT_TRACE2(( "HVAR " ));
+
+    error = face->goto_table( face, TTAG_HVAR, stream, &table_len );
+    if ( error )
+    {
+      FT_TRACE2(( "is missing\n" ));
+      goto Exit;
+    }
+
+    table_offset = FT_STREAM_POS();
+
+    if ( FT_READ_USHORT( majorVersion ) ||
+         FT_READ_USHORT( minorVersion ) )
+      goto Exit;
+    if ( majorVersion != 1 )
+    {
+      FT_TRACE2(( "bad table version %d\n", majorVersion ));
+      error = FT_THROW( Invalid_Table );
+      goto Exit;
+    }
+
+    if ( FT_READ_ULONG( store_offset ) ||
+         FT_READ_ULONG( map_offset )   )
+      goto Exit;
+
+    /* parse item variation store */
+    {
+      FT_UShort  format;
+      FT_ULong   region_offset;
+      FT_UInt    i, j, k;
+      FT_UInt    shortDeltaCount;
+
+      GX_HVStore    itemStore;
+      GX_HVarTable  hvarTable;
+      GX_HVarData   hvarData;
+
+
+      if ( FT_STREAM_SEEK( table_offset + store_offset ) ||
+           FT_READ_USHORT( format )                      )
+        goto Exit;
+      if ( format != 1 )
+      {
+        FT_TRACE2(( "bad store format %d\n", format ));
+        error = FT_THROW( Invalid_Table );
+        goto Exit;
+      }
+
+      if ( FT_NEW( blend->hvar_table ) )    /* allocate table at top level */
+        goto Exit;
+
+      hvarTable = blend->hvar_table;
+      itemStore = &hvarTable->itemStore;
+
+      /* read top level fields */
+      if ( FT_READ_ULONG( region_offset )         ||
+           FT_READ_USHORT( itemStore->dataCount ) )
+        goto Exit;
+
+      /* make temporary copy of item variation data offsets; */
+      /* we will parse region list first, then come back     */
+      if ( FT_NEW_ARRAY( dataOffsetArray, itemStore->dataCount ) )
+        goto Exit;
+
+      for ( i = 0; i < itemStore->dataCount; i++ )
+      {
+        if ( FT_READ_ULONG( dataOffsetArray[i] ) )
+          goto Exit;
+      }
+
+      /* parse array of region records (region list) */
+      if ( FT_STREAM_SEEK( table_offset + store_offset + region_offset ) )
+        goto Exit;
+
+      if ( FT_READ_USHORT( itemStore->axisCount )   ||
+           FT_READ_USHORT( itemStore->regionCount ) )
+        goto Exit;
+
+      if ( FT_NEW_ARRAY( itemStore->varRegionList, itemStore->regionCount ) )
+        goto Exit;
+
+      for ( i = 0; i < itemStore->regionCount; i++ )
+      {
+        GX_AxisCoords  axisCoords;
+
+
+        if ( FT_NEW_ARRAY( itemStore->varRegionList[i].axisList,
+                           itemStore->axisCount ) )
+          goto Exit;
+
+        axisCoords = itemStore->varRegionList[i].axisList;
+
+        for ( j = 0; j < itemStore->axisCount; j++ )
+        {
+          FT_Short  start, peak, end;
+
+
+          if ( FT_READ_SHORT( start ) ||
+               FT_READ_SHORT( peak )  ||
+               FT_READ_SHORT( end )   )
+            goto Exit;
+
+          axisCoords[j].startCoord = FT_fdot14ToFixed( start );
+          axisCoords[j].peakCoord  = FT_fdot14ToFixed( peak );
+          axisCoords[j].endCoord   = FT_fdot14ToFixed( end );
+        }
+      }
+
+      /* end of region list parse */
+
+      /* use dataOffsetArray now to parse varData items */
+      if ( FT_NEW_ARRAY( itemStore->varData, itemStore->dataCount ) )
+        goto Exit;
+
+      for ( i = 0; i < itemStore->dataCount; i++ )
+      {
+        hvarData = &itemStore->varData[i];
+
+        if ( FT_STREAM_SEEK( table_offset       +
+                             store_offset       +
+                             dataOffsetArray[i] ) )
+          goto Exit;
+
+        if ( FT_READ_USHORT( hvarData->itemCount )      ||
+             FT_READ_USHORT( shortDeltaCount )          ||
+             FT_READ_USHORT( hvarData->regionIdxCount ) )
+          goto Exit;
+
+        /* check some data consistency */
+        if ( shortDeltaCount > hvarData->regionIdxCount )
+        {
+          FT_TRACE2(( "bad short count %d or region count %d\n",
+                      shortDeltaCount,
+                      hvarData->regionIdxCount ));
+          error = FT_THROW( Invalid_Table );
+          goto Exit;
+        }
+
+        if ( hvarData->regionIdxCount > itemStore->regionCount )
+        {
+          FT_TRACE2(( "inconsistent regionCount %d in varData[%d]\n",
+                      hvarData->regionIdxCount,
+                      i ));
+          error = FT_THROW( Invalid_Table );
+          goto Exit;
+        }
+
+        /* parse region indices */
+        if ( FT_NEW_ARRAY( hvarData->regionIndices,
+                           hvarData->regionIdxCount ) )
+          goto Exit;
+
+        for ( j = 0; j < hvarData->regionIdxCount; j++ )
+        {
+          if ( FT_READ_USHORT( hvarData->regionIndices[j] ) )
+            goto Exit;
+
+          if ( hvarData->regionIndices[j] >= itemStore->regionCount )
+          {
+            FT_TRACE2(( "bad region index %d\n",
+                        hvarData->regionIndices[j] ));
+            error = FT_THROW( Invalid_Table );
+            goto Exit;
+          }
+        }
+
+        /* Parse delta set.                                                */
+        /*                                                                 */
+        /* On input, deltas are ( shortDeltaCount + regionIdxCount ) bytes */
+        /* each; on output, deltas are expanded to `regionIdxCount' shorts */
+        /* each.                                                           */
+        if ( FT_NEW_ARRAY( hvarData->deltaSet,
+                           hvarData->regionIdxCount * hvarData->itemCount ) )
+          goto Exit;
+
+        /* the delta set is stored as a 2-dimensional array of shorts; */
+        /* sign-extend signed bytes to signed shorts                   */
+        for ( j = 0; j < hvarData->itemCount * hvarData->regionIdxCount; )
+        {
+          for ( k = 0; k < shortDeltaCount; k++, j++ )
+          {
+            /* read the short deltas */
+            FT_Short  delta;
+
+
+            if ( FT_READ_SHORT( delta ) )
+              goto Exit;
+
+            hvarData->deltaSet[j] = delta;
+          }
+
+          for ( ; k < hvarData->regionIdxCount; k++, j++ )
+          {
+            /* read the (signed) byte deltas */
+            FT_Char  delta;
+
+
+            if ( FT_READ_CHAR( delta ) )
+              goto Exit;
+
+            hvarData->deltaSet[j] = delta;
+          }
+        }
+      }
+    }
+
+    /* end parse item variation store */
+
+    /* parse width map */
+    {
+      GX_WidthMap  widthMap;
+
+      FT_UShort  format;
+      FT_UInt    entrySize;
+      FT_UInt    innerBitCount;
+      FT_UInt    innerIndexMask;
+      FT_UInt    i, j;
+
+
+      widthMap = &blend->hvar_table->widthMap;
+
+      if ( FT_READ_USHORT( format )             ||
+           FT_READ_USHORT( widthMap->mapCount ) )
+        goto Exit;
+
+      if ( format & 0xFFC0 )
+      {
+        FT_TRACE2(( "bad map format %d\n", format ));
+        error = FT_THROW( Invalid_Table );
+        goto Exit;
+      }
+
+      /* bytes per entry: 1, 2, 3, or 4 */
+      entrySize      = ( ( format & 0x0030 ) >> 4 ) + 1;
+      innerBitCount  = ( format & 0x000F ) + 1;
+      innerIndexMask = ( 1 << innerBitCount ) - 1;
+
+      if ( FT_NEW_ARRAY( widthMap->innerIndex, widthMap->mapCount ) )
+        goto Exit;
+
+      if ( FT_NEW_ARRAY( widthMap->outerIndex, widthMap->mapCount ) )
+        goto Exit;
+
+      for ( i = 0; i < widthMap->mapCount; i++ )
+      {
+        FT_UInt  mapData = 0;
+        FT_UInt  outerIndex, innerIndex;
+
+
+        /* read map data one unsigned byte at a time, big endian */
+        for ( j = 0; j < entrySize; j++ )
+        {
+          FT_Byte  data;
+
+
+          if ( FT_READ_BYTE( data ) )
+            goto Exit;
+
+          mapData = ( mapData << 8 ) | data;
+        }
+
+        outerIndex = mapData >> innerBitCount;
+
+        if ( outerIndex >= blend->hvar_table->itemStore.dataCount )
+        {
+          FT_TRACE2(( "outerIndex[%d] == %d out of range\n",
+                      i,
+                      outerIndex ));
+          error = FT_THROW( Invalid_Table );
+          goto Exit;
+        }
+
+        widthMap->outerIndex[i] = outerIndex;
+
+        innerIndex = mapData & innerIndexMask;
+
+        if ( innerIndex >=
+               blend->hvar_table->itemStore.varData[outerIndex].itemCount )
+        {
+          FT_TRACE2(( "innerIndex[%d] == %d out of range\n",
+                      i,
+                      innerIndex ));
+          error = FT_THROW( Invalid_Table );
+            goto Exit;
+        }
+
+        widthMap->innerIndex[i] = innerIndex;
+      }
+    }
+
+    /* end parse width map */
+
+    FT_TRACE2(( "loaded\n" ));
+    error = FT_Err_Ok;
+
+  Exit:
+    FT_FREE( dataOffsetArray );
+
+    if ( !error )
+      blend->hvar_checked = TRUE;
+
+    return error;
+  }
+
+
   typedef struct  GX_GVar_Head_
   {
     FT_Long    version;
@@ -778,6 +1133,7 @@
     FT_Var_Axis*         a;
     FT_Var_Named_Style*  ns;
     GX_FVar_Head         fvar_head;
+    FT_Bool              usePsName;
 
     static const FT_Frame_Field  fvar_fields[] =
     {
@@ -851,8 +1207,6 @@
            fvar_head.axisSize != 20                                       ||
            /* axisCount limit implied by 16-bit instanceSize */
            fvar_head.axisCount > 0x3FFE                                   ||
-           fvar_head.instanceSize != 4 + 4 * fvar_head.axisCount          ||
-           /* instanceCount limit implied by limited range of name IDs */
            fvar_head.instanceCount > 0x7EFF                               ||
            fvar_head.offsetToData + fvar_head.axisCount * 20U +
              fvar_head.instanceCount * fvar_head.instanceSize > table_len )
@@ -863,6 +1217,18 @@
         goto Exit;
       }
 
+      if ( fvar_head.instanceSize == 4 + 4 * fvar_head.axisCount )
+        usePsName = FALSE;
+      else if ( fvar_head.instanceSize == 6 + 4 * fvar_head.axisCount )
+        usePsName = TRUE;
+      else
+      {
+        FT_TRACE1(( "\n"
+                    "TT_Get_MM_Var: invalid `fvar' header\n" ));
+        error = FT_THROW( Invalid_Table );
+        goto Exit;
+      }
+
       FT_TRACE2(( "loaded\n" ));
 
       FT_TRACE5(( "number of GX style axes: %d\n", fvar_head.axisCount ));
@@ -952,7 +1318,9 @@
       ns = mmvar->namedstyle;
       for ( i = 0; i < fvar_head.instanceCount; i++, ns++ )
       {
-        if ( FT_FRAME_ENTER( 4L + 4L * fvar_head.axisCount ) )
+        /* PostScript names add 2 bytes to the instance record size */
+        if ( FT_FRAME_ENTER( ( usePsName ? 6L : 4L ) +
+                             4L * fvar_head.axisCount ) )
           goto Exit;
 
         ns->strid       =    FT_GET_USHORT();
@@ -961,6 +1329,9 @@
         for ( j = 0; j < fvar_head.axisCount; j++ )
           ns->coords[j] = FT_GET_LONG();
 
+        if ( usePsName )
+          ns->psid = FT_GET_USHORT();
+
         FT_FRAME_EXIT();
       }
     }
@@ -2296,6 +2667,30 @@
         FT_FREE( blend->avar_segment );
       }
 
+      if ( blend->hvar_table != NULL )
+      {
+        if ( blend->hvar_table->itemStore.varData )
+        {
+          for ( i = 0; i < blend->hvar_table->itemStore.dataCount; i++ )
+          {
+            FT_FREE( blend->hvar_table->itemStore.varData[i].regionIndices );
+            FT_FREE( blend->hvar_table->itemStore.varData[i].deltaSet );
+          }
+          FT_FREE( blend->hvar_table->itemStore.varData );
+        }
+
+        if ( blend->hvar_table->itemStore.varRegionList )
+        {
+          for ( i = 0; i < blend->hvar_table->itemStore.regionCount; i++ )
+            FT_FREE( blend->hvar_table->itemStore.varRegionList[i].axisList );
+          FT_FREE( blend->hvar_table->itemStore.varRegionList );
+        }
+
+        FT_FREE( blend->hvar_table->widthMap.innerIndex );
+        FT_FREE( blend->hvar_table->widthMap.outerIndex );
+        FT_FREE( blend->hvar_table );
+      }
+
       FT_FREE( blend->tuplecoords );
       FT_FREE( blend->glyphoffsets );
       FT_FREE( blend );
diff --git a/src/truetype/ttgxvar.h b/src/truetype/ttgxvar.h
index 9e4d749..c5c98ea 100644
--- a/src/truetype/ttgxvar.h
+++ b/src/truetype/ttgxvar.h
@@ -61,6 +61,77 @@ FT_BEGIN_HEADER
   } GX_AVarSegmentRec, *GX_AVarSegment;
 
 
+  typedef struct  GX_HVarDataRec_
+  {
+    FT_UInt    itemCount;      /* number of delta sets per item         */
+    FT_UInt    regionIdxCount; /* number of region indices in this data */
+    FT_UInt*   regionIndices;  /* array of `regionCount' indices;       */
+                               /* these index `varRegionList'           */
+    FT_Short*  deltaSet;       /* array of `itemCount' deltas           */
+                               /* use `innerIndex' for this array       */
+
+  } GX_HVarDataRec, *GX_HVarData;
+
+
+  /* contribution of one axis to a region */
+  typedef struct  GX_AxisCoordsRec_
+  {
+    FT_Fixed  startCoord;
+    FT_Fixed  peakCoord;      /* zero means no effect (factor = 1) */
+    FT_Fixed  endCoord;
+
+  } GX_AxisCoordsRec, *GX_AxisCoords;
+
+
+  typedef struct  GX_HVarRegionRec_
+  {
+    GX_AxisCoords  axisList;               /* array of axisCount records */
+
+  } GX_HVarRegionRec, *GX_HVarRegion;
+
+
+  /* HVAR item variation store */
+  typedef struct  GX_HVStoreRec_
+  {
+    FT_UInt        dataCount;
+    GX_HVarData    varData;            /* array of dataCount records;     */
+                                       /* use `outerIndex' for this array */
+    FT_UShort      axisCount;
+    FT_UInt        regionCount;        /* total number of regions defined */
+    GX_HVarRegion  varRegionList;
+
+  } GX_HVStoreRec, *GX_HVStore;
+
+
+  typedef struct  GX_WidthMapRec_
+  {
+    FT_UInt   mapCount;
+    FT_UInt*  outerIndex;             /* indices to item var data */
+    FT_UInt*  innerIndex;             /* indices to delta set     */
+
+  } GX_WidthMapRec, *GX_WidthMap;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Struct>                                                              */
+  /*    GX_HVarTableRec                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Data from the `HVAR' table.                                        */
+  /*                                                                       */
+  typedef struct  GX_HVarTableRec_
+  {
+    GX_HVStoreRec   itemStore;        /* Item Variation Store */
+    GX_WidthMapRec  widthMap;         /* Advance Width Mapping */
+#if 0
+    GX_LSBMap       LsbMap;           /* not implemented */
+    GX_RSBMap       RsbMap;           /* not implemented */
+#endif
+
+  } GX_HVarTableRec, *GX_HVarTable;
+
+
   /*************************************************************************/
   /*                                                                       */
   /* <Struct>                                                              */
@@ -89,6 +160,11 @@ FT_BEGIN_HEADER
     FT_Bool         avar_checked;
     GX_AVarSegment  avar_segment;
 
+    FT_Bool         hvar_loaded;
+    FT_Bool         hvar_checked;
+    FT_Error        hvar_error;
+    GX_HVarTable    hvar_table;
+
     FT_UInt         tuplecount;      /* shared tuples in `gvar'           */
     FT_Fixed*       tuplecoords;     /* tuplecoords[tuplecount][num_axis] */
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]