< prev index next >

src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c

Print this page


   1 /***************************************************************************/
   2 /*                                                                         */
   3 /*  ttgxvar.c                                                              */
   4 /*                                                                         */
   5 /*    TrueType GX Font Variation loader                                    */
   6 /*                                                                         */
   7 /*  Copyright 2004-2018 by                                                 */
   8 /*  David Turner, Robert Wilhelm, Werner Lemberg, and George Williams.     */
   9 /*                                                                         */
  10 /*  This file is part of the FreeType project, and may only be used,       */
  11 /*  modified, and distributed under the terms of the FreeType project      */
  12 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
  13 /*  this file you indicate that you have read the license and              */
  14 /*  understand and accept it fully.                                        */
  15 /*                                                                         */
  16 /***************************************************************************/
  17 
  18 
  19   /*************************************************************************/
  20   /*                                                                       */
  21   /* Apple documents the `fvar', `gvar', `cvar', and `avar' tables at      */
  22   /*                                                                       */
  23   /*   https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6[fgca]var.html */
  24   /*                                                                       */
  25   /* The documentation for `gvar' is not intelligible; `cvar' refers you   */
  26   /* to `gvar' and is thus also incomprehensible.                          */
  27   /*                                                                       */
  28   /* The documentation for `avar' appears correct, but Apple has no fonts  */
  29   /* with an `avar' table, so it is hard to test.                          */
  30   /*                                                                       */
  31   /* Many thanks to John Jenkins (at Apple) in figuring this out.          */
  32   /*                                                                       */
  33   /*                                                                       */
  34   /* Apple's `kern' table has some references to tuple indices, but as     */
  35   /* there is no indication where these indices are defined, nor how to    */
  36   /* interpolate the kerning values (different tuples have different       */
  37   /* classes) this issue is ignored.                                       */
  38   /*                                                                       */
  39   /*************************************************************************/
  40 
  41 
  42 #include <ft2build.h>
  43 #include FT_INTERNAL_DEBUG_H
  44 #include FT_CONFIG_CONFIG_H
  45 #include FT_INTERNAL_STREAM_H
  46 #include FT_INTERNAL_SFNT_H
  47 #include FT_TRUETYPE_TAGS_H
  48 #include FT_TRUETYPE_IDS_H
  49 #include FT_MULTIPLE_MASTERS_H
  50 #include FT_LIST_H
  51 
  52 #include "ttpload.h"
  53 #include "ttgxvar.h"
  54 
  55 #include "tterrors.h"
  56 
  57 
  58 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
  59 
  60 
  61 #define FT_Stream_FTell( stream )                         \
  62           (FT_ULong)( (stream)->cursor - (stream)->base )
  63 #define FT_Stream_SeekSet( stream, off )                               \
  64           (stream)->cursor =                                           \
  65             ( (off) < (FT_ULong)( (stream)->limit - (stream)->base ) ) \
  66                         ? (stream)->base + (off)                       \
  67                         : (stream)->limit
  68 
  69 
  70   /*************************************************************************/
  71   /*                                                                       */
  72   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  73   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
  74   /* messages during execution.                                            */
  75   /*                                                                       */









  76 #undef  FT_COMPONENT
  77 #define FT_COMPONENT  trace_ttgxvar
  78 
  79 
  80   /*************************************************************************/
  81   /*************************************************************************/
  82   /*****                                                               *****/
  83   /*****                       Internal Routines                       *****/
  84   /*****                                                               *****/
  85   /*************************************************************************/
  86   /*************************************************************************/
  87 
  88 
  89   /*************************************************************************/
  90   /*                                                                       */
  91   /* The macro ALL_POINTS is used in `ft_var_readpackedpoints'.  It        */
  92   /* indicates that there is a delta for every point without needing to    */
  93   /* enumerate all of them.                                                */
  94   /*                                                                       */
  95 
  96   /* ensure that value `0' has the same width as a pointer */
  97 #define ALL_POINTS  (FT_UShort*)~(FT_PtrDist)0
  98 
  99 
 100 #define GX_PT_POINTS_ARE_WORDS      0x80U
 101 #define GX_PT_POINT_RUN_COUNT_MASK  0x7FU
 102 
 103 
 104   /*************************************************************************/
 105   /*                                                                       */
 106   /* <Function>                                                            */
 107   /*    ft_var_readpackedpoints                                            */
 108   /*                                                                       */
 109   /* <Description>                                                         */
 110   /*    Read a set of points to which the following deltas will apply.     */
 111   /*    Points are packed with a run length encoding.                      */
 112   /*                                                                       */
 113   /* <Input>                                                               */
 114   /*    stream    :: The data stream.                                      */
 115   /*                                                                       */
 116   /*    size      :: The size of the table holding the data.               */
 117   /*                                                                       */
 118   /* <Output>                                                              */
 119   /*    point_cnt :: The number of points read.  A zero value means that   */
 120   /*                 all points in the glyph will be affected, without     */
 121   /*                 enumerating them individually.                        */
 122   /*                                                                       */
 123   /* <Return>                                                              */
 124   /*    An array of FT_UShort containing the affected points or the        */
 125   /*    special value ALL_POINTS.                                          */
 126   /*                                                                       */



 127   static FT_UShort*
 128   ft_var_readpackedpoints( FT_Stream  stream,
 129                            FT_ULong   size,
 130                            FT_UInt   *point_cnt )
 131   {
 132     FT_UShort *points = NULL;
 133     FT_UInt    n;
 134     FT_UInt    runcnt;
 135     FT_UInt    i, j;
 136     FT_UShort  first;
 137     FT_Memory  memory = stream->memory;
 138     FT_Error   error  = FT_Err_Ok;
 139 
 140     FT_UNUSED( error );
 141 
 142 
 143     *point_cnt = 0;
 144 
 145     n = FT_GET_BYTE();
 146     if ( n == 0 )


 194 
 195         for ( j = 0; j < runcnt; j++ )
 196         {
 197           first      += FT_GET_BYTE();
 198           points[i++] = first;
 199           if ( i >= n )
 200             break;
 201         }
 202       }
 203     }
 204 
 205     return points;
 206   }
 207 
 208 
 209 #define GX_DT_DELTAS_ARE_ZERO       0x80U
 210 #define GX_DT_DELTAS_ARE_WORDS      0x40U
 211 #define GX_DT_DELTA_RUN_COUNT_MASK  0x3FU
 212 
 213 
 214   /*************************************************************************/
 215   /*                                                                       */
 216   /* <Function>                                                            */
 217   /*    ft_var_readpackeddeltas                                            */
 218   /*                                                                       */
 219   /* <Description>                                                         */
 220   /*    Read a set of deltas.  These are packed slightly differently than  */
 221   /*    points.  In particular there is no overall count.                  */
 222   /*                                                                       */
 223   /* <Input>                                                               */
 224   /*    stream    :: The data stream.                                      */
 225   /*                                                                       */
 226   /*    size      :: The size of the table holding the data.               */
 227   /*                                                                       */
 228   /*    delta_cnt :: The number of deltas to be read.                      */
 229   /*                                                                       */
 230   /* <Return>                                                              */
 231   /*    An array of FT_Short containing the deltas for the affected        */
 232   /*    points.  (This only gets the deltas for one dimension.  It will    */
 233   /*    generally be called twice, once for x, once for y.  When used in   */
 234   /*    cvt table, it will only be called once.)                           */
 235   /*                                                                       */
 236   static FT_Short*







 237   ft_var_readpackeddeltas( FT_Stream  stream,
 238                            FT_ULong   size,
 239                            FT_UInt    delta_cnt )
 240   {
 241     FT_Short  *deltas = NULL;
 242     FT_UInt    runcnt, cnt;
 243     FT_UInt    i, j;
 244     FT_Memory  memory = stream->memory;
 245     FT_Error   error  = FT_Err_Ok;
 246 
 247     FT_UNUSED( error );
 248 
 249 
 250     if ( delta_cnt > size )
 251     {
 252       FT_TRACE1(( "ft_var_readpackeddeltas: number of points too large\n" ));
 253       return NULL;
 254     }
 255 
 256     if ( FT_NEW_ARRAY( deltas, delta_cnt ) )
 257       return NULL;
 258 
 259     i = 0;
 260     while ( i < delta_cnt )
 261     {
 262       runcnt = FT_GET_BYTE();
 263       cnt    = runcnt & GX_DT_DELTA_RUN_COUNT_MASK;
 264 
 265       if ( runcnt & GX_DT_DELTAS_ARE_ZERO )
 266       {
 267         /* `runcnt' zeroes get added */
 268         for ( j = 0; j <= cnt && i < delta_cnt; j++ )
 269           deltas[i++] = 0;
 270       }
 271       else if ( runcnt & GX_DT_DELTAS_ARE_WORDS )
 272       {
 273         /* `runcnt' shorts from the stack */
 274         for ( j = 0; j <= cnt && i < delta_cnt; j++ )
 275           deltas[i++] = FT_GET_SHORT();
 276       }
 277       else
 278       {
 279         /* `runcnt' signed bytes from the stack */
 280         for ( j = 0; j <= cnt && i < delta_cnt; j++ )
 281           deltas[i++] = FT_GET_CHAR();
 282       }
 283 
 284       if ( j <= cnt )
 285       {
 286         /* bad format */
 287         FT_FREE( deltas );
 288         return NULL;
 289       }
 290     }
 291 
 292     return deltas;
 293   }
 294 
 295 
 296   /*************************************************************************/
 297   /*                                                                       */
 298   /* <Function>                                                            */
 299   /*    ft_var_load_avar                                                   */
 300   /*                                                                       */
 301   /* <Description>                                                         */
 302   /*    Parse the `avar' table if present.  It need not be, so we return   */
 303   /*    nothing.                                                           */
 304   /*                                                                       */
 305   /* <InOut>                                                               */
 306   /*    face :: The font face.                                             */
 307   /*                                                                       */

 308   static void
 309   ft_var_load_avar( TT_Face  face )
 310   {
 311     FT_Stream       stream = FT_FACE_STREAM( face );
 312     FT_Memory       memory = stream->memory;
 313     GX_Blend        blend  = face->blend;
 314     GX_AVarSegment  segment;
 315     FT_Error        error = FT_Err_Ok;
 316     FT_Long         version;
 317     FT_Long         axisCount;
 318     FT_Int          i, j;
 319     FT_ULong        table_len;
 320 
 321     FT_UNUSED( error );
 322 
 323 
 324     FT_TRACE2(( "AVAR " ));
 325 
 326     blend->avar_loaded = TRUE;
 327     error = face->goto_table( face, TTAG_avar, stream, &table_len );


 377 
 378       for ( j = 0; j < segment->pairCount; j++ )
 379       {
 380         /* convert to Fixed */
 381         segment->correspondence[j].fromCoord = FT_GET_SHORT() * 4;
 382         segment->correspondence[j].toCoord   = FT_GET_SHORT() * 4;
 383 
 384         FT_TRACE5(( "    mapping %.5f to %.5f\n",
 385                     segment->correspondence[j].fromCoord / 65536.0,
 386                     segment->correspondence[j].toCoord / 65536.0 ));
 387       }
 388 
 389       FT_TRACE5(( "\n" ));
 390     }
 391 
 392   Exit:
 393     FT_FRAME_EXIT();
 394   }
 395 
 396 
 397   /* some macros we need */
 398 #define FT_FIXED_ONE  ( (FT_Fixed)0x10000 )
 399 
 400 #define FT_fdot14ToFixed( x )                \
 401         ( (FT_Fixed)( (FT_ULong)(x) << 2 ) )
 402 #define FT_intToFixed( i )                    \
 403         ( (FT_Fixed)( (FT_ULong)(i) << 16 ) )
 404 #define FT_fixedToInt( x )                                   \
 405         ( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) )
 406 
 407 
 408   static FT_Error
 409   ft_var_load_item_variation_store( TT_Face          face,
 410                                     FT_ULong         offset,
 411                                     GX_ItemVarStore  itemStore )
 412   {
 413     FT_Stream  stream = FT_FACE_STREAM( face );
 414     FT_Memory  memory = stream->memory;
 415 
 416     FT_Error   error;
 417     FT_UShort  format;
 418     FT_ULong   region_offset;
 419     FT_UInt    i, j, k;
 420     FT_UInt    shortDeltaCount;
 421 
 422     GX_Blend        blend = face->blend;
 423     GX_ItemVarData  varData;
 424 
 425     FT_ULong*  dataOffsetArray = NULL;
 426 
 427 


 685 
 686       innerIndex = mapData & innerIndexMask;
 687 
 688       if ( innerIndex >= itemStore->varData[outerIndex].itemCount )
 689       {
 690         FT_TRACE2(( "innerIndex[%d] == %d out of range\n",
 691                     i,
 692                     innerIndex ));
 693         error = FT_THROW( Invalid_Table );
 694           goto Exit;
 695       }
 696 
 697       map->innerIndex[i] = innerIndex;
 698     }
 699 
 700   Exit:
 701     return error;
 702   }
 703 
 704 
 705   /*************************************************************************/
 706   /*                                                                       */
 707   /* <Function>                                                            */
 708   /*    ft_var_load_hvvar                                                  */
 709   /*                                                                       */
 710   /* <Description>                                                         */
 711   /*    If `vertical' is zero, parse the `HVAR' table and set              */
 712   /*    `blend->hvar_loaded' to TRUE.  On success, `blend->hvar_checked'   */
 713   /*    is set to TRUE.                                                    */
 714   /*                                                                       */
 715   /*    If `vertical' is not zero, parse the `VVAR' table and set          */
 716   /*    `blend->vvar_loaded' to TRUE.  On success, `blend->vvar_checked'   */
 717   /*    is set to TRUE.                                                    */
 718   /*                                                                       */
 719   /*    Some memory may remain allocated on error; it is always freed in   */
 720   /*    `tt_done_blend', however.                                          */
 721   /*                                                                       */
 722   /* <InOut>                                                               */
 723   /*    face :: The font face.                                             */
 724   /*                                                                       */
 725   /* <Return>                                                              */
 726   /*    FreeType error code.  0 means success.                             */
 727   /*                                                                       */

 728   static FT_Error
 729   ft_var_load_hvvar( TT_Face  face,
 730                      FT_Bool  vertical )
 731   {
 732     FT_Stream  stream = FT_FACE_STREAM( face );
 733     FT_Memory  memory = stream->memory;
 734 
 735     GX_Blend  blend = face->blend;
 736 
 737     GX_HVVarTable  table;
 738 
 739     FT_Error   error;
 740     FT_UShort  majorVersion;
 741     FT_ULong   table_len;
 742     FT_ULong   table_offset;
 743     FT_ULong   store_offset;
 744     FT_ULong   widthMap_offset;
 745 
 746 
 747     if ( vertical )


 855                          FT_UInt          innerIndex )
 856   {
 857     GX_ItemVarData  varData;
 858     FT_Short*       deltaSet;
 859 
 860     FT_UInt   master, j;
 861     FT_Fixed  netAdjustment = 0;     /* accumulated adjustment */
 862     FT_Fixed  scaledDelta;
 863     FT_Fixed  delta;
 864 
 865 
 866     /* See pseudo code from `Font Variations Overview' */
 867     /* in the OpenType specification.                  */
 868 
 869     varData  = &itemStore->varData[outerIndex];
 870     deltaSet = &varData->deltaSet[varData->regionIdxCount * innerIndex];
 871 
 872     /* outer loop steps through master designs to be blended */
 873     for ( master = 0; master < varData->regionIdxCount; master++ )
 874     {
 875       FT_Fixed  scalar      = FT_FIXED_ONE;
 876       FT_UInt   regionIndex = varData->regionIndices[master];
 877 
 878       GX_AxisCoords  axis = itemStore->varRegionList[regionIndex].axisList;
 879 
 880 
 881       /* inner loop steps through axes in this region */
 882       for ( j = 0; j < itemStore->axisCount; j++, axis++ )
 883       {
 884         FT_Fixed  axisScalar;
 885 
 886 
 887         /* compute the scalar contribution of this axis; */
 888         /* ignore invalid ranges                         */
 889         if ( axis->startCoord > axis->peakCoord ||
 890              axis->peakCoord > axis->endCoord   )
 891           axisScalar = FT_FIXED_ONE;
 892 
 893         else if ( axis->startCoord < 0 &&
 894                   axis->endCoord > 0   &&
 895                   axis->peakCoord != 0 )
 896           axisScalar = FT_FIXED_ONE;
 897 
 898         /* peak of 0 means ignore this axis */
 899         else if ( axis->peakCoord == 0 )
 900           axisScalar = FT_FIXED_ONE;
 901 
 902         /* ignore this region if coords are out of range */
 903         else if ( face->blend->normalizedcoords[j] < axis->startCoord ||
 904                   face->blend->normalizedcoords[j] > axis->endCoord   )
 905           axisScalar = 0;
 906 
 907         /* calculate a proportional factor */
 908         else

 909         {
 910           if ( face->blend->normalizedcoords[j] == axis->peakCoord )
 911             axisScalar = FT_FIXED_ONE;



 912           else if ( face->blend->normalizedcoords[j] < axis->peakCoord )
 913             axisScalar =
 914               FT_DivFix( face->blend->normalizedcoords[j] - axis->startCoord,

 915                          axis->peakCoord - axis->startCoord );
 916           else
 917             axisScalar =
 918               FT_DivFix( axis->endCoord - face->blend->normalizedcoords[j],

 919                          axis->endCoord - axis->peakCoord );
 920         }
 921 
 922         /* take product of all the axis scalars */
 923         scalar = FT_MulFix( scalar, axisScalar );
 924 
 925       } /* per-axis loop */
 926 
 927       /* get the scaled delta for this region */
 928       delta       = FT_intToFixed( deltaSet[master] );
 929       scaledDelta = FT_MulFix( scalar, delta );
 930 
 931       /* accumulate the adjustments from each region */
 932       netAdjustment = netAdjustment + scaledDelta;
 933 
 934     } /* per-region loop */
 935 
 936     return FT_fixedToInt( netAdjustment );
 937   }
 938 
 939 
 940   /*************************************************************************/
 941   /*                                                                       */
 942   /* <Function>                                                            */
 943   /*    tt_hvadvance_adjust                                                */
 944   /*                                                                       */
 945   /* <Description>                                                         */
 946   /*    Apply `HVAR' advance width or `VVAR' advance height adjustment of  */
 947   /*    a given glyph.                                                     */
 948   /*                                                                       */
 949   /* <Input>                                                               */
 950   /*    gindex   :: The glyph index.                                       */
 951   /*                                                                       */
 952   /*    vertical :: If set, handle `VVAR' table.                           */
 953   /*                                                                       */
 954   /* <InOut>                                                               */
 955   /*    face     :: The font face.                                         */
 956   /*                                                                       */
 957   /*    adelta   :: Points to width or height value that gets modified.    */
 958   /*                                                                       */




 959   static FT_Error
 960   tt_hvadvance_adjust( TT_Face  face,
 961                        FT_UInt  gindex,
 962                        FT_Int  *avalue,
 963                        FT_Bool  vertical )
 964   {
 965     FT_Error  error = FT_Err_Ok;
 966     FT_UInt   innerIndex, outerIndex;
 967     FT_Int    delta;
 968 
 969     GX_HVVarTable  table;
 970 
 971 
 972     if ( !face->doblend || !face->blend )
 973       goto Exit;
 974 
 975     if ( vertical )
 976     {
 977       if ( !face->blend->vvar_loaded )
 978       {


1134       GX_VALUE_CASE( STRS, os2.yStrikeoutSize );
1135       GX_VALUE_CASE( UNDO, postscript.underlinePosition );
1136       GX_VALUE_CASE( UNDS, postscript.underlineThickness );
1137       GX_VALUE_CASE( VASC, vertical.Ascender );
1138       GX_VALUE_CASE( VCOF, vertical.caret_Offset );
1139       GX_VALUE_CASE( VCRN, vertical.caret_Slope_Run );
1140       GX_VALUE_CASE( VCRS, vertical.caret_Slope_Rise );
1141       GX_VALUE_CASE( VDSC, vertical.Descender );
1142       GX_VALUE_CASE( VLGP, vertical.Line_Gap );
1143       GX_VALUE_CASE( XHGT, os2.sxHeight );
1144 
1145     default:
1146       /* ignore unknown tag */
1147       p = NULL;
1148     }
1149 
1150     return p;
1151   }
1152 
1153 
1154   /*************************************************************************/
1155   /*                                                                       */
1156   /* <Function>                                                            */
1157   /*    ft_var_load_mvar                                                   */
1158   /*                                                                       */
1159   /* <Description>                                                         */
1160   /*    Parse the `MVAR' table.                                            */
1161   /*                                                                       */
1162   /*    Some memory may remain allocated on error; it is always freed in   */
1163   /*    `tt_done_blend', however.                                          */
1164   /*                                                                       */
1165   /* <InOut>                                                               */
1166   /*    face :: The font face.                                             */
1167   /*                                                                       */

1168   static void
1169   ft_var_load_mvar( TT_Face  face )
1170   {
1171     FT_Stream  stream = FT_FACE_STREAM( face );
1172     FT_Memory  memory = stream->memory;
1173 
1174     GX_Blend         blend = face->blend;
1175     GX_ItemVarStore  itemStore;
1176     GX_Value         value, limit;
1177 
1178     FT_Error   error;
1179     FT_UShort  majorVersion;
1180     FT_ULong   table_len;
1181     FT_ULong   table_offset;
1182     FT_UShort  store_offset;
1183     FT_ULong   records_offset;
1184 
1185 
1186     FT_TRACE2(( "MVAR " ));
1187 


1280 
1281     face->variation_support |= TT_FACE_FLAG_VAR_MVAR;
1282   }
1283 
1284 
1285   static FT_Error
1286   tt_size_reset_iterator( FT_ListNode  node,
1287                           void*        user )
1288   {
1289     TT_Size  size = (TT_Size)node->data;
1290 
1291     FT_UNUSED( user );
1292 
1293 
1294     tt_size_reset( size, 1 );
1295 
1296     return FT_Err_Ok;
1297   }
1298 
1299 
1300   /*************************************************************************/
1301   /*                                                                       */
1302   /* <Function>                                                            */
1303   /*    tt_apply_mvar                                                      */
1304   /*                                                                       */
1305   /* <Description>                                                         */
1306   /*    Apply `MVAR' table adjustments.                                    */
1307   /*                                                                       */
1308   /* <InOut>                                                               */
1309   /*    face :: The font face.                                             */
1310   /*                                                                       */

1311   FT_LOCAL_DEF( void )
1312   tt_apply_mvar( TT_Face  face )
1313   {
1314     GX_Blend  blend = face->blend;
1315     GX_Value  value, limit;



1316 
1317 
1318     if ( !( face->variation_support & TT_FACE_FLAG_VAR_MVAR ) )
1319       return;
1320 
1321     value = blend->mvar_table->values;
1322     limit = value + blend->mvar_table->valueCount;
1323 
1324     for ( ; value < limit; value++ )
1325     {
1326       FT_Short*  p = ft_var_get_value_pointer( face, value->tag );
1327       FT_Int     delta;
1328 
1329 
1330       delta = ft_var_get_item_delta( face,
1331                                      &blend->mvar_table->itemStore,
1332                                      value->outerIndex,
1333                                      value->innerIndex );
1334 
1335       if ( p )
1336       {
1337         FT_TRACE5(( "value %c%c%c%c (%d unit%s) adjusted by %d unit%s (MVAR)\n",
1338                     (FT_Char)( value->tag >> 24 ),
1339                     (FT_Char)( value->tag >> 16 ),
1340                     (FT_Char)( value->tag >> 8 ),
1341                     (FT_Char)( value->tag ),
1342                     value->unmodified,
1343                     value->unmodified == 1 ? "" : "s",
1344                     delta,
1345                     delta == 1 ? "" : "s" ));
1346 
1347         /* since we handle both signed and unsigned values as FT_Short, */
1348         /* ensure proper overflow arithmetic                            */
1349         *p = (FT_Short)( value->unmodified + (FT_Short)delta );








1350       }
1351     }
1352 
1353     /* adjust all derived values */
1354     {
1355       FT_Face  root = &face->root;
1356 




























1357 
1358       if ( face->os2.version != 0xFFFFU )
1359       {
1360         if ( face->os2.sTypoAscender || face->os2.sTypoDescender )
1361         {
1362           root->ascender  = face->os2.sTypoAscender;
1363           root->descender = face->os2.sTypoDescender;
1364 


1365           root->height = root->ascender - root->descender +
1366                          face->os2.sTypoLineGap;
1367         }
1368         else
1369         {
1370           root->ascender  =  (FT_Short)face->os2.usWinAscent;
1371           root->descender = -(FT_Short)face->os2.usWinDescent;
1372 
1373           root->height = root->ascender - root->descender;
1374         }
1375       }
1376 
1377       root->underline_position  = face->postscript.underlinePosition -
1378                                   face->postscript.underlineThickness / 2;
1379       root->underline_thickness = face->postscript.underlineThickness;
1380 
1381       /* iterate over all FT_Size objects and call `tt_size_reset' */
1382       /* to propagate the metrics changes                          */
1383       FT_List_Iterate( &root->sizes_list,
1384                        tt_size_reset_iterator,
1385                        NULL );
1386     }
1387   }
1388 
1389 
1390   typedef struct  GX_GVar_Head_
1391   {
1392     FT_Long    version;
1393     FT_UShort  axisCount;
1394     FT_UShort  globalCoordCount;
1395     FT_ULong   offsetToCoord;
1396     FT_UShort  glyphCount;
1397     FT_UShort  flags;
1398     FT_ULong   offsetToData;
1399 
1400   } GX_GVar_Head;
1401 
1402 
1403   /*************************************************************************/
1404   /*                                                                       */
1405   /* <Function>                                                            */
1406   /*    ft_var_load_gvar                                                   */
1407   /*                                                                       */
1408   /* <Description>                                                         */
1409   /*    Parse the `gvar' table if present.  If `fvar' is there, `gvar' had */
1410   /*    better be there too.                                               */
1411   /*                                                                       */
1412   /* <InOut>                                                               */
1413   /*    face :: The font face.                                             */
1414   /*                                                                       */
1415   /* <Return>                                                              */
1416   /*    FreeType error code.  0 means success.                             */
1417   /*                                                                       */

1418   static FT_Error
1419   ft_var_load_gvar( TT_Face  face )
1420   {
1421     FT_Stream     stream = FT_FACE_STREAM( face );
1422     FT_Memory     memory = stream->memory;
1423     GX_Blend      blend  = face->blend;
1424     FT_Error      error;
1425     FT_UInt       i, j;
1426     FT_ULong      table_len;
1427     FT_ULong      gvar_start;
1428     FT_ULong      offsetToData;
1429     GX_GVar_Head  gvar_head;
1430 
1431     static const FT_Frame_Field  gvar_fields[] =
1432     {
1433 
1434 #undef  FT_STRUCTURE
1435 #define FT_STRUCTURE  GX_GVar_Head
1436 
1437       FT_FRAME_START( 20 ),


1495       goto Exit;
1496     }
1497 
1498     FT_TRACE2(( "loaded\n" ));
1499 
1500     blend->gvar_size   = table_len;
1501     blend->tuplecount  = gvar_head.globalCoordCount;
1502     blend->gv_glyphcnt = gvar_head.glyphCount;
1503     offsetToData       = gvar_start + gvar_head.offsetToData;
1504 
1505     FT_TRACE5(( "gvar: there %s %d shared coordinate%s:\n",
1506                 blend->tuplecount == 1 ? "is" : "are",
1507                 blend->tuplecount,
1508                 blend->tuplecount == 1 ? "" : "s" ));
1509 
1510     if ( FT_NEW_ARRAY( blend->glyphoffsets, blend->gv_glyphcnt + 1 ) )
1511       goto Exit;
1512 
1513     if ( gvar_head.flags & 1 )
1514     {



1515       /* long offsets (one more offset than glyphs, to mark size of last) */
1516       if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 4L ) )
1517         goto Exit;
1518 
1519       for ( i = 0; i <= blend->gv_glyphcnt; i++ )

1520         blend->glyphoffsets[i] = offsetToData + FT_GET_ULONG();
1521 
1522       FT_FRAME_EXIT();








1523     }
1524     else
1525     {



1526       /* short offsets (one more offset than glyphs, to mark size of last) */
1527       if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 2L ) )
1528         goto Exit;
1529 
1530       for ( i = 0; i <= blend->gv_glyphcnt; i++ )

1531         blend->glyphoffsets[i] = offsetToData + FT_GET_USHORT() * 2;
1532                                                /* XXX: Undocumented: `*2'! */










1533 
1534       FT_FRAME_EXIT();
1535     }

1536 
1537     if ( blend->tuplecount != 0 )
1538     {
1539       if ( FT_NEW_ARRAY( blend->tuplecoords,
1540                          gvar_head.axisCount * blend->tuplecount ) )
1541         goto Exit;
1542 
1543       if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord )         ||
1544            FT_FRAME_ENTER( blend->tuplecount * gvar_head.axisCount * 2L ) )
1545         goto Exit;
1546 
1547       for ( i = 0; i < blend->tuplecount; i++ )
1548       {
1549         FT_TRACE5(( "  [ " ));
1550         for ( j = 0; j < (FT_UInt)gvar_head.axisCount; j++ )
1551         {
1552           blend->tuplecoords[i * gvar_head.axisCount + j] =
1553             FT_GET_SHORT() * 4;                 /* convert to FT_Fixed */
1554           FT_TRACE5(( "%.5f ",
1555             blend->tuplecoords[i * gvar_head.axisCount + j] / 65536.0 ));
1556         }
1557         FT_TRACE5(( "]\n" ));
1558       }
1559 
1560       FT_TRACE5(( "\n" ));
1561 
1562       FT_FRAME_EXIT();
1563     }
1564 
1565   Exit:
1566     return error;
1567   }
1568 
1569 
1570   /*************************************************************************/
1571   /*                                                                       */
1572   /* <Function>                                                            */
1573   /*    ft_var_apply_tuple                                                 */
1574   /*                                                                       */
1575   /* <Description>                                                         */
1576   /*    Figure out whether a given tuple (design) applies to the current   */
1577   /*    blend, and if so, what is the scaling factor.                      */
1578   /*                                                                       */
1579   /* <Input>                                                               */
1580   /*    blend           :: The current blend of the font.                  */
1581   /*                                                                       */
1582   /*    tupleIndex      :: A flag saying whether this is an intermediate   */
1583   /*                       tuple or not.                                   */
1584   /*                                                                       */
1585   /*    tuple_coords    :: The coordinates of the tuple in normalized axis */
1586   /*                       units.                                          */
1587   /*                                                                       */
1588   /*    im_start_coords :: The initial coordinates where this tuple starts */
1589   /*                       to apply (for intermediate coordinates).        */
1590   /*                                                                       */
1591   /*    im_end_coords   :: The final coordinates after which this tuple no */
1592   /*                       longer applies (for intermediate coordinates).  */
1593   /*                                                                       */
1594   /* <Return>                                                              */
1595   /*    An FT_Fixed value containing the scaling factor.                   */
1596   /*                                                                       */





1597   static FT_Fixed
1598   ft_var_apply_tuple( GX_Blend   blend,
1599                       FT_UShort  tupleIndex,
1600                       FT_Fixed*  tuple_coords,
1601                       FT_Fixed*  im_start_coords,
1602                       FT_Fixed*  im_end_coords )
1603   {
1604     FT_UInt   i;
1605     FT_Fixed  apply = 0x10000L;
1606 
1607 
1608     for ( i = 0; i < blend->num_axis; i++ )
1609     {
1610       FT_TRACE6(( "    axis coordinate %d (%.5f):\n",
1611                   i, blend->normalizedcoords[i] / 65536.0 ));
1612       if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) )
1613         FT_TRACE6(( "      intermediate coordinates %d (%.5f, %.5f):\n",
1614                     i,
1615                     im_start_coords[i] / 65536.0,
1616                     im_end_coords[i] / 65536.0 ));
1617 
1618       /* It's not clear why (for intermediate tuples) we don't need     */
1619       /* to check against start/end -- the documentation says we don't. */
1620       /* Similarly, it's unclear why we don't need to scale along the   */
1621       /* axis.                                                          */
1622 
1623       if ( tuple_coords[i] == 0 )
1624       {
1625         FT_TRACE6(( "      tuple coordinate is zero, ignored\n", i ));
1626         continue;
1627       }
1628 
1629       if ( blend->normalizedcoords[i] == 0 )
1630       {
1631         FT_TRACE6(( "      axis coordinate is zero, stop\n" ));
1632         apply = 0;
1633         break;
1634       }
1635 
1636       if ( blend->normalizedcoords[i] == tuple_coords[i] )
1637       {
1638         FT_TRACE6(( "      tuple coordinate value %.5f fits perfectly\n",
1639                     tuple_coords[i] / 65536.0 ));
1640         /* `apply' does not change */
1641         continue;
1642       }
1643 
1644       if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) )
1645       {
1646         /* not an intermediate tuple */
1647 
1648         if ( blend->normalizedcoords[i] < FT_MIN( 0, tuple_coords[i] ) ||
1649              blend->normalizedcoords[i] > FT_MAX( 0, tuple_coords[i] ) )
1650         {
1651           FT_TRACE6(( "      tuple coordinate value %.5f is exceeded, stop\n",
1652                       tuple_coords[i] / 65536.0 ));
1653           apply = 0;
1654           break;
1655         }
1656 
1657         FT_TRACE6(( "      tuple coordinate value %.5f fits\n",
1658                     tuple_coords[i] / 65536.0 ));
1659         apply = FT_MulDiv( apply,
1660                            blend->normalizedcoords[i],
1661                            tuple_coords[i] );
1662       }
1663       else
1664       {
1665         /* intermediate tuple */
1666 
1667         if ( blend->normalizedcoords[i] < im_start_coords[i] ||
1668              blend->normalizedcoords[i] > im_end_coords[i]   )
1669         {
1670           FT_TRACE6(( "      intermediate tuple range [%.5f;%.5f] is exceeded,"
1671                       " stop\n",
1672                       im_start_coords[i] / 65536.0,
1673                       im_end_coords[i] / 65536.0 ));
1674           apply = 0;
1675           break;
1676         }
1677 
1678         else if ( blend->normalizedcoords[i] < tuple_coords[i] )
1679         {
1680           FT_TRACE6(( "      intermediate tuple range [%.5f;%.5f] fits\n",
1681                       im_start_coords[i] / 65536.0,
1682                       im_end_coords[i] / 65536.0 ));

1683           apply = FT_MulDiv( apply,
1684                              blend->normalizedcoords[i] - im_start_coords[i],
1685                              tuple_coords[i] - im_start_coords[i] );
1686         }
1687 
1688         else
1689         {
1690           FT_TRACE6(( "      intermediate tuple range [%.5f;%.5f] fits\n",
1691                       im_start_coords[i] / 65536.0,
1692                       im_end_coords[i] / 65536.0 ));
1693           apply = FT_MulDiv( apply,
1694                              im_end_coords[i] - blend->normalizedcoords[i],
1695                              im_end_coords[i] - tuple_coords[i] );
1696         }
1697       }
1698     }
1699 
1700     FT_TRACE6(( "    apply factor is %.5f\n", apply / 65536.0 ));
1701 
1702     return apply;
1703   }
1704 
1705 
1706   /* convert from design coordinates to normalized coordinates */
1707 
1708   static void
1709   ft_var_to_normalized( TT_Face    face,
1710                         FT_UInt    num_coords,
1711                         FT_Fixed*  coords,
1712                         FT_Fixed*  normalized )
1713   {
1714     GX_Blend        blend;
1715     FT_MM_Var*      mmvar;
1716     FT_UInt         i, j;
1717     FT_Var_Axis*    a;
1718     GX_AVarSegment  av;


1739       FT_Fixed  coord = coords[i];
1740 
1741 
1742       FT_TRACE5(( "    %d: %.5f\n", i, coord / 65536.0 ));
1743       if ( coord > a->maximum || coord < a->minimum )
1744       {
1745         FT_TRACE1((
1746           "ft_var_to_normalized: design coordinate %.5f\n"
1747           "                      is out of range [%.5f;%.5f]; clamping\n",
1748           coord / 65536.0,
1749           a->minimum / 65536.0,
1750           a->maximum / 65536.0 ));
1751 
1752         if ( coord > a->maximum )
1753           coord = a->maximum;
1754         else
1755           coord = a->minimum;
1756       }
1757 
1758       if ( coord < a->def )
1759         normalized[i] = -FT_DivFix( coord - a->def,
1760                                     a->minimum - a->def );
1761       else if ( coord > a->def )
1762         normalized[i] = FT_DivFix( coord - a->def,
1763                                    a->maximum - a->def );
1764       else
1765         normalized[i] = 0;
1766     }
1767 
1768     FT_TRACE5(( "\n" ));
1769 
1770     for ( ; i < mmvar->num_axis; i++ )
1771       normalized[i] = 0;
1772 
1773     if ( blend->avar_segment )
1774     {
1775       FT_TRACE5(( "normalized design coordinates"
1776                   " before applying `avar' data:\n" ));
1777 
1778       av = blend->avar_segment;
1779       for ( i = 0; i < mmvar->num_axis; i++, av++ )
1780       {
1781         for ( j = 1; j < (FT_UInt)av->pairCount; j++ )
1782         {
1783           if ( normalized[i] < av->correspondence[j].fromCoord )


1893     FT_UShort  axisCount;
1894     FT_UShort  axisSize;
1895     FT_UShort  instanceCount;
1896     FT_UShort  instanceSize;
1897 
1898   } GX_FVar_Head;
1899 
1900 
1901   typedef struct  fvar_axis_
1902   {
1903     FT_ULong   axisTag;
1904     FT_Fixed   minValue;
1905     FT_Fixed   defaultValue;
1906     FT_Fixed   maxValue;
1907     FT_UShort  flags;
1908     FT_UShort  nameID;
1909 
1910   } GX_FVar_Axis;
1911 
1912 
1913   /*************************************************************************/
1914   /*                                                                       */
1915   /* <Function>                                                            */
1916   /*    TT_Get_MM_Var                                                      */
1917   /*                                                                       */
1918   /* <Description>                                                         */
1919   /*    Check that the font's `fvar' table is valid, parse it, and return  */
1920   /*    those data.  It also loads (and parses) the `MVAR' table, if       */
1921   /*    possible.                                                          */
1922   /*                                                                       */
1923   /* <InOut>                                                               */
1924   /*    face   :: The font face.                                           */
1925   /*              TT_Get_MM_Var initializes the blend structure.           */
1926   /*                                                                       */
1927   /* <Output>                                                              */
1928   /*    master :: The `fvar' data (must be freed by caller).  Can be NULL, */
1929   /*              which makes this function simply load MM support.        */
1930   /*                                                                       */
1931   /* <Return>                                                              */
1932   /*    FreeType error code.  0 means success.                             */
1933   /*                                                                       */


1934   FT_LOCAL_DEF( FT_Error )
1935   TT_Get_MM_Var( TT_Face      face,
1936                  FT_MM_Var*  *master )
1937   {
1938     FT_Stream            stream     = face->root.stream;
1939     FT_Memory            memory     = face->root.memory;
1940     FT_ULong             table_len;
1941     FT_Error             error      = FT_Err_Ok;
1942     FT_ULong             fvar_start = 0;
1943     FT_UInt              i, j;
1944     FT_MM_Var*           mmvar = NULL;
1945     FT_Fixed*            next_coords;
1946     FT_Fixed*            nsc;
1947     FT_String*           next_name;
1948     FT_Var_Axis*         a;
1949     FT_Fixed*            c;
1950     FT_Var_Named_Style*  ns;
1951     GX_FVar_Head         fvar_head;
1952     FT_Bool              usePsName  = 0;
1953     FT_UInt              num_instances;


2490       FT_Bool    have_diff = 0;
2491       FT_UInt    j;
2492       FT_Fixed*  c;
2493       FT_Fixed*  n;
2494 
2495 
2496       manageCvt = mcvt_retain;
2497 
2498       for ( i = 0; i < num_coords; i++ )
2499       {
2500         if ( blend->normalizedcoords[i] != coords[i] )
2501         {
2502           manageCvt = mcvt_load;
2503           have_diff = 1;
2504           break;
2505         }
2506       }
2507 
2508       if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) )
2509       {
2510         FT_UInt  idx = (FT_UInt)face->root.face_index >> 16;
2511 
2512 
2513         c = blend->normalizedcoords + i;
2514         n = blend->normalized_stylecoords + idx * mmvar->num_axis + i;



2515         for ( j = i; j < mmvar->num_axis; j++, n++, c++ )
2516           if ( *c != *n )
2517             have_diff = 1;
2518       }
2519       else
2520       {
2521         c = blend->normalizedcoords + i;
2522         for ( j = i; j < mmvar->num_axis; j++, c++ )
2523           if ( *c != 0 )
2524             have_diff = 1;
2525       }
2526 
2527       /* return value -1 indicates `no change' */
2528       if ( !have_diff )



2529         return -1;

2530 
2531       for ( ; i < mmvar->num_axis; i++ )
2532       {
2533         if ( blend->normalizedcoords[i] != 0 )
2534         {
2535           manageCvt = mcvt_load;
2536           break;
2537         }
2538       }
2539 
2540       /* If we don't change the blend coords then we don't need to do  */
2541       /* anything to the cvt table.  It will be correct.  Otherwise we */
2542       /* no longer have the original cvt (it was modified when we set  */
2543       /* the blend last time), so we must reload and then modify it.   */
2544     }
2545 
2546     blend->num_axis = mmvar->num_axis;
2547     FT_MEM_COPY( blend->normalizedcoords,
2548                  coords,
2549                  num_coords * sizeof ( FT_Fixed ) );


2573         /* The original cvt table is in memory.  All we need to do is */
2574         /* apply the `cvar' table (if any).                           */
2575         error = tt_face_vary_cvt( face, face->root.stream );
2576         break;
2577 
2578       case mcvt_retain:
2579         /* The cvt table is correct for this set of coordinates. */
2580         break;
2581       }
2582     }
2583 
2584     /* enforce recomputation of the PostScript name; */
2585     FT_FREE( face->postscript_name );
2586     face->postscript_name = NULL;
2587 
2588   Exit:
2589     return error;
2590   }
2591 
2592 
2593   /*************************************************************************/
2594   /*                                                                       */
2595   /* <Function>                                                            */
2596   /*    TT_Set_MM_Blend                                                    */
2597   /*                                                                       */
2598   /* <Description>                                                         */
2599   /*    Set the blend (normalized) coordinates for this instance of the    */
2600   /*    font.  Check that the `gvar' table is reasonable and does some     */
2601   /*    initial preparation.                                               */
2602   /*                                                                       */
2603   /* <InOut>                                                               */
2604   /*    face       :: The font.                                            */
2605   /*                  Initialize the blend structure with `gvar' data.     */
2606   /*                                                                       */
2607   /* <Input>                                                               */
2608   /*    num_coords :: The number of available coordinates.  If it is       */
2609   /*                  larger than the number of axes, ignore the excess    */
2610   /*                  values.  If it is smaller than the number of axes,   */
2611   /*                  use the default value (0) for the remaining axes.    */
2612   /*                                                                       */
2613   /*    coords     :: An array of `num_coords', each between [-1,1].       */
2614   /*                                                                       */
2615   /* <Return>                                                              */
2616   /*    FreeType error code.  0 means success.                             */
2617   /*                                                                       */



2618   FT_LOCAL_DEF( FT_Error )
2619   TT_Set_MM_Blend( TT_Face    face,
2620                    FT_UInt    num_coords,
2621                    FT_Fixed*  coords )
2622   {
2623     FT_Error  error;
2624 
2625 
2626     error = tt_set_mm_blend( face, num_coords, coords, 1 );
2627     if ( error )
2628       return error;
2629 
2630     if ( num_coords )
2631       face->root.face_flags |= FT_FACE_FLAG_VARIATION;
2632     else
2633       face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
2634 
2635     return FT_Err_Ok;
2636   }
2637 
2638 
2639   /*************************************************************************/
2640   /*                                                                       */
2641   /* <Function>                                                            */
2642   /*    TT_Get_MM_Blend                                                    */
2643   /*                                                                       */
2644   /* <Description>                                                         */
2645   /*    Get the blend (normalized) coordinates for this instance of the    */
2646   /*    font.                                                              */
2647   /*                                                                       */
2648   /* <InOut>                                                               */
2649   /*    face       :: The font.                                            */
2650   /*                  Initialize the blend structure with `gvar' data.     */
2651   /*                                                                       */
2652   /* <Input>                                                               */
2653   /*    num_coords :: The number of available coordinates.  If it is       */
2654   /*                  larger than the number of axes, set the excess       */
2655   /*                  values to 0.                                         */
2656   /*                                                                       */
2657   /*    coords     :: An array of `num_coords', each between [-1,1].       */
2658   /*                                                                       */
2659   /* <Return>                                                              */
2660   /*    FreeType error code.  0 means success.                             */
2661   /*                                                                       */



2662   FT_LOCAL_DEF( FT_Error )
2663   TT_Get_MM_Blend( TT_Face    face,
2664                    FT_UInt    num_coords,
2665                    FT_Fixed*  coords )
2666   {
2667     FT_Error  error = FT_Err_Ok;
2668     GX_Blend  blend;
2669     FT_UInt   i, nc;
2670 
2671 
2672     if ( !face->blend )
2673     {
2674       if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
2675         return error;
2676     }
2677 
2678     blend = face->blend;
2679 
2680     if ( !blend->coords )
2681     {


2695     }
2696 
2697     if ( face->doblend )
2698     {
2699       for ( i = 0; i < nc; i++ )
2700         coords[i] = blend->normalizedcoords[i];
2701     }
2702     else
2703     {
2704       for ( i = 0; i < nc; i++ )
2705         coords[i] = 0;
2706     }
2707 
2708     for ( ; i < num_coords; i++ )
2709       coords[i] = 0;
2710 
2711     return FT_Err_Ok;
2712   }
2713 
2714 
2715   /*************************************************************************/
2716   /*                                                                       */
2717   /* <Function>                                                            */
2718   /*    TT_Set_Var_Design                                                  */
2719   /*                                                                       */
2720   /* <Description>                                                         */
2721   /*    Set the coordinates for the instance, measured in the user         */
2722   /*    coordinate system.  Parse the `avar' table (if present) to convert */
2723   /*    from user to normalized coordinates.                               */
2724   /*                                                                       */
2725   /* <InOut>                                                               */
2726   /*    face       :: The font face.                                       */
2727   /*                  Initialize the blend struct with `gvar' data.        */
2728   /*                                                                       */
2729   /* <Input>                                                               */
2730   /*    num_coords :: The number of available coordinates.  If it is       */
2731   /*                  larger than the number of axes, ignore the excess    */
2732   /*                  values.  If it is smaller than the number of axes,   */
2733   /*                  use the default values for the remaining axes.       */
2734   /*                                                                       */
2735   /*    coords     :: A coordinate array with `num_coords' elements.       */
2736   /*                                                                       */
2737   /* <Return>                                                              */
2738   /*    FreeType error code.  0 means success.                             */
2739   /*                                                                       */



2740   FT_LOCAL_DEF( FT_Error )
2741   TT_Set_Var_Design( TT_Face    face,
2742                      FT_UInt    num_coords,
2743                      FT_Fixed*  coords )
2744   {
2745     FT_Error    error  = FT_Err_Ok;
2746     GX_Blend    blend;
2747     FT_MM_Var*  mmvar;
2748     FT_UInt     i;
2749     FT_Memory   memory = face->root.memory;
2750 
2751     FT_Fixed*  c;
2752     FT_Fixed*  n;
2753     FT_Fixed*  normalized = NULL;
2754 
2755     FT_Bool  have_diff = 0;
2756 
2757 
2758     if ( !face->blend )
2759     {


2837 
2838     FT_TRACE5(( "TT_Set_Var_Design:\n"
2839                 "  normalized design coordinates:\n" ));
2840     ft_var_to_normalized( face, num_coords, blend->coords, normalized );
2841 
2842     error = tt_set_mm_blend( face, mmvar->num_axis, normalized, 0 );
2843     if ( error )
2844       goto Exit;
2845 
2846     if ( num_coords )
2847       face->root.face_flags |= FT_FACE_FLAG_VARIATION;
2848     else
2849       face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
2850 
2851   Exit:
2852     FT_FREE( normalized );
2853     return error;
2854   }
2855 
2856 
2857   /*************************************************************************/
2858   /*                                                                       */
2859   /* <Function>                                                            */
2860   /*    TT_Get_Var_Design                                                  */
2861   /*                                                                       */
2862   /* <Description>                                                         */
2863   /*    Get the design coordinates of the currently selected interpolated  */
2864   /*    font.                                                              */
2865   /*                                                                       */
2866   /* <Input>                                                               */
2867   /*    face       :: A handle to the source face.                         */
2868   /*                                                                       */
2869   /*    num_coords :: The number of design coordinates to retrieve.  If it */
2870   /*                  is larger than the number of axes, set the excess    */
2871   /*                  values to~0.                                         */
2872   /*                                                                       */
2873   /* <Output>                                                              */
2874   /*    coords     :: The design coordinates array.                        */
2875   /*                                                                       */
2876   /* <Return>                                                              */
2877   /*    FreeType error code.  0~means success.                             */
2878   /*                                                                       */



2879   FT_LOCAL_DEF( FT_Error )
2880   TT_Get_Var_Design( TT_Face    face,
2881                      FT_UInt    num_coords,
2882                      FT_Fixed*  coords )
2883   {
2884     FT_Error  error = FT_Err_Ok;
2885     GX_Blend  blend;
2886     FT_UInt   i, nc;
2887 
2888 
2889     if ( !face->blend )
2890     {
2891       if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
2892         return error;
2893     }
2894 
2895     blend = face->blend;
2896 
2897     if ( !blend->coords )
2898     {


2912     }
2913 
2914     if ( face->doblend )
2915     {
2916       for ( i = 0; i < nc; i++ )
2917         coords[i] = blend->coords[i];
2918     }
2919     else
2920     {
2921       for ( i = 0; i < nc; i++ )
2922         coords[i] = 0;
2923     }
2924 
2925     for ( ; i < num_coords; i++ )
2926       coords[i] = 0;
2927 
2928     return FT_Err_Ok;
2929   }
2930 
2931 
2932   /*************************************************************************/
2933   /*                                                                       */
2934   /* <Function>                                                            */
2935   /*    TT_Set_Named_Instance                                              */
2936   /*                                                                       */
2937   /* <Description>                                                         */
2938   /*    Set the given named instance, also resetting any further           */
2939   /*    variation.                                                         */
2940   /*                                                                       */
2941   /* <Input>                                                               */
2942   /*    face           :: A handle to the source face.                     */
2943   /*                                                                       */
2944   /*    instance_index :: The instance index, starting with value 1.       */
2945   /*                      Value 0 indicates to not use an instance.        */
2946   /*                                                                       */
2947   /* <Return>                                                              */
2948   /*    FreeType error code.  0~means success.                             */
2949   /*                                                                       */


2950   FT_LOCAL_DEF( FT_Error )
2951   TT_Set_Named_Instance( TT_Face  face,
2952                          FT_UInt  instance_index )
2953   {
2954     FT_Error    error = FT_ERR( Invalid_Argument );
2955     GX_Blend    blend;
2956     FT_MM_Var*  mmvar;
2957 
2958     FT_UInt  num_instances;
2959 
2960 
2961     if ( !face->blend )
2962     {
2963       if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
2964         goto Exit;
2965     }
2966 
2967     blend = face->blend;
2968     mmvar = blend->mmvar;
2969 


3005       error = TT_Set_Var_Design( face, 0, NULL );
3006 
3007     face->root.face_index  = ( instance_index << 16 )             |
3008                              ( face->root.face_index & 0xFFFFL );
3009     face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
3010 
3011   Exit:
3012     return error;
3013   }
3014 
3015 
3016   /*************************************************************************/
3017   /*************************************************************************/
3018   /*****                                                               *****/
3019   /*****                     GX VAR PARSING ROUTINES                   *****/
3020   /*****                                                               *****/
3021   /*************************************************************************/
3022   /*************************************************************************/
3023 
3024 
3025   /*************************************************************************/
3026   /*                                                                       */
3027   /* <Function>                                                            */
3028   /*    tt_face_vary_cvt                                                   */
3029   /*                                                                       */
3030   /* <Description>                                                         */
3031   /*    Modify the loaded cvt table according to the `cvar' table and the  */
3032   /*    font's blend.                                                      */
3033   /*                                                                       */
3034   /* <InOut>                                                               */
3035   /*    face   :: A handle to the target face object.                      */
3036   /*                                                                       */
3037   /* <Input>                                                               */
3038   /*    stream :: A handle to the input stream.                            */
3039   /*                                                                       */
3040   /* <Return>                                                              */
3041   /*    FreeType error code.  0 means success.                             */
3042   /*                                                                       */
3043   /*    Most errors are ignored.  It is perfectly valid not to have a      */
3044   /*    `cvar' table even if there is a `gvar' and `fvar' table.           */
3045   /*                                                                       */


3046   FT_LOCAL_DEF( FT_Error )
3047   tt_face_vary_cvt( TT_Face    face,
3048                     FT_Stream  stream )
3049   {
3050     FT_Error    error;
3051     FT_Memory   memory = stream->memory;

3052     FT_ULong    table_start;
3053     FT_ULong    table_len;

3054     FT_UInt     tupleCount;
3055     FT_ULong    offsetToData;

3056     FT_ULong    here;
3057     FT_UInt     i, j;

3058     FT_Fixed*   tuple_coords    = NULL;
3059     FT_Fixed*   im_start_coords = NULL;
3060     FT_Fixed*   im_end_coords   = NULL;

3061     GX_Blend    blend           = face->blend;
3062     FT_UInt     point_count, spoint_count = 0;



3063     FT_UShort*  sharedpoints = NULL;
3064     FT_UShort*  localpoints  = NULL;
3065     FT_UShort*  points;
3066     FT_Short*   deltas;


3067 
3068 
3069     FT_TRACE2(( "CVAR " ));
3070 
3071     if ( !blend )
3072     {
3073       FT_TRACE2(( "\n"
3074                   "tt_face_vary_cvt: no blend specified\n" ));
3075       error = FT_Err_Ok;
3076       goto Exit;
3077     }
3078 
3079     if ( !face->cvt )
3080     {
3081       FT_TRACE2(( "\n"
3082                   "tt_face_vary_cvt: no `cvt ' table\n" ));
3083       error = FT_Err_Ok;
3084       goto Exit;
3085     }
3086 


3129       goto FExit;
3130     }
3131 
3132     offsetToData += table_start;
3133 
3134     if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS )
3135     {
3136       here = FT_Stream_FTell( stream );
3137 
3138       FT_Stream_SeekSet( stream, offsetToData );
3139 
3140       sharedpoints = ft_var_readpackedpoints( stream,
3141                                               table_len,
3142                                               &spoint_count );
3143       offsetToData = FT_Stream_FTell( stream );
3144 
3145       FT_Stream_SeekSet( stream, here );
3146     }
3147 
3148     FT_TRACE5(( "cvar: there %s %d tuple%s:\n",
3149                 ( tupleCount & 0xFFF ) == 1 ? "is" : "are",
3150                 tupleCount & 0xFFF,
3151                 ( tupleCount & 0xFFF ) == 1 ? "" : "s" ));



3152 
3153     for ( i = 0; i < ( tupleCount & 0xFFF ); i++ )
3154     {
3155       FT_UInt   tupleDataSize;
3156       FT_UInt   tupleIndex;
3157       FT_Fixed  apply;
3158 
3159 
3160       FT_TRACE6(( "  tuple %d:\n", i ));
3161 
3162       tupleDataSize = FT_GET_USHORT();
3163       tupleIndex    = FT_GET_USHORT();
3164 
3165       if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
3166       {
3167         for ( j = 0; j < blend->num_axis; j++ )
3168           tuple_coords[j] = FT_GET_SHORT() * 4;  /* convert from        */
3169                                                  /* short frac to fixed */
3170       }
3171       else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount )
3172       {
3173         FT_TRACE2(( "tt_face_vary_cvt:"
3174                     " invalid tuple index\n" ));
3175 
3176         error = FT_THROW( Invalid_Table );
3177         goto Exit;
3178       }
3179       else










3180         FT_MEM_COPY(
3181           tuple_coords,
3182           &blend->tuplecoords[( tupleIndex & 0xFFF ) * blend->num_axis],

3183           blend->num_axis * sizeof ( FT_Fixed ) );

3184 
3185       if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
3186       {
3187         for ( j = 0; j < blend->num_axis; j++ )
3188           im_start_coords[j] = FT_GET_SHORT() * 4;
3189         for ( j = 0; j < blend->num_axis; j++ )
3190           im_end_coords[j] = FT_GET_SHORT() * 4;
3191       }
3192 
3193       apply = ft_var_apply_tuple( blend,
3194                                   (FT_UShort)tupleIndex,
3195                                   tuple_coords,
3196                                   im_start_coords,
3197                                   im_end_coords );
3198 
3199       if ( apply == 0 )              /* tuple isn't active for our blend */
3200       {
3201         offsetToData += tupleDataSize;
3202         continue;
3203       }


3224                                         point_count == 0 ? face->cvt_size
3225                                                          : point_count );
3226 
3227       if ( !points                                                        ||
3228            !deltas                                                        ||
3229            ( localpoints == ALL_POINTS && point_count != face->cvt_size ) )
3230         ; /* failure, ignore it */
3231 
3232       else if ( localpoints == ALL_POINTS )
3233       {
3234 #ifdef FT_DEBUG_LEVEL_TRACE
3235         int  count = 0;
3236 #endif
3237 
3238 
3239         FT_TRACE7(( "    CVT deltas:\n" ));
3240 
3241         /* this means that there are deltas for every entry in cvt */
3242         for ( j = 0; j < face->cvt_size; j++ )
3243         {
3244           FT_Long  orig_cvt = face->cvt[j];
3245 
3246 
3247           face->cvt[j] = (FT_Short)( orig_cvt +
3248                                      FT_MulFix( deltas[j], apply ) );
3249 
3250 #ifdef FT_DEBUG_LEVEL_TRACE
3251           if ( orig_cvt != face->cvt[j] )
3252           {
3253             FT_TRACE7(( "      %d: %d -> %d\n",
3254                         j, orig_cvt, face->cvt[j] ));




3255             count++;
3256           }
3257 #endif
3258         }
3259 
3260 #ifdef FT_DEBUG_LEVEL_TRACE
3261         if ( !count )
3262           FT_TRACE7(( "      none\n" ));
3263 #endif
3264       }
3265 
3266       else
3267       {
3268 #ifdef FT_DEBUG_LEVEL_TRACE
3269         int  count = 0;
3270 #endif
3271 
3272 
3273         FT_TRACE7(( "    CVT deltas:\n" ));
3274 
3275         for ( j = 0; j < point_count; j++ )
3276         {
3277           int      pindex;
3278           FT_Long  orig_cvt;
3279 
3280 
3281           pindex = points[j];
3282           if ( (FT_ULong)pindex >= face->cvt_size )
3283             continue;
3284 
3285           orig_cvt          = face->cvt[pindex];
3286           face->cvt[pindex] = (FT_Short)( orig_cvt +
3287                                           FT_MulFix( deltas[j], apply ) );
3288 
3289 #ifdef FT_DEBUG_LEVEL_TRACE
3290           if ( orig_cvt != face->cvt[pindex] )
3291           {
3292             FT_TRACE7(( "      %d: %d -> %d\n",
3293                         pindex, orig_cvt, face->cvt[pindex] ));




3294             count++;
3295           }
3296 #endif
3297         }
3298 
3299 #ifdef FT_DEBUG_LEVEL_TRACE
3300         if ( !count )
3301           FT_TRACE7(( "      none\n" ));
3302 #endif
3303       }
3304 
3305       if ( localpoints != ALL_POINTS )
3306         FT_FREE( localpoints );
3307       FT_FREE( deltas );
3308 
3309       offsetToData += tupleDataSize;
3310 
3311       FT_Stream_SeekSet( stream, here );
3312     }
3313 
3314     FT_TRACE5(( "\n" ));
3315 



3316   FExit:
3317     FT_FRAME_EXIT();
3318 
3319   Exit:
3320     if ( sharedpoints != ALL_POINTS )
3321       FT_FREE( sharedpoints );
3322     FT_FREE( tuple_coords );
3323     FT_FREE( im_start_coords );
3324     FT_FREE( im_end_coords );

3325 
3326     return error;
3327   }
3328 
3329 
3330   /* Shift the original coordinates of all points between indices `p1' */
3331   /* and `p2', using the same difference as given by index `ref'.      */
3332 
3333   /* modeled after `af_iup_shift' */
3334 
3335   static void
3336   tt_delta_shift( int         p1,
3337                   int         p2,
3338                   int         ref,
3339                   FT_Vector*  in_points,
3340                   FT_Vector*  out_points )
3341   {
3342     int        p;
3343     FT_Vector  delta;
3344 


3351 
3352     for ( p = p1; p < ref; p++ )
3353     {
3354       out_points[p].x += delta.x;
3355       out_points[p].y += delta.y;
3356     }
3357 
3358     for ( p = ref + 1; p <= p2; p++ )
3359     {
3360       out_points[p].x += delta.x;
3361       out_points[p].y += delta.y;
3362     }
3363   }
3364 
3365 
3366   /* Interpolate the original coordinates of all points with indices */
3367   /* between `p1' and `p2', using `ref1' and `ref2' as the reference */
3368   /* point indices.                                                  */
3369 
3370   /* modeled after `af_iup_interp', `_iup_worker_interpolate', and */
3371   /* `Ins_IUP'                                                     */
3372 
3373   static void
3374   tt_delta_interpolate( int         p1,
3375                         int         p2,
3376                         int         ref1,
3377                         int         ref2,
3378                         FT_Vector*  in_points,
3379                         FT_Vector*  out_points )
3380   {
3381     int  p, i;
3382 
3383     FT_Pos  out, in1, in2, out1, out2, d1, d2;
3384 
3385 
3386     if ( p1 > p2 )
3387       return;
3388 
3389     /* handle both horizontal and vertical coordinates */
3390     for ( i = 0; i <= 1; i++ )
3391     {
3392       /* shift array pointers so that we can access `foo.y' as `foo.x' */


3511                                 cur_delta,
3512                                 first_delta,
3513                                 in_points,
3514                                 out_points );
3515 
3516           if ( first_delta > 0 )
3517             tt_delta_interpolate( first_point,
3518                                   first_delta - 1,
3519                                   cur_delta,
3520                                   first_delta,
3521                                   in_points,
3522                                   out_points );
3523         }
3524       }
3525       contour++;
3526 
3527     } while ( contour < outline->n_contours );
3528   }
3529 
3530 
3531   /*************************************************************************/
3532   /*                                                                       */
3533   /* <Function>                                                            */
3534   /*    TT_Vary_Apply_Glyph_Deltas                                         */
3535   /*                                                                       */
3536   /* <Description>                                                         */
3537   /*    Apply the appropriate deltas to the current glyph.                 */
3538   /*                                                                       */
3539   /* <Input>                                                               */
3540   /*    face        :: A handle to the target face object.                 */
3541   /*                                                                       */
3542   /*    glyph_index :: The index of the glyph being modified.              */
3543   /*                                                                       */
3544   /*    n_points    :: The number of the points in the glyph, including    */
3545   /*                   phantom points.                                     */
3546   /*                                                                       */
3547   /* <InOut>                                                               */
3548   /*    outline     :: The outline to change.                              */
3549   /*                                                                       */
3550   /* <Return>                                                              */
3551   /*    FreeType error code.  0 means success.                             */
3552   /*                                                                       */




3553   FT_LOCAL_DEF( FT_Error )
3554   TT_Vary_Apply_Glyph_Deltas( TT_Face      face,
3555                               FT_UInt      glyph_index,
3556                               FT_Outline*  outline,
3557                               FT_UInt      n_points )
3558   {

3559     FT_Stream   stream = face->root.stream;
3560     FT_Memory   memory = stream->memory;
3561     GX_Blend    blend  = face->blend;
3562 
3563     FT_Vector*  points_org = NULL;
3564     FT_Vector*  points_out = NULL;
3565     FT_Bool*    has_delta  = NULL;
3566 
3567     FT_Error    error;
3568     FT_ULong    glyph_start;

3569     FT_UInt     tupleCount;
3570     FT_ULong    offsetToData;


3571     FT_ULong    here;
3572     FT_UInt     i, j;

3573     FT_Fixed*   tuple_coords    = NULL;
3574     FT_Fixed*   im_start_coords = NULL;
3575     FT_Fixed*   im_end_coords   = NULL;
3576     FT_UInt     point_count, spoint_count = 0;





3577     FT_UShort*  sharedpoints = NULL;
3578     FT_UShort*  localpoints  = NULL;
3579     FT_UShort*  points;
3580     FT_Short    *deltas_x, *deltas_y;




3581 
3582 
3583     if ( !face->doblend || !blend )
3584       return FT_THROW( Invalid_Argument );
3585 
3586     if ( glyph_index >= blend->gv_glyphcnt      ||
3587          blend->glyphoffsets[glyph_index] ==
3588            blend->glyphoffsets[glyph_index + 1] )
3589     {
3590       FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
3591                   " no variation data for this glyph\n" ));
3592       return FT_Err_Ok;
3593     }
3594 
3595     if ( FT_NEW_ARRAY( points_org, n_points ) ||
3596          FT_NEW_ARRAY( points_out, n_points ) ||
3597          FT_NEW_ARRAY( has_delta, n_points )  )
3598       goto Fail1;
3599 



3600     if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] )   ||
3601          FT_FRAME_ENTER( blend->glyphoffsets[glyph_index + 1] -
3602                            blend->glyphoffsets[glyph_index] ) )
3603       goto Fail1;
3604 
3605     glyph_start = FT_Stream_FTell( stream );
3606 
3607     /* each set of glyph variation data is formatted similarly to `cvar' */
3608 
3609     if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis )    ||
3610          FT_NEW_ARRAY( im_start_coords, blend->num_axis ) ||
3611          FT_NEW_ARRAY( im_end_coords, blend->num_axis )   )
3612       goto Fail2;
3613 
3614     tupleCount   = FT_GET_USHORT();
3615     offsetToData = FT_GET_USHORT();
3616 
3617     /* rough sanity test */
3618     if ( offsetToData + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) * 4 >
3619            blend->gvar_size )
3620     {
3621       FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
3622                   " invalid glyph variation array header\n" ));
3623 
3624       error = FT_THROW( Invalid_Table );
3625       goto Fail2;
3626     }
3627 
3628     offsetToData += glyph_start;
3629 
3630     if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS )
3631     {
3632       here = FT_Stream_FTell( stream );
3633 
3634       FT_Stream_SeekSet( stream, offsetToData );
3635 
3636       sharedpoints = ft_var_readpackedpoints( stream,
3637                                               blend->gvar_size,
3638                                               &spoint_count );
3639       offsetToData = FT_Stream_FTell( stream );
3640 
3641       FT_Stream_SeekSet( stream, here );
3642     }
3643 
3644     FT_TRACE5(( "gvar: there %s %d tuple%s:\n",
3645                 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "is" : "are",
3646                 tupleCount & GX_TC_TUPLE_COUNT_MASK,
3647                 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" ));
3648 




3649     for ( j = 0; j < n_points; j++ )
3650       points_org[j] = outline->points[j];



3651 
3652     for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ )
3653     {
3654       FT_UInt   tupleDataSize;
3655       FT_UInt   tupleIndex;
3656       FT_Fixed  apply;
3657 
3658 
3659       FT_TRACE6(( "  tuple %d:\n", i ));
3660 
3661       tupleDataSize = FT_GET_USHORT();
3662       tupleIndex    = FT_GET_USHORT();
3663 
3664       if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
3665       {
3666         for ( j = 0; j < blend->num_axis; j++ )
3667           tuple_coords[j] = FT_GET_SHORT() * 4;   /* convert from        */
3668                                                   /* short frac to fixed */
3669       }
3670       else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount )
3671       {
3672         FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
3673                     " invalid tuple index\n" ));
3674 
3675         error = FT_THROW( Invalid_Table );
3676         goto Fail2;
3677       }
3678       else
3679         FT_MEM_COPY(
3680           tuple_coords,
3681           &blend->tuplecoords[( tupleIndex & 0xFFF ) * blend->num_axis],

3682           blend->num_axis * sizeof ( FT_Fixed ) );
3683 
3684       if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
3685       {
3686         for ( j = 0; j < blend->num_axis; j++ )
3687           im_start_coords[j] = FT_GET_SHORT() * 4;
3688         for ( j = 0; j < blend->num_axis; j++ )
3689           im_end_coords[j] = FT_GET_SHORT() * 4;
3690       }
3691 
3692       apply = ft_var_apply_tuple( blend,
3693                                   (FT_UShort)tupleIndex,
3694                                   tuple_coords,
3695                                   im_start_coords,
3696                                   im_end_coords );
3697 
3698       if ( apply == 0 )              /* tuple isn't active for our blend */
3699       {
3700         offsetToData += tupleDataSize;
3701         continue;


3725       deltas_y = ft_var_readpackeddeltas( stream,
3726                                           blend->gvar_size,
3727                                           point_count == 0 ? n_points
3728                                                            : point_count );
3729 
3730       if ( !points || !deltas_y || !deltas_x )
3731         ; /* failure, ignore it */
3732 
3733       else if ( points == ALL_POINTS )
3734       {
3735 #ifdef FT_DEBUG_LEVEL_TRACE
3736         int  count = 0;
3737 #endif
3738 
3739 
3740         FT_TRACE7(( "    point deltas:\n" ));
3741 
3742         /* this means that there are deltas for every point in the glyph */
3743         for ( j = 0; j < n_points; j++ )
3744         {
3745           FT_Pos  delta_x = FT_MulFix( deltas_x[j], apply );
3746           FT_Pos  delta_y = FT_MulFix( deltas_y[j], apply );



3747 
3748 
3749           if ( j < n_points - 4 )
3750           {
3751             outline->points[j].x += delta_x;
3752             outline->points[j].y += delta_y;
3753           }
3754           else
3755           {
3756             /* To avoid double adjustment of advance width or height, */
3757             /* adjust phantom points only if there is no HVAR or VVAR */
3758             /* support, respectively.                                 */
3759             if ( j == ( n_points - 4 )        &&
3760                  !( face->variation_support &
3761                     TT_FACE_FLAG_VAR_LSB    ) )
3762               outline->points[j].x += delta_x;
3763 
3764             else if ( j == ( n_points - 3 )          &&
3765                       !( face->variation_support   &
3766                          TT_FACE_FLAG_VAR_HADVANCE ) )
3767               outline->points[j].x += delta_x;
3768 
3769             else if ( j == ( n_points - 2 )        &&
3770                       !( face->variation_support &
3771                          TT_FACE_FLAG_VAR_TSB    ) )
3772               outline->points[j].y += delta_y;
3773 
3774             else if ( j == ( n_points - 1 )          &&
3775                       !( face->variation_support   &
3776                          TT_FACE_FLAG_VAR_VADVANCE ) )
3777               outline->points[j].y += delta_y;
3778           }
3779 
3780 #ifdef FT_DEBUG_LEVEL_TRACE
3781           if ( delta_x || delta_y )
3782           {
3783             FT_TRACE7(( "      %d: (%d, %d) -> (%d, %d)\n",
3784                         j,
3785                         outline->points[j].x - delta_x,
3786                         outline->points[j].y - delta_y,
3787                         outline->points[j].x,
3788                         outline->points[j].y ));




3789             count++;
3790           }
3791 #endif
3792         }
3793 
3794 #ifdef FT_DEBUG_LEVEL_TRACE
3795         if ( !count )
3796           FT_TRACE7(( "      none\n" ));
3797 #endif
3798       }
3799 
3800       else
3801       {
3802 #ifdef FT_DEBUG_LEVEL_TRACE
3803         int  count = 0;
3804 #endif
3805 
3806 
3807         /* we have to interpolate the missing deltas similar to the */
3808         /* IUP bytecode instruction                                 */


3820           if ( idx >= n_points )
3821             continue;
3822 
3823           has_delta[idx] = TRUE;
3824 
3825           points_out[idx].x += FT_MulFix( deltas_x[j], apply );
3826           points_out[idx].y += FT_MulFix( deltas_y[j], apply );
3827         }
3828 
3829         /* no need to handle phantom points here,      */
3830         /* since solitary points can't be interpolated */
3831         tt_interpolate_deltas( outline,
3832                                points_out,
3833                                points_org,
3834                                has_delta );
3835 
3836         FT_TRACE7(( "    point deltas:\n" ));
3837 
3838         for ( j = 0; j < n_points; j++ )
3839         {
3840           FT_Pos  delta_x = points_out[j].x - points_org[j].x;
3841           FT_Pos  delta_y = points_out[j].y - points_org[j].y;



3842 
3843 
3844           if ( j < n_points - 4 )
3845           {
3846             outline->points[j].x += delta_x;
3847             outline->points[j].y += delta_y;
3848           }
3849           else
3850           {
3851             /* To avoid double adjustment of advance width or height, */
3852             /* adjust phantom points only if there is no HVAR or VVAR */
3853             /* support, respectively.                                 */
3854             if ( j == ( n_points - 4 )        &&
3855                  !( face->variation_support &
3856                     TT_FACE_FLAG_VAR_LSB    ) )
3857               outline->points[j].x += delta_x;
3858 
3859             else if ( j == ( n_points - 3 )          &&
3860                       !( face->variation_support   &
3861                          TT_FACE_FLAG_VAR_HADVANCE ) )
3862               outline->points[j].x += delta_x;
3863 
3864             else if ( j == ( n_points - 2 )        &&
3865                       !( face->variation_support &
3866                          TT_FACE_FLAG_VAR_TSB    ) )
3867               outline->points[j].y += delta_y;
3868 
3869             else if ( j == ( n_points - 1 )          &&
3870                       !( face->variation_support   &
3871                          TT_FACE_FLAG_VAR_VADVANCE ) )
3872               outline->points[j].y += delta_y;
3873           }
3874 
3875 #ifdef FT_DEBUG_LEVEL_TRACE
3876           if ( delta_x || delta_y )
3877           {
3878             FT_TRACE7(( "      %d: (%d, %d) -> (%d, %d)\n",
3879                         j,
3880                         outline->points[j].x - delta_x,
3881                         outline->points[j].y - delta_y,
3882                         outline->points[j].x,
3883                         outline->points[j].y ));




3884             count++;
3885           }
3886 #endif
3887         }
3888 
3889 #ifdef FT_DEBUG_LEVEL_TRACE
3890         if ( !count )
3891           FT_TRACE7(( "      none\n" ));
3892 #endif
3893       }
3894 
3895       if ( localpoints != ALL_POINTS )
3896         FT_FREE( localpoints );
3897       FT_FREE( deltas_x );
3898       FT_FREE( deltas_y );
3899 
3900       offsetToData += tupleDataSize;
3901 
3902       FT_Stream_SeekSet( stream, here );
3903     }
3904 
3905     FT_TRACE5(( "\n" ));
3906 










3907   Fail2:
3908     if ( sharedpoints != ALL_POINTS )
3909       FT_FREE( sharedpoints );
3910     FT_FREE( tuple_coords );
3911     FT_FREE( im_start_coords );
3912     FT_FREE( im_end_coords );
3913 
3914     FT_FRAME_EXIT();
3915 
3916   Fail1:
3917     FT_FREE( points_org );
3918     FT_FREE( points_out );
3919     FT_FREE( has_delta );
3920 
3921     return error;
3922   }
3923 
3924 
3925   /*************************************************************************/
3926   /*                                                                       */
3927   /* <Function>                                                            */
3928   /*    tt_get_var_blend                                                   */
3929   /*                                                                       */
3930   /* <Description>                                                         */
3931   /*    An extended internal version of `TT_Get_MM_Blend' that returns     */
3932   /*    pointers instead of copying data, without any initialization of    */
3933   /*    the MM machinery in case it isn't loaded yet.                      */
3934   /*                                                                       */
3935   FT_LOCAL_DEF( FT_Error )
3936   tt_get_var_blend( TT_Face      face,
3937                     FT_UInt     *num_coords,
3938                     FT_Fixed*   *coords,
3939                     FT_Fixed*   *normalizedcoords,
3940                     FT_MM_Var*  *mm_var )
3941   {
3942     if ( face->blend )
3943     {
3944       if ( num_coords )
3945         *num_coords       = face->blend->num_axis;
3946       if ( coords )
3947         *coords           = face->blend->coords;
3948       if ( normalizedcoords )
3949         *normalizedcoords = face->blend->normalizedcoords;
3950       if ( mm_var )
3951         *mm_var           = face->blend->mmvar;
3952     }
3953     else
3954     {


3976     {
3977       for ( i = 0; i < itemStore->dataCount; i++ )
3978       {
3979         FT_FREE( itemStore->varData[i].regionIndices );
3980         FT_FREE( itemStore->varData[i].deltaSet );
3981       }
3982 
3983       FT_FREE( itemStore->varData );
3984     }
3985 
3986     if ( itemStore->varRegionList )
3987     {
3988       for ( i = 0; i < itemStore->regionCount; i++ )
3989         FT_FREE( itemStore->varRegionList[i].axisList );
3990 
3991       FT_FREE( itemStore->varRegionList );
3992     }
3993   }
3994 
3995 
3996   /*************************************************************************/
3997   /*                                                                       */
3998   /* <Function>                                                            */
3999   /*    tt_done_blend                                                      */
4000   /*                                                                       */
4001   /* <Description>                                                         */
4002   /*    Free the blend internal data structure.                            */
4003   /*                                                                       */
4004   FT_LOCAL_DEF( void )
4005   tt_done_blend( TT_Face  face )
4006   {
4007     FT_Memory  memory = FT_FACE_MEMORY( face );
4008     GX_Blend   blend  = face->blend;
4009 
4010 
4011     if ( blend )
4012     {
4013       FT_UInt  i, num_axes;
4014 
4015 
4016       /* blend->num_axis might not be set up yet */
4017       num_axes = blend->mmvar->num_axis;
4018 
4019       FT_FREE( blend->coords );
4020       FT_FREE( blend->normalizedcoords );
4021       FT_FREE( blend->normalized_stylecoords );
4022       FT_FREE( blend->mmvar );
4023 


   1 /****************************************************************************
   2  *
   3  * ttgxvar.c
   4  *
   5  *   TrueType GX Font Variation loader
   6  *
   7  * Copyright (C) 2004-2019 by
   8  * David Turner, Robert Wilhelm, Werner Lemberg, and George Williams.
   9  *
  10  * This file is part of the FreeType project, and may only be used,
  11  * modified, and distributed under the terms of the FreeType project
  12  * license, LICENSE.TXT.  By continuing to use, modify, or distribute
  13  * this file you indicate that you have read the license and
  14  * understand and accept it fully.
  15  *
  16  */
  17 
  18 
  19   /**************************************************************************
  20    *
  21    * Apple documents the `fvar', `gvar', `cvar', and `avar' tables at
  22    *
  23    *   https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6[fgca]var.html
  24    *
  25    * The documentation for `gvar' is not intelligible; `cvar' refers you
  26    * to `gvar' and is thus also incomprehensible.
  27    *
  28    * The documentation for `avar' appears correct, but Apple has no fonts
  29    * with an `avar' table, so it is hard to test.
  30    *
  31    * Many thanks to John Jenkins (at Apple) in figuring this out.
  32    *
  33    *
  34    * Apple's `kern' table has some references to tuple indices, but as
  35    * there is no indication where these indices are defined, nor how to
  36    * interpolate the kerning values (different tuples have different
  37    * classes) this issue is ignored.
  38    *
  39    */
  40 
  41 
  42 #include <ft2build.h>
  43 #include FT_INTERNAL_DEBUG_H
  44 #include FT_CONFIG_CONFIG_H
  45 #include FT_INTERNAL_STREAM_H
  46 #include FT_INTERNAL_SFNT_H
  47 #include FT_TRUETYPE_TAGS_H
  48 #include FT_TRUETYPE_IDS_H
  49 #include FT_MULTIPLE_MASTERS_H
  50 #include FT_LIST_H
  51 
  52 #include "ttpload.h"
  53 #include "ttgxvar.h"
  54 
  55 #include "tterrors.h"
  56 
  57 
  58 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
  59 
  60 
  61 #define FT_Stream_FTell( stream )                         \
  62           (FT_ULong)( (stream)->cursor - (stream)->base )
  63 #define FT_Stream_SeekSet( stream, off )                               \
  64           (stream)->cursor =                                           \
  65             ( (off) < (FT_ULong)( (stream)->limit - (stream)->base ) ) \
  66                         ? (stream)->base + (off)                       \
  67                         : (stream)->limit
  68 
  69 
  70   /* some macros we need */
  71 #define FT_fdot14ToFixed( x )                \
  72         ( (FT_Fixed)( (FT_ULong)(x) << 2 ) )
  73 #define FT_intToFixed( i )                    \
  74         ( (FT_Fixed)( (FT_ULong)(i) << 16 ) )
  75 #define FT_fixedToInt( x )                                   \
  76         ( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) )
  77 
  78 
  79   /**************************************************************************
  80    *
  81    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
  82    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
  83    * messages during execution.
  84    */
  85 #undef  FT_COMPONENT
  86 #define FT_COMPONENT  ttgxvar
  87 
  88 
  89   /*************************************************************************/
  90   /*************************************************************************/
  91   /*****                                                               *****/
  92   /*****                       Internal Routines                       *****/
  93   /*****                                                               *****/
  94   /*************************************************************************/
  95   /*************************************************************************/
  96 
  97 
  98   /**************************************************************************
  99    *
 100    * The macro ALL_POINTS is used in `ft_var_readpackedpoints'.  It
 101    * indicates that there is a delta for every point without needing to
 102    * enumerate all of them.
 103    */
 104 
 105   /* ensure that value `0' has the same width as a pointer */
 106 #define ALL_POINTS  (FT_UShort*)~(FT_PtrDist)0
 107 
 108 
 109 #define GX_PT_POINTS_ARE_WORDS      0x80U
 110 #define GX_PT_POINT_RUN_COUNT_MASK  0x7FU
 111 
 112 
 113   /**************************************************************************
 114    *
 115    * @Function:
 116    *   ft_var_readpackedpoints
 117    *
 118    * @Description:
 119    *   Read a set of points to which the following deltas will apply.
 120    *   Points are packed with a run length encoding.
 121    *
 122    * @Input:
 123    *   stream ::
 124    *     The data stream.
 125    *
 126    *   size ::
 127    *     The size of the table holding the data.
 128    *
 129    * @Output:
 130    *   point_cnt ::
 131    *     The number of points read.  A zero value means that
 132    *     all points in the glyph will be affected, without
 133    *     enumerating them individually.
 134    *
 135    * @Return:
 136    *   An array of FT_UShort containing the affected points or the
 137    *   special value ALL_POINTS.
 138    */
 139   static FT_UShort*
 140   ft_var_readpackedpoints( FT_Stream  stream,
 141                            FT_ULong   size,
 142                            FT_UInt   *point_cnt )
 143   {
 144     FT_UShort *points = NULL;
 145     FT_UInt    n;
 146     FT_UInt    runcnt;
 147     FT_UInt    i, j;
 148     FT_UShort  first;
 149     FT_Memory  memory = stream->memory;
 150     FT_Error   error  = FT_Err_Ok;
 151 
 152     FT_UNUSED( error );
 153 
 154 
 155     *point_cnt = 0;
 156 
 157     n = FT_GET_BYTE();
 158     if ( n == 0 )


 206 
 207         for ( j = 0; j < runcnt; j++ )
 208         {
 209           first      += FT_GET_BYTE();
 210           points[i++] = first;
 211           if ( i >= n )
 212             break;
 213         }
 214       }
 215     }
 216 
 217     return points;
 218   }
 219 
 220 
 221 #define GX_DT_DELTAS_ARE_ZERO       0x80U
 222 #define GX_DT_DELTAS_ARE_WORDS      0x40U
 223 #define GX_DT_DELTA_RUN_COUNT_MASK  0x3FU
 224 
 225 
 226   /**************************************************************************
 227    *
 228    * @Function:
 229    *   ft_var_readpackeddeltas
 230    *
 231    * @Description:
 232    *   Read a set of deltas.  These are packed slightly differently than
 233    *   points.  In particular there is no overall count.
 234    *
 235    * @Input:
 236    *   stream ::
 237    *     The data stream.
 238    *
 239    *   size ::
 240    *     The size of the table holding the data.
 241    *
 242    *   delta_cnt ::
 243    *     The number of deltas to be read.
 244    *
 245    * @Return:
 246    *   An array of FT_Fixed containing the deltas for the affected
 247    *   points.  (This only gets the deltas for one dimension.  It will
 248    *   generally be called twice, once for x, once for y.  When used in
 249    *   cvt table, it will only be called once.)
 250    *
 251    *   We use FT_Fixed to avoid accumulation errors while summing up all
 252    *   deltas (the rounding to integer values happens as the very last
 253    *   step).
 254    */
 255   static FT_Fixed*
 256   ft_var_readpackeddeltas( FT_Stream  stream,
 257                            FT_ULong   size,
 258                            FT_UInt    delta_cnt )
 259   {
 260     FT_Fixed  *deltas = NULL;
 261     FT_UInt    runcnt, cnt;
 262     FT_UInt    i, j;
 263     FT_Memory  memory = stream->memory;
 264     FT_Error   error  = FT_Err_Ok;
 265 
 266     FT_UNUSED( error );
 267 
 268 
 269     if ( delta_cnt > size )
 270     {
 271       FT_TRACE1(( "ft_var_readpackeddeltas: number of points too large\n" ));
 272       return NULL;
 273     }
 274 
 275     if ( FT_NEW_ARRAY( deltas, delta_cnt ) )
 276       return NULL;
 277 
 278     i = 0;
 279     while ( i < delta_cnt )
 280     {
 281       runcnt = FT_GET_BYTE();
 282       cnt    = runcnt & GX_DT_DELTA_RUN_COUNT_MASK;
 283 
 284       if ( runcnt & GX_DT_DELTAS_ARE_ZERO )
 285       {
 286         /* `runcnt' zeroes get added */
 287         for ( j = 0; j <= cnt && i < delta_cnt; j++ )
 288           deltas[i++] = 0;
 289       }
 290       else if ( runcnt & GX_DT_DELTAS_ARE_WORDS )
 291       {
 292         /* `runcnt' shorts from the stack */
 293         for ( j = 0; j <= cnt && i < delta_cnt; j++ )
 294           deltas[i++] = FT_intToFixed( FT_GET_SHORT() );
 295       }
 296       else
 297       {
 298         /* `runcnt' signed bytes from the stack */
 299         for ( j = 0; j <= cnt && i < delta_cnt; j++ )
 300           deltas[i++] = FT_intToFixed( FT_GET_CHAR() );
 301       }
 302 
 303       if ( j <= cnt )
 304       {
 305         /* bad format */
 306         FT_FREE( deltas );
 307         return NULL;
 308       }
 309     }
 310 
 311     return deltas;
 312   }
 313 
 314 
 315   /**************************************************************************
 316    *
 317    * @Function:
 318    *   ft_var_load_avar
 319    *
 320    * @Description:
 321    *   Parse the `avar' table if present.  It need not be, so we return
 322    *   nothing.
 323    *
 324    * @InOut:
 325    *   face ::
 326    *     The font face.
 327    */
 328   static void
 329   ft_var_load_avar( TT_Face  face )
 330   {
 331     FT_Stream       stream = FT_FACE_STREAM( face );
 332     FT_Memory       memory = stream->memory;
 333     GX_Blend        blend  = face->blend;
 334     GX_AVarSegment  segment;
 335     FT_Error        error = FT_Err_Ok;
 336     FT_Long         version;
 337     FT_Long         axisCount;
 338     FT_Int          i, j;
 339     FT_ULong        table_len;
 340 
 341     FT_UNUSED( error );
 342 
 343 
 344     FT_TRACE2(( "AVAR " ));
 345 
 346     blend->avar_loaded = TRUE;
 347     error = face->goto_table( face, TTAG_avar, stream, &table_len );


 397 
 398       for ( j = 0; j < segment->pairCount; j++ )
 399       {
 400         /* convert to Fixed */
 401         segment->correspondence[j].fromCoord = FT_GET_SHORT() * 4;
 402         segment->correspondence[j].toCoord   = FT_GET_SHORT() * 4;
 403 
 404         FT_TRACE5(( "    mapping %.5f to %.5f\n",
 405                     segment->correspondence[j].fromCoord / 65536.0,
 406                     segment->correspondence[j].toCoord / 65536.0 ));
 407       }
 408 
 409       FT_TRACE5(( "\n" ));
 410     }
 411 
 412   Exit:
 413     FT_FRAME_EXIT();
 414   }
 415 
 416 











 417   static FT_Error
 418   ft_var_load_item_variation_store( TT_Face          face,
 419                                     FT_ULong         offset,
 420                                     GX_ItemVarStore  itemStore )
 421   {
 422     FT_Stream  stream = FT_FACE_STREAM( face );
 423     FT_Memory  memory = stream->memory;
 424 
 425     FT_Error   error;
 426     FT_UShort  format;
 427     FT_ULong   region_offset;
 428     FT_UInt    i, j, k;
 429     FT_UInt    shortDeltaCount;
 430 
 431     GX_Blend        blend = face->blend;
 432     GX_ItemVarData  varData;
 433 
 434     FT_ULong*  dataOffsetArray = NULL;
 435 
 436 


 694 
 695       innerIndex = mapData & innerIndexMask;
 696 
 697       if ( innerIndex >= itemStore->varData[outerIndex].itemCount )
 698       {
 699         FT_TRACE2(( "innerIndex[%d] == %d out of range\n",
 700                     i,
 701                     innerIndex ));
 702         error = FT_THROW( Invalid_Table );
 703           goto Exit;
 704       }
 705 
 706       map->innerIndex[i] = innerIndex;
 707     }
 708 
 709   Exit:
 710     return error;
 711   }
 712 
 713 
 714   /**************************************************************************
 715    *
 716    * @Function:
 717    *   ft_var_load_hvvar
 718    *
 719    * @Description:
 720    *   If `vertical' is zero, parse the `HVAR' table and set
 721    *   `blend->hvar_loaded' to TRUE.  On success, `blend->hvar_checked'
 722    *   is set to TRUE.
 723    *
 724    *   If `vertical' is not zero, parse the `VVAR' table and set
 725    *   `blend->vvar_loaded' to TRUE.  On success, `blend->vvar_checked'
 726    *   is set to TRUE.
 727    *
 728    *   Some memory may remain allocated on error; it is always freed in
 729    *   `tt_done_blend', however.
 730    *
 731    * @InOut:
 732    *   face ::
 733    *     The font face.
 734    *
 735    * @Return:
 736    *   FreeType error code.  0 means success.
 737    */
 738   static FT_Error
 739   ft_var_load_hvvar( TT_Face  face,
 740                      FT_Bool  vertical )
 741   {
 742     FT_Stream  stream = FT_FACE_STREAM( face );
 743     FT_Memory  memory = stream->memory;
 744 
 745     GX_Blend  blend = face->blend;
 746 
 747     GX_HVVarTable  table;
 748 
 749     FT_Error   error;
 750     FT_UShort  majorVersion;
 751     FT_ULong   table_len;
 752     FT_ULong   table_offset;
 753     FT_ULong   store_offset;
 754     FT_ULong   widthMap_offset;
 755 
 756 
 757     if ( vertical )


 865                          FT_UInt          innerIndex )
 866   {
 867     GX_ItemVarData  varData;
 868     FT_Short*       deltaSet;
 869 
 870     FT_UInt   master, j;
 871     FT_Fixed  netAdjustment = 0;     /* accumulated adjustment */
 872     FT_Fixed  scaledDelta;
 873     FT_Fixed  delta;
 874 
 875 
 876     /* See pseudo code from `Font Variations Overview' */
 877     /* in the OpenType specification.                  */
 878 
 879     varData  = &itemStore->varData[outerIndex];
 880     deltaSet = &varData->deltaSet[varData->regionIdxCount * innerIndex];
 881 
 882     /* outer loop steps through master designs to be blended */
 883     for ( master = 0; master < varData->regionIdxCount; master++ )
 884     {
 885       FT_Fixed  scalar      = 0x10000L;
 886       FT_UInt   regionIndex = varData->regionIndices[master];
 887 
 888       GX_AxisCoords  axis = itemStore->varRegionList[regionIndex].axisList;
 889 
 890 
 891       /* inner loop steps through axes in this region */
 892       for ( j = 0; j < itemStore->axisCount; j++, axis++ )
 893       {



 894         /* compute the scalar contribution of this axis; */
 895         /* ignore invalid ranges                         */
 896         if ( axis->startCoord > axis->peakCoord ||
 897              axis->peakCoord > axis->endCoord   )
 898           continue;
 899 
 900         else if ( axis->startCoord < 0 &&
 901                   axis->endCoord > 0   &&
 902                   axis->peakCoord != 0 )
 903           continue;
 904 
 905         /* peak of 0 means ignore this axis */
 906         else if ( axis->peakCoord == 0 )
 907           continue;
 908 
 909         else if ( face->blend->normalizedcoords[j] == axis->peakCoord )
 910           continue;


 911 
 912         /* ignore this region if coords are out of range */
 913         else if ( face->blend->normalizedcoords[j] <= axis->startCoord ||
 914                   face->blend->normalizedcoords[j] >= axis->endCoord   )
 915         {
 916           scalar = 0;
 917           break;
 918         }
 919 
 920         /* cumulative product of all the axis scalars */
 921         else if ( face->blend->normalizedcoords[j] < axis->peakCoord )
 922           scalar =
 923             FT_MulDiv( scalar,
 924                        face->blend->normalizedcoords[j] - axis->startCoord,
 925                        axis->peakCoord - axis->startCoord );
 926         else
 927           scalar =
 928             FT_MulDiv( scalar,
 929                        axis->endCoord - face->blend->normalizedcoords[j],
 930                        axis->endCoord - axis->peakCoord );





 931       } /* per-axis loop */
 932 
 933       /* get the scaled delta for this region */
 934       delta       = FT_intToFixed( deltaSet[master] );
 935       scaledDelta = FT_MulFix( scalar, delta );
 936 
 937       /* accumulate the adjustments from each region */
 938       netAdjustment = netAdjustment + scaledDelta;
 939 
 940     } /* per-region loop */
 941 
 942     return FT_fixedToInt( netAdjustment );
 943   }
 944 
 945 
 946   /**************************************************************************
 947    *
 948    * @Function:
 949    *   tt_hvadvance_adjust
 950    *
 951    * @Description:
 952    *   Apply `HVAR' advance width or `VVAR' advance height adjustment of
 953    *   a given glyph.
 954    *
 955    * @Input:
 956    *   gindex ::
 957    *     The glyph index.
 958    *
 959    *   vertical ::
 960    *     If set, handle `VVAR' table.
 961    *
 962    * @InOut:
 963    *   face ::
 964    *     The font face.
 965    *
 966    *   adelta ::
 967    *     Points to width or height value that gets modified.
 968    */
 969   static FT_Error
 970   tt_hvadvance_adjust( TT_Face  face,
 971                        FT_UInt  gindex,
 972                        FT_Int  *avalue,
 973                        FT_Bool  vertical )
 974   {
 975     FT_Error  error = FT_Err_Ok;
 976     FT_UInt   innerIndex, outerIndex;
 977     FT_Int    delta;
 978 
 979     GX_HVVarTable  table;
 980 
 981 
 982     if ( !face->doblend || !face->blend )
 983       goto Exit;
 984 
 985     if ( vertical )
 986     {
 987       if ( !face->blend->vvar_loaded )
 988       {


1144       GX_VALUE_CASE( STRS, os2.yStrikeoutSize );
1145       GX_VALUE_CASE( UNDO, postscript.underlinePosition );
1146       GX_VALUE_CASE( UNDS, postscript.underlineThickness );
1147       GX_VALUE_CASE( VASC, vertical.Ascender );
1148       GX_VALUE_CASE( VCOF, vertical.caret_Offset );
1149       GX_VALUE_CASE( VCRN, vertical.caret_Slope_Run );
1150       GX_VALUE_CASE( VCRS, vertical.caret_Slope_Rise );
1151       GX_VALUE_CASE( VDSC, vertical.Descender );
1152       GX_VALUE_CASE( VLGP, vertical.Line_Gap );
1153       GX_VALUE_CASE( XHGT, os2.sxHeight );
1154 
1155     default:
1156       /* ignore unknown tag */
1157       p = NULL;
1158     }
1159 
1160     return p;
1161   }
1162 
1163 
1164   /**************************************************************************
1165    *
1166    * @Function:
1167    *   ft_var_load_mvar
1168    *
1169    * @Description:
1170    *   Parse the `MVAR' table.
1171    *
1172    *   Some memory may remain allocated on error; it is always freed in
1173    *   `tt_done_blend', however.
1174    *
1175    * @InOut:
1176    *   face ::
1177    *     The font face.
1178    */
1179   static void
1180   ft_var_load_mvar( TT_Face  face )
1181   {
1182     FT_Stream  stream = FT_FACE_STREAM( face );
1183     FT_Memory  memory = stream->memory;
1184 
1185     GX_Blend         blend = face->blend;
1186     GX_ItemVarStore  itemStore;
1187     GX_Value         value, limit;
1188 
1189     FT_Error   error;
1190     FT_UShort  majorVersion;
1191     FT_ULong   table_len;
1192     FT_ULong   table_offset;
1193     FT_UShort  store_offset;
1194     FT_ULong   records_offset;
1195 
1196 
1197     FT_TRACE2(( "MVAR " ));
1198 


1291 
1292     face->variation_support |= TT_FACE_FLAG_VAR_MVAR;
1293   }
1294 
1295 
1296   static FT_Error
1297   tt_size_reset_iterator( FT_ListNode  node,
1298                           void*        user )
1299   {
1300     TT_Size  size = (TT_Size)node->data;
1301 
1302     FT_UNUSED( user );
1303 
1304 
1305     tt_size_reset( size, 1 );
1306 
1307     return FT_Err_Ok;
1308   }
1309 
1310 
1311   /**************************************************************************
1312    *
1313    * @Function:
1314    *   tt_apply_mvar
1315    *
1316    * @Description:
1317    *   Apply `MVAR' table adjustments.
1318    *
1319    * @InOut:
1320    *   face ::
1321    *     The font face.
1322    */
1323   FT_LOCAL_DEF( void )
1324   tt_apply_mvar( TT_Face  face )
1325   {
1326     GX_Blend  blend = face->blend;
1327     GX_Value  value, limit;
1328     FT_Short  mvar_hasc_delta = 0;
1329     FT_Short  mvar_hdsc_delta = 0;
1330     FT_Short  mvar_hlgp_delta = 0;
1331 
1332 
1333     if ( !( face->variation_support & TT_FACE_FLAG_VAR_MVAR ) )
1334       return;
1335 
1336     value = blend->mvar_table->values;
1337     limit = value + blend->mvar_table->valueCount;
1338 
1339     for ( ; value < limit; value++ )
1340     {
1341       FT_Short*  p = ft_var_get_value_pointer( face, value->tag );
1342       FT_Int     delta;
1343 
1344 
1345       delta = ft_var_get_item_delta( face,
1346                                      &blend->mvar_table->itemStore,
1347                                      value->outerIndex,
1348                                      value->innerIndex );
1349 
1350       if ( p )
1351       {
1352         FT_TRACE5(( "value %c%c%c%c (%d unit%s) adjusted by %d unit%s (MVAR)\n",
1353                     (FT_Char)( value->tag >> 24 ),
1354                     (FT_Char)( value->tag >> 16 ),
1355                     (FT_Char)( value->tag >> 8 ),
1356                     (FT_Char)( value->tag ),
1357                     value->unmodified,
1358                     value->unmodified == 1 ? "" : "s",
1359                     delta,
1360                     delta == 1 ? "" : "s" ));
1361 
1362         /* since we handle both signed and unsigned values as FT_Short, */
1363         /* ensure proper overflow arithmetic                            */
1364         *p = (FT_Short)( value->unmodified + (FT_Short)delta );
1365 
1366         /* Treat hasc, hdsc and hlgp specially, see below. */
1367         if ( value->tag == MVAR_TAG_HASC )
1368           mvar_hasc_delta = (FT_Short)delta;
1369         else if ( value->tag == MVAR_TAG_HDSC )
1370           mvar_hdsc_delta = (FT_Short)delta;
1371         else if ( value->tag == MVAR_TAG_HLGP )
1372           mvar_hlgp_delta = (FT_Short)delta;
1373       }
1374     }
1375 
1376     /* adjust all derived values */
1377     {
1378       FT_Face  root = &face->root;
1379 
1380       /*
1381        * Apply the deltas of hasc, hdsc and hlgp to the FT_Face's ascender,
1382        * descender and height attributes, no matter how they were originally
1383        * computed.
1384        *
1385        * (Code that ignores those and accesses the font's metrics values
1386        * directly is already served by the delta application code above.)
1387        *
1388        * The MVAR table supports variations for both typo and win metrics.
1389        * According to Behdad Esfahbod, the thinking of the working group was
1390        * that no one uses win metrics anymore for setting line metrics (the
1391        * specification even calls these metrics "horizontal clipping
1392        * ascent/descent", probably for their role on the Windows platform in
1393        * computing clipping boxes), and new fonts should use typo metrics, so
1394        * typo deltas should be applied to whatever sfnt_load_face decided the
1395        * line metrics should be.
1396        *
1397        * Before, the following led to different line metrics between default
1398        * outline and instances, visible when e.g. the default outlines were
1399        * used as the regular face and instances for everything else:
1400        *
1401        * 1. sfnt_load_face applied the hhea metrics by default.
1402        * 2. This code later applied the typo metrics by default, regardless of
1403        *    whether they were actually changed or the font had the OS/2 table's
1404        *    fsSelection's bit 7 (USE_TYPO_METRICS) set.
1405        */
1406       FT_Short  current_line_gap = root->height - root->ascender +
1407                                    root->descender;
1408 






1409 
1410       root->ascender  = root->ascender + mvar_hasc_delta;
1411       root->descender = root->descender + mvar_hdsc_delta;
1412       root->height    = root->ascender - root->descender +
1413                         current_line_gap + mvar_hlgp_delta;









1414 
1415       root->underline_position  = face->postscript.underlinePosition -
1416                                   face->postscript.underlineThickness / 2;
1417       root->underline_thickness = face->postscript.underlineThickness;
1418 
1419       /* iterate over all FT_Size objects and call `tt_size_reset' */
1420       /* to propagate the metrics changes                          */
1421       FT_List_Iterate( &root->sizes_list,
1422                        tt_size_reset_iterator,
1423                        NULL );
1424     }
1425   }
1426 
1427 
1428   typedef struct  GX_GVar_Head_
1429   {
1430     FT_Long    version;
1431     FT_UShort  axisCount;
1432     FT_UShort  globalCoordCount;
1433     FT_ULong   offsetToCoord;
1434     FT_UShort  glyphCount;
1435     FT_UShort  flags;
1436     FT_ULong   offsetToData;
1437 
1438   } GX_GVar_Head;
1439 
1440 
1441   /**************************************************************************
1442    *
1443    * @Function:
1444    *   ft_var_load_gvar
1445    *
1446    * @Description:
1447    *   Parse the `gvar' table if present.  If `fvar' is there, `gvar' had
1448    *   better be there too.
1449    *
1450    * @InOut:
1451    *   face ::
1452    *     The font face.
1453    *
1454    * @Return:
1455    *   FreeType error code.  0 means success.
1456    */
1457   static FT_Error
1458   ft_var_load_gvar( TT_Face  face )
1459   {
1460     FT_Stream     stream = FT_FACE_STREAM( face );
1461     FT_Memory     memory = stream->memory;
1462     GX_Blend      blend  = face->blend;
1463     FT_Error      error;
1464     FT_UInt       i, j;
1465     FT_ULong      table_len;
1466     FT_ULong      gvar_start;
1467     FT_ULong      offsetToData;
1468     GX_GVar_Head  gvar_head;
1469 
1470     static const FT_Frame_Field  gvar_fields[] =
1471     {
1472 
1473 #undef  FT_STRUCTURE
1474 #define FT_STRUCTURE  GX_GVar_Head
1475 
1476       FT_FRAME_START( 20 ),


1534       goto Exit;
1535     }
1536 
1537     FT_TRACE2(( "loaded\n" ));
1538 
1539     blend->gvar_size   = table_len;
1540     blend->tuplecount  = gvar_head.globalCoordCount;
1541     blend->gv_glyphcnt = gvar_head.glyphCount;
1542     offsetToData       = gvar_start + gvar_head.offsetToData;
1543 
1544     FT_TRACE5(( "gvar: there %s %d shared coordinate%s:\n",
1545                 blend->tuplecount == 1 ? "is" : "are",
1546                 blend->tuplecount,
1547                 blend->tuplecount == 1 ? "" : "s" ));
1548 
1549     if ( FT_NEW_ARRAY( blend->glyphoffsets, blend->gv_glyphcnt + 1 ) )
1550       goto Exit;
1551 
1552     if ( gvar_head.flags & 1 )
1553     {
1554       FT_ULong  limit = gvar_start + table_len;
1555 
1556 
1557       /* long offsets (one more offset than glyphs, to mark size of last) */
1558       if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 4L ) )
1559         goto Exit;
1560 
1561       for ( i = 0; i <= blend->gv_glyphcnt; i++ )
1562       {
1563         blend->glyphoffsets[i] = offsetToData + FT_GET_ULONG();
1564         /* use `>', not `>=' */
1565         if ( blend->glyphoffsets[i] > limit )
1566         {
1567           FT_TRACE2(( "ft_var_load_gvar:"
1568                       " invalid glyph variation data offset for index %d\n",
1569                       i ));
1570           error = FT_THROW( Invalid_Table );
1571           break;
1572         }
1573       }
1574     }
1575     else
1576     {
1577       FT_ULong  limit = gvar_start + table_len;
1578 
1579 
1580       /* short offsets (one more offset than glyphs, to mark size of last) */
1581       if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 2L ) )
1582         goto Exit;
1583 
1584       for ( i = 0; i <= blend->gv_glyphcnt; i++ )
1585       {
1586         blend->glyphoffsets[i] = offsetToData + FT_GET_USHORT() * 2;
1587         /* use `>', not `>=' */
1588         if ( blend->glyphoffsets[i] > limit )
1589         {
1590           FT_TRACE2(( "ft_var_load_gvar:"
1591                       " invalid glyph variation data offset for index %d\n",
1592                       i ));
1593           error = FT_THROW( Invalid_Table );
1594           break;
1595         }
1596       }
1597     }
1598 
1599     FT_FRAME_EXIT();
1600     if ( error )
1601       goto Exit;
1602 
1603     if ( blend->tuplecount != 0 )
1604     {
1605       if ( FT_NEW_ARRAY( blend->tuplecoords,
1606                          gvar_head.axisCount * blend->tuplecount ) )
1607         goto Exit;
1608 
1609       if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord )         ||
1610            FT_FRAME_ENTER( blend->tuplecount * gvar_head.axisCount * 2L ) )
1611         goto Exit;
1612 
1613       for ( i = 0; i < blend->tuplecount; i++ )
1614       {
1615         FT_TRACE5(( "  [ " ));
1616         for ( j = 0; j < (FT_UInt)gvar_head.axisCount; j++ )
1617         {
1618           blend->tuplecoords[i * gvar_head.axisCount + j] =
1619             FT_GET_SHORT() * 4;                 /* convert to FT_Fixed */
1620           FT_TRACE5(( "%.5f ",
1621             blend->tuplecoords[i * gvar_head.axisCount + j] / 65536.0 ));
1622         }
1623         FT_TRACE5(( "]\n" ));
1624       }
1625 
1626       FT_TRACE5(( "\n" ));
1627 
1628       FT_FRAME_EXIT();
1629     }
1630 
1631   Exit:
1632     return error;
1633   }
1634 
1635 
1636   /**************************************************************************
1637    *
1638    * @Function:
1639    *   ft_var_apply_tuple
1640    *
1641    * @Description:
1642    *   Figure out whether a given tuple (design) applies to the current
1643    *   blend, and if so, what is the scaling factor.
1644    *
1645    * @Input:
1646    *   blend ::
1647    *     The current blend of the font.
1648    *
1649    *   tupleIndex ::
1650    *     A flag saying whether this is an intermediate
1651    *     tuple or not.
1652    *
1653    *   tuple_coords ::
1654    *     The coordinates of the tuple in normalized axis
1655    *     units.
1656    *
1657    *   im_start_coords ::
1658    *     The initial coordinates where this tuple starts
1659    *     to apply (for intermediate coordinates).
1660    *
1661    *   im_end_coords ::
1662    *     The final coordinates after which this tuple no
1663    *     longer applies (for intermediate coordinates).
1664    *
1665    * @Return:
1666    *   An FT_Fixed value containing the scaling factor.
1667    */
1668   static FT_Fixed
1669   ft_var_apply_tuple( GX_Blend   blend,
1670                       FT_UShort  tupleIndex,
1671                       FT_Fixed*  tuple_coords,
1672                       FT_Fixed*  im_start_coords,
1673                       FT_Fixed*  im_end_coords )
1674   {
1675     FT_UInt   i;
1676     FT_Fixed  apply = 0x10000L;
1677 
1678 
1679     for ( i = 0; i < blend->num_axis; i++ )
1680     {
1681       FT_TRACE6(( "    axis %d coordinate %.5f:\n",
1682                   i, blend->normalizedcoords[i] / 65536.0 ));





1683 
1684       /* It's not clear why (for intermediate tuples) we don't need     */
1685       /* to check against start/end -- the documentation says we don't. */
1686       /* Similarly, it's unclear why we don't need to scale along the   */
1687       /* axis.                                                          */
1688 
1689       if ( tuple_coords[i] == 0 )
1690       {
1691         FT_TRACE6(( "      tuple coordinate is zero, ignore\n", i ));
1692         continue;
1693       }
1694 
1695       if ( blend->normalizedcoords[i] == 0 )
1696       {
1697         FT_TRACE6(( "      axis coordinate is zero, stop\n" ));
1698         apply = 0;
1699         break;
1700       }
1701 
1702       if ( blend->normalizedcoords[i] == tuple_coords[i] )
1703       {
1704         FT_TRACE6(( "      tuple coordinate %.5f fits perfectly\n",
1705                     tuple_coords[i] / 65536.0 ));
1706         /* `apply' does not change */
1707         continue;
1708       }
1709 
1710       if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) )
1711       {
1712         /* not an intermediate tuple */
1713 
1714         if ( blend->normalizedcoords[i] < FT_MIN( 0, tuple_coords[i] ) ||
1715              blend->normalizedcoords[i] > FT_MAX( 0, tuple_coords[i] ) )
1716         {
1717           FT_TRACE6(( "      tuple coordinate %.5f is exceeded, stop\n",
1718                       tuple_coords[i] / 65536.0 ));
1719           apply = 0;
1720           break;
1721         }
1722 
1723         FT_TRACE6(( "      tuple coordinate %.5f fits\n",
1724                     tuple_coords[i] / 65536.0 ));
1725         apply = FT_MulDiv( apply,
1726                            blend->normalizedcoords[i],
1727                            tuple_coords[i] );
1728       }
1729       else
1730       {
1731         /* intermediate tuple */
1732 
1733         if ( blend->normalizedcoords[i] <= im_start_coords[i] ||
1734              blend->normalizedcoords[i] >= im_end_coords[i]   )
1735         {
1736           FT_TRACE6(( "      intermediate tuple range ]%.5f;%.5f[ is exceeded,"
1737                       " stop\n",
1738                       im_start_coords[i] / 65536.0,
1739                       im_end_coords[i] / 65536.0 ));
1740           apply = 0;
1741           break;
1742         }
1743 
1744         FT_TRACE6(( "      intermediate tuple range ]%.5f;%.5f[ fits\n",


1745                     im_start_coords[i] / 65536.0,
1746                     im_end_coords[i] / 65536.0 ));
1747         if ( blend->normalizedcoords[i] < tuple_coords[i] )
1748           apply = FT_MulDiv( apply,
1749                              blend->normalizedcoords[i] - im_start_coords[i],
1750                              tuple_coords[i] - im_start_coords[i] );


1751         else




1752           apply = FT_MulDiv( apply,
1753                              im_end_coords[i] - blend->normalizedcoords[i],
1754                              im_end_coords[i] - tuple_coords[i] );
1755       }
1756     }

1757 
1758     FT_TRACE6(( "    apply factor is %.5f\n", apply / 65536.0 ));
1759 
1760     return apply;
1761   }
1762 
1763 
1764   /* convert from design coordinates to normalized coordinates */
1765 
1766   static void
1767   ft_var_to_normalized( TT_Face    face,
1768                         FT_UInt    num_coords,
1769                         FT_Fixed*  coords,
1770                         FT_Fixed*  normalized )
1771   {
1772     GX_Blend        blend;
1773     FT_MM_Var*      mmvar;
1774     FT_UInt         i, j;
1775     FT_Var_Axis*    a;
1776     GX_AVarSegment  av;


1797       FT_Fixed  coord = coords[i];
1798 
1799 
1800       FT_TRACE5(( "    %d: %.5f\n", i, coord / 65536.0 ));
1801       if ( coord > a->maximum || coord < a->minimum )
1802       {
1803         FT_TRACE1((
1804           "ft_var_to_normalized: design coordinate %.5f\n"
1805           "                      is out of range [%.5f;%.5f]; clamping\n",
1806           coord / 65536.0,
1807           a->minimum / 65536.0,
1808           a->maximum / 65536.0 ));
1809 
1810         if ( coord > a->maximum )
1811           coord = a->maximum;
1812         else
1813           coord = a->minimum;
1814       }
1815 
1816       if ( coord < a->def )
1817         normalized[i] = -FT_DivFix( SUB_LONG( coord, a->def ),
1818                                     SUB_LONG( a->minimum, a->def ) );
1819       else if ( coord > a->def )
1820         normalized[i] = FT_DivFix( SUB_LONG( coord, a->def ),
1821                                    SUB_LONG( a->maximum, a->def ) );
1822       else
1823         normalized[i] = 0;
1824     }
1825 
1826     FT_TRACE5(( "\n" ));
1827 
1828     for ( ; i < mmvar->num_axis; i++ )
1829       normalized[i] = 0;
1830 
1831     if ( blend->avar_segment )
1832     {
1833       FT_TRACE5(( "normalized design coordinates"
1834                   " before applying `avar' data:\n" ));
1835 
1836       av = blend->avar_segment;
1837       for ( i = 0; i < mmvar->num_axis; i++, av++ )
1838       {
1839         for ( j = 1; j < (FT_UInt)av->pairCount; j++ )
1840         {
1841           if ( normalized[i] < av->correspondence[j].fromCoord )


1951     FT_UShort  axisCount;
1952     FT_UShort  axisSize;
1953     FT_UShort  instanceCount;
1954     FT_UShort  instanceSize;
1955 
1956   } GX_FVar_Head;
1957 
1958 
1959   typedef struct  fvar_axis_
1960   {
1961     FT_ULong   axisTag;
1962     FT_Fixed   minValue;
1963     FT_Fixed   defaultValue;
1964     FT_Fixed   maxValue;
1965     FT_UShort  flags;
1966     FT_UShort  nameID;
1967 
1968   } GX_FVar_Axis;
1969 
1970 
1971   /**************************************************************************
1972    *
1973    * @Function:
1974    *   TT_Get_MM_Var
1975    *
1976    * @Description:
1977    *   Check that the font's `fvar' table is valid, parse it, and return
1978    *   those data.  It also loads (and parses) the `MVAR' table, if
1979    *   possible.
1980    *
1981    * @InOut:
1982    *   face ::
1983    *     The font face.
1984    *     TT_Get_MM_Var initializes the blend structure.
1985    *
1986    * @Output:
1987    *   master ::
1988    *     The `fvar' data (must be freed by caller).  Can be NULL,
1989    *     which makes this function simply load MM support.
1990    *
1991    * @Return:
1992    *   FreeType error code.  0 means success.
1993    */
1994   FT_LOCAL_DEF( FT_Error )
1995   TT_Get_MM_Var( TT_Face      face,
1996                  FT_MM_Var*  *master )
1997   {
1998     FT_Stream            stream     = face->root.stream;
1999     FT_Memory            memory     = face->root.memory;
2000     FT_ULong             table_len;
2001     FT_Error             error      = FT_Err_Ok;
2002     FT_ULong             fvar_start = 0;
2003     FT_UInt              i, j;
2004     FT_MM_Var*           mmvar = NULL;
2005     FT_Fixed*            next_coords;
2006     FT_Fixed*            nsc;
2007     FT_String*           next_name;
2008     FT_Var_Axis*         a;
2009     FT_Fixed*            c;
2010     FT_Var_Named_Style*  ns;
2011     GX_FVar_Head         fvar_head;
2012     FT_Bool              usePsName  = 0;
2013     FT_UInt              num_instances;


2550       FT_Bool    have_diff = 0;
2551       FT_UInt    j;
2552       FT_Fixed*  c;
2553       FT_Fixed*  n;
2554 
2555 
2556       manageCvt = mcvt_retain;
2557 
2558       for ( i = 0; i < num_coords; i++ )
2559       {
2560         if ( blend->normalizedcoords[i] != coords[i] )
2561         {
2562           manageCvt = mcvt_load;
2563           have_diff = 1;
2564           break;
2565         }
2566       }
2567 
2568       if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) )
2569       {
2570         FT_UInt  instance_index = (FT_UInt)face->root.face_index >> 16;
2571 
2572 
2573         c = blend->normalizedcoords + i;
2574         n = blend->normalized_stylecoords            +
2575             ( instance_index - 1 ) * mmvar->num_axis +
2576             i;
2577 
2578         for ( j = i; j < mmvar->num_axis; j++, n++, c++ )
2579           if ( *c != *n )
2580             have_diff = 1;
2581       }
2582       else
2583       {
2584         c = blend->normalizedcoords + i;
2585         for ( j = i; j < mmvar->num_axis; j++, c++ )
2586           if ( *c != 0 )
2587             have_diff = 1;
2588       }
2589 
2590       /* return value -1 indicates `no change' */
2591       if ( !have_diff )
2592       {
2593         face->doblend = TRUE;
2594 
2595         return -1;
2596       }
2597 
2598       for ( ; i < mmvar->num_axis; i++ )
2599       {
2600         if ( blend->normalizedcoords[i] != 0 )
2601         {
2602           manageCvt = mcvt_load;
2603           break;
2604         }
2605       }
2606 
2607       /* If we don't change the blend coords then we don't need to do  */
2608       /* anything to the cvt table.  It will be correct.  Otherwise we */
2609       /* no longer have the original cvt (it was modified when we set  */
2610       /* the blend last time), so we must reload and then modify it.   */
2611     }
2612 
2613     blend->num_axis = mmvar->num_axis;
2614     FT_MEM_COPY( blend->normalizedcoords,
2615                  coords,
2616                  num_coords * sizeof ( FT_Fixed ) );


2640         /* The original cvt table is in memory.  All we need to do is */
2641         /* apply the `cvar' table (if any).                           */
2642         error = tt_face_vary_cvt( face, face->root.stream );
2643         break;
2644 
2645       case mcvt_retain:
2646         /* The cvt table is correct for this set of coordinates. */
2647         break;
2648       }
2649     }
2650 
2651     /* enforce recomputation of the PostScript name; */
2652     FT_FREE( face->postscript_name );
2653     face->postscript_name = NULL;
2654 
2655   Exit:
2656     return error;
2657   }
2658 
2659 
2660   /**************************************************************************
2661    *
2662    * @Function:
2663    *   TT_Set_MM_Blend
2664    *
2665    * @Description:
2666    *   Set the blend (normalized) coordinates for this instance of the
2667    *   font.  Check that the `gvar' table is reasonable and does some
2668    *   initial preparation.
2669    *
2670    * @InOut:
2671    *   face ::
2672    *     The font.
2673    *     Initialize the blend structure with `gvar' data.
2674    *
2675    * @Input:
2676    *   num_coords ::
2677    *     The number of available coordinates.  If it is
2678    *     larger than the number of axes, ignore the excess
2679    *     values.  If it is smaller than the number of axes,
2680    *     use the default value (0) for the remaining axes.
2681    *
2682    *   coords ::
2683    *     An array of `num_coords', each between [-1,1].
2684    *
2685    * @Return:
2686    *   FreeType error code.  0 means success.
2687    */
2688   FT_LOCAL_DEF( FT_Error )
2689   TT_Set_MM_Blend( TT_Face    face,
2690                    FT_UInt    num_coords,
2691                    FT_Fixed*  coords )
2692   {
2693     FT_Error  error;
2694 
2695 
2696     error = tt_set_mm_blend( face, num_coords, coords, 1 );
2697     if ( error )
2698       return error;
2699 
2700     if ( num_coords )
2701       face->root.face_flags |= FT_FACE_FLAG_VARIATION;
2702     else
2703       face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
2704 
2705     return FT_Err_Ok;
2706   }
2707 
2708 
2709   /**************************************************************************
2710    *
2711    * @Function:
2712    *   TT_Get_MM_Blend
2713    *
2714    * @Description:
2715    *   Get the blend (normalized) coordinates for this instance of the
2716    *   font.
2717    *
2718    * @InOut:
2719    *   face ::
2720    *     The font.
2721    *     Initialize the blend structure with `gvar' data.
2722    *
2723    * @Input:
2724    *   num_coords ::
2725    *     The number of available coordinates.  If it is
2726    *     larger than the number of axes, set the excess
2727    *     values to 0.
2728    *
2729    *   coords ::
2730    *     An array of `num_coords', each between [-1,1].
2731    *
2732    * @Return:
2733    *   FreeType error code.  0 means success.
2734    */
2735   FT_LOCAL_DEF( FT_Error )
2736   TT_Get_MM_Blend( TT_Face    face,
2737                    FT_UInt    num_coords,
2738                    FT_Fixed*  coords )
2739   {
2740     FT_Error  error = FT_Err_Ok;
2741     GX_Blend  blend;
2742     FT_UInt   i, nc;
2743 
2744 
2745     if ( !face->blend )
2746     {
2747       if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
2748         return error;
2749     }
2750 
2751     blend = face->blend;
2752 
2753     if ( !blend->coords )
2754     {


2768     }
2769 
2770     if ( face->doblend )
2771     {
2772       for ( i = 0; i < nc; i++ )
2773         coords[i] = blend->normalizedcoords[i];
2774     }
2775     else
2776     {
2777       for ( i = 0; i < nc; i++ )
2778         coords[i] = 0;
2779     }
2780 
2781     for ( ; i < num_coords; i++ )
2782       coords[i] = 0;
2783 
2784     return FT_Err_Ok;
2785   }
2786 
2787 
2788   /**************************************************************************
2789    *
2790    * @Function:
2791    *   TT_Set_Var_Design
2792    *
2793    * @Description:
2794    *   Set the coordinates for the instance, measured in the user
2795    *   coordinate system.  Parse the `avar' table (if present) to convert
2796    *   from user to normalized coordinates.
2797    *
2798    * @InOut:
2799    *   face ::
2800    *     The font face.
2801    *     Initialize the blend struct with `gvar' data.
2802    *
2803    * @Input:
2804    *   num_coords ::
2805    *     The number of available coordinates.  If it is
2806    *     larger than the number of axes, ignore the excess
2807    *     values.  If it is smaller than the number of axes,
2808    *     use the default values for the remaining axes.
2809    *
2810    *   coords ::
2811    *     A coordinate array with `num_coords' elements.
2812    *
2813    * @Return:
2814    *   FreeType error code.  0 means success.
2815    */
2816   FT_LOCAL_DEF( FT_Error )
2817   TT_Set_Var_Design( TT_Face    face,
2818                      FT_UInt    num_coords,
2819                      FT_Fixed*  coords )
2820   {
2821     FT_Error    error  = FT_Err_Ok;
2822     GX_Blend    blend;
2823     FT_MM_Var*  mmvar;
2824     FT_UInt     i;
2825     FT_Memory   memory = face->root.memory;
2826 
2827     FT_Fixed*  c;
2828     FT_Fixed*  n;
2829     FT_Fixed*  normalized = NULL;
2830 
2831     FT_Bool  have_diff = 0;
2832 
2833 
2834     if ( !face->blend )
2835     {


2913 
2914     FT_TRACE5(( "TT_Set_Var_Design:\n"
2915                 "  normalized design coordinates:\n" ));
2916     ft_var_to_normalized( face, num_coords, blend->coords, normalized );
2917 
2918     error = tt_set_mm_blend( face, mmvar->num_axis, normalized, 0 );
2919     if ( error )
2920       goto Exit;
2921 
2922     if ( num_coords )
2923       face->root.face_flags |= FT_FACE_FLAG_VARIATION;
2924     else
2925       face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
2926 
2927   Exit:
2928     FT_FREE( normalized );
2929     return error;
2930   }
2931 
2932 
2933   /**************************************************************************
2934    *
2935    * @Function:
2936    *   TT_Get_Var_Design
2937    *
2938    * @Description:
2939    *   Get the design coordinates of the currently selected interpolated
2940    *   font.
2941    *
2942    * @Input:
2943    *   face ::
2944    *     A handle to the source face.
2945    *
2946    *   num_coords ::
2947    *     The number of design coordinates to retrieve.  If it
2948    *     is larger than the number of axes, set the excess
2949    *     values to~0.
2950    *
2951    * @Output:
2952    *   coords ::
2953    *     The design coordinates array.
2954    *
2955    * @Return:
2956    *   FreeType error code.  0~means success.
2957    */
2958   FT_LOCAL_DEF( FT_Error )
2959   TT_Get_Var_Design( TT_Face    face,
2960                      FT_UInt    num_coords,
2961                      FT_Fixed*  coords )
2962   {
2963     FT_Error  error = FT_Err_Ok;
2964     GX_Blend  blend;
2965     FT_UInt   i, nc;
2966 
2967 
2968     if ( !face->blend )
2969     {
2970       if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
2971         return error;
2972     }
2973 
2974     blend = face->blend;
2975 
2976     if ( !blend->coords )
2977     {


2991     }
2992 
2993     if ( face->doblend )
2994     {
2995       for ( i = 0; i < nc; i++ )
2996         coords[i] = blend->coords[i];
2997     }
2998     else
2999     {
3000       for ( i = 0; i < nc; i++ )
3001         coords[i] = 0;
3002     }
3003 
3004     for ( ; i < num_coords; i++ )
3005       coords[i] = 0;
3006 
3007     return FT_Err_Ok;
3008   }
3009 
3010 
3011   /**************************************************************************
3012    *
3013    * @Function:
3014    *   TT_Set_Named_Instance
3015    *
3016    * @Description:
3017    *   Set the given named instance, also resetting any further
3018    *   variation.
3019    *
3020    * @Input:
3021    *   face ::
3022    *     A handle to the source face.
3023    *
3024    *   instance_index ::
3025    *     The instance index, starting with value 1.
3026    *     Value 0 indicates to not use an instance.
3027    *
3028    * @Return:
3029    *   FreeType error code.  0~means success.
3030    */
3031   FT_LOCAL_DEF( FT_Error )
3032   TT_Set_Named_Instance( TT_Face  face,
3033                          FT_UInt  instance_index )
3034   {
3035     FT_Error    error = FT_ERR( Invalid_Argument );
3036     GX_Blend    blend;
3037     FT_MM_Var*  mmvar;
3038 
3039     FT_UInt  num_instances;
3040 
3041 
3042     if ( !face->blend )
3043     {
3044       if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
3045         goto Exit;
3046     }
3047 
3048     blend = face->blend;
3049     mmvar = blend->mmvar;
3050 


3086       error = TT_Set_Var_Design( face, 0, NULL );
3087 
3088     face->root.face_index  = ( instance_index << 16 )             |
3089                              ( face->root.face_index & 0xFFFFL );
3090     face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
3091 
3092   Exit:
3093     return error;
3094   }
3095 
3096 
3097   /*************************************************************************/
3098   /*************************************************************************/
3099   /*****                                                               *****/
3100   /*****                     GX VAR PARSING ROUTINES                   *****/
3101   /*****                                                               *****/
3102   /*************************************************************************/
3103   /*************************************************************************/
3104 
3105 
3106   /**************************************************************************
3107    *
3108    * @Function:
3109    *   tt_face_vary_cvt
3110    *
3111    * @Description:
3112    *   Modify the loaded cvt table according to the `cvar' table and the
3113    *   font's blend.
3114    *
3115    * @InOut:
3116    *   face ::
3117    *     A handle to the target face object.
3118    *
3119    * @Input:
3120    *   stream ::
3121    *     A handle to the input stream.
3122    *
3123    * @Return:
3124    *   FreeType error code.  0 means success.
3125    *
3126    *   Most errors are ignored.  It is perfectly valid not to have a
3127    *   `cvar' table even if there is a `gvar' and `fvar' table.
3128    */
3129   FT_LOCAL_DEF( FT_Error )
3130   tt_face_vary_cvt( TT_Face    face,
3131                     FT_Stream  stream )
3132   {
3133     FT_Error   error;
3134     FT_Memory  memory = stream->memory;
3135 
3136     FT_ULong  table_start;
3137     FT_ULong  table_len;
3138 
3139     FT_UInt   tupleCount;
3140     FT_ULong  offsetToData;
3141 
3142     FT_ULong  here;
3143     FT_UInt   i, j;
3144 
3145     FT_Fixed*  tuple_coords    = NULL;
3146     FT_Fixed*  im_start_coords = NULL;
3147     FT_Fixed*  im_end_coords   = NULL;
3148 
3149     GX_Blend  blend = face->blend;
3150 
3151     FT_UInt  point_count;
3152     FT_UInt  spoint_count = 0;
3153 
3154     FT_UShort*  sharedpoints = NULL;
3155     FT_UShort*  localpoints  = NULL;
3156     FT_UShort*  points;
3157 
3158     FT_Fixed*  deltas     = NULL;
3159     FT_Fixed*  cvt_deltas = NULL;
3160 
3161 
3162     FT_TRACE2(( "CVAR " ));
3163 
3164     if ( !blend )
3165     {
3166       FT_TRACE2(( "\n"
3167                   "tt_face_vary_cvt: no blend specified\n" ));
3168       error = FT_Err_Ok;
3169       goto Exit;
3170     }
3171 
3172     if ( !face->cvt )
3173     {
3174       FT_TRACE2(( "\n"
3175                   "tt_face_vary_cvt: no `cvt ' table\n" ));
3176       error = FT_Err_Ok;
3177       goto Exit;
3178     }
3179 


3222       goto FExit;
3223     }
3224 
3225     offsetToData += table_start;
3226 
3227     if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS )
3228     {
3229       here = FT_Stream_FTell( stream );
3230 
3231       FT_Stream_SeekSet( stream, offsetToData );
3232 
3233       sharedpoints = ft_var_readpackedpoints( stream,
3234                                               table_len,
3235                                               &spoint_count );
3236       offsetToData = FT_Stream_FTell( stream );
3237 
3238       FT_Stream_SeekSet( stream, here );
3239     }
3240 
3241     FT_TRACE5(( "cvar: there %s %d tuple%s:\n",
3242                 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "is" : "are",
3243                 tupleCount & GX_TC_TUPLE_COUNT_MASK,
3244                 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" ));
3245 
3246     if ( FT_NEW_ARRAY( cvt_deltas, face->cvt_size ) )
3247       goto FExit;
3248 
3249     for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ )
3250     {
3251       FT_UInt   tupleDataSize;
3252       FT_UInt   tupleIndex;
3253       FT_Fixed  apply;
3254 
3255 
3256       FT_TRACE6(( "  tuple %d:\n", i ));
3257 
3258       tupleDataSize = FT_GET_USHORT();
3259       tupleIndex    = FT_GET_USHORT();
3260 
3261       if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
3262       {
3263         for ( j = 0; j < blend->num_axis; j++ )
3264           tuple_coords[j] = FT_GET_SHORT() * 4;  /* convert from        */
3265                                                  /* short frac to fixed */
3266       }
3267       else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount )
3268       {
3269         FT_TRACE2(( "tt_face_vary_cvt:"
3270                     " invalid tuple index\n" ));
3271 
3272         error = FT_THROW( Invalid_Table );
3273         goto FExit;
3274       }
3275       else
3276       {
3277         if ( !blend->tuplecoords )
3278         {
3279           FT_TRACE2(( "tt_face_vary_cvt:"
3280                       " no valid tuple coordinates available\n" ));
3281 
3282           error = FT_THROW( Invalid_Table );
3283           goto FExit;
3284         }
3285 
3286         FT_MEM_COPY(
3287           tuple_coords,
3288           blend->tuplecoords +
3289             ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis,
3290           blend->num_axis * sizeof ( FT_Fixed ) );
3291       }
3292 
3293       if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
3294       {
3295         for ( j = 0; j < blend->num_axis; j++ )
3296           im_start_coords[j] = FT_GET_SHORT() * 4;
3297         for ( j = 0; j < blend->num_axis; j++ )
3298           im_end_coords[j] = FT_GET_SHORT() * 4;
3299       }
3300 
3301       apply = ft_var_apply_tuple( blend,
3302                                   (FT_UShort)tupleIndex,
3303                                   tuple_coords,
3304                                   im_start_coords,
3305                                   im_end_coords );
3306 
3307       if ( apply == 0 )              /* tuple isn't active for our blend */
3308       {
3309         offsetToData += tupleDataSize;
3310         continue;
3311       }


3332                                         point_count == 0 ? face->cvt_size
3333                                                          : point_count );
3334 
3335       if ( !points                                                        ||
3336            !deltas                                                        ||
3337            ( localpoints == ALL_POINTS && point_count != face->cvt_size ) )
3338         ; /* failure, ignore it */
3339 
3340       else if ( localpoints == ALL_POINTS )
3341       {
3342 #ifdef FT_DEBUG_LEVEL_TRACE
3343         int  count = 0;
3344 #endif
3345 
3346 
3347         FT_TRACE7(( "    CVT deltas:\n" ));
3348 
3349         /* this means that there are deltas for every entry in cvt */
3350         for ( j = 0; j < face->cvt_size; j++ )
3351         {
3352           FT_Fixed  old_cvt_delta;
3353 
3354 
3355           old_cvt_delta = cvt_deltas[j];
3356           cvt_deltas[j] = old_cvt_delta + FT_MulFix( deltas[j], apply );
3357 
3358 #ifdef FT_DEBUG_LEVEL_TRACE
3359           if ( old_cvt_delta != cvt_deltas[j] )
3360           {
3361             FT_TRACE7(( "      %d: %f -> %f\n",
3362                         j,
3363                         ( FT_intToFixed( face->cvt[j] ) +
3364                           old_cvt_delta ) / 65536.0,
3365                         ( FT_intToFixed( face->cvt[j] ) +
3366                           cvt_deltas[j] ) / 65536.0 ));
3367             count++;
3368           }
3369 #endif
3370         }
3371 
3372 #ifdef FT_DEBUG_LEVEL_TRACE
3373         if ( !count )
3374           FT_TRACE7(( "      none\n" ));
3375 #endif
3376       }
3377 
3378       else
3379       {
3380 #ifdef FT_DEBUG_LEVEL_TRACE
3381         int  count = 0;
3382 #endif
3383 
3384 
3385         FT_TRACE7(( "    CVT deltas:\n" ));
3386 
3387         for ( j = 0; j < point_count; j++ )
3388         {
3389           int       pindex;
3390           FT_Fixed  old_cvt_delta;
3391 
3392 
3393           pindex = points[j];
3394           if ( (FT_ULong)pindex >= face->cvt_size )
3395             continue;
3396 
3397           old_cvt_delta      = cvt_deltas[pindex];
3398           cvt_deltas[pindex] = old_cvt_delta + FT_MulFix( deltas[j], apply );

3399 
3400 #ifdef FT_DEBUG_LEVEL_TRACE
3401           if ( old_cvt_delta != cvt_deltas[pindex] )
3402           {
3403             FT_TRACE7(( "      %d: %f -> %f\n",
3404                         pindex,
3405                         ( FT_intToFixed( face->cvt[pindex] ) +
3406                           old_cvt_delta ) / 65536.0,
3407                         ( FT_intToFixed( face->cvt[pindex] ) +
3408                           cvt_deltas[pindex] ) / 65536.0 ));
3409             count++;
3410           }
3411 #endif
3412         }
3413 
3414 #ifdef FT_DEBUG_LEVEL_TRACE
3415         if ( !count )
3416           FT_TRACE7(( "      none\n" ));
3417 #endif
3418       }
3419 
3420       if ( localpoints != ALL_POINTS )
3421         FT_FREE( localpoints );
3422       FT_FREE( deltas );
3423 
3424       offsetToData += tupleDataSize;
3425 
3426       FT_Stream_SeekSet( stream, here );
3427     }
3428 
3429     FT_TRACE5(( "\n" ));
3430 
3431     for ( i = 0; i < face->cvt_size; i++ )
3432       face->cvt[i] += FT_fixedToInt( cvt_deltas[i] );
3433 
3434   FExit:
3435     FT_FRAME_EXIT();
3436 
3437   Exit:
3438     if ( sharedpoints != ALL_POINTS )
3439       FT_FREE( sharedpoints );
3440     FT_FREE( tuple_coords );
3441     FT_FREE( im_start_coords );
3442     FT_FREE( im_end_coords );
3443     FT_FREE( cvt_deltas );
3444 
3445     return error;
3446   }
3447 
3448 
3449   /* Shift the original coordinates of all points between indices `p1' */
3450   /* and `p2', using the same difference as given by index `ref'.      */
3451 
3452   /* modeled after `af_iup_shift' */
3453 
3454   static void
3455   tt_delta_shift( int         p1,
3456                   int         p2,
3457                   int         ref,
3458                   FT_Vector*  in_points,
3459                   FT_Vector*  out_points )
3460   {
3461     int        p;
3462     FT_Vector  delta;
3463 


3470 
3471     for ( p = p1; p < ref; p++ )
3472     {
3473       out_points[p].x += delta.x;
3474       out_points[p].y += delta.y;
3475     }
3476 
3477     for ( p = ref + 1; p <= p2; p++ )
3478     {
3479       out_points[p].x += delta.x;
3480       out_points[p].y += delta.y;
3481     }
3482   }
3483 
3484 
3485   /* Interpolate the original coordinates of all points with indices */
3486   /* between `p1' and `p2', using `ref1' and `ref2' as the reference */
3487   /* point indices.                                                  */
3488 
3489   /* modeled after `af_iup_interp', `_iup_worker_interpolate', and   */
3490   /* `Ins_IUP' with spec differences in handling ill-defined cases.  */

3491   static void
3492   tt_delta_interpolate( int         p1,
3493                         int         p2,
3494                         int         ref1,
3495                         int         ref2,
3496                         FT_Vector*  in_points,
3497                         FT_Vector*  out_points )
3498   {
3499     int  p, i;
3500 
3501     FT_Pos  out, in1, in2, out1, out2, d1, d2;
3502 
3503 
3504     if ( p1 > p2 )
3505       return;
3506 
3507     /* handle both horizontal and vertical coordinates */
3508     for ( i = 0; i <= 1; i++ )
3509     {
3510       /* shift array pointers so that we can access `foo.y' as `foo.x' */


3629                                 cur_delta,
3630                                 first_delta,
3631                                 in_points,
3632                                 out_points );
3633 
3634           if ( first_delta > 0 )
3635             tt_delta_interpolate( first_point,
3636                                   first_delta - 1,
3637                                   cur_delta,
3638                                   first_delta,
3639                                   in_points,
3640                                   out_points );
3641         }
3642       }
3643       contour++;
3644 
3645     } while ( contour < outline->n_contours );
3646   }
3647 
3648 
3649   /**************************************************************************
3650    *
3651    * @Function:
3652    *   TT_Vary_Apply_Glyph_Deltas
3653    *
3654    * @Description:
3655    *   Apply the appropriate deltas to the current glyph.
3656    *
3657    * @Input:
3658    *   face ::
3659    *     A handle to the target face object.
3660    *
3661    *   glyph_index ::
3662    *     The index of the glyph being modified.
3663    *
3664    *   n_points ::
3665    *     The number of the points in the glyph, including
3666    *     phantom points.
3667    *
3668    * @InOut:
3669    *   outline ::
3670    *     The outline to change.
3671    *
3672    * @Return:
3673    *   FreeType error code.  0 means success.
3674    */
3675   FT_LOCAL_DEF( FT_Error )
3676   TT_Vary_Apply_Glyph_Deltas( TT_Face      face,
3677                               FT_UInt      glyph_index,
3678                               FT_Outline*  outline,
3679                               FT_UInt      n_points )
3680   {
3681     FT_Error   error;
3682     FT_Stream  stream = face->root.stream;
3683     FT_Memory  memory = stream->memory;

3684 
3685     FT_Vector*  points_org = NULL;  /* coordinates in 16.16 format */
3686     FT_Vector*  points_out = NULL;  /* coordinates in 16.16 format */
3687     FT_Bool*    has_delta  = NULL;
3688 

3689     FT_ULong  glyph_start;
3690 
3691     FT_UInt   tupleCount;
3692     FT_ULong  offsetToData;
3693     FT_ULong  dataSize;
3694 
3695     FT_ULong  here;
3696     FT_UInt   i, j;
3697 
3698     FT_Fixed*  tuple_coords    = NULL;
3699     FT_Fixed*  im_start_coords = NULL;
3700     FT_Fixed*  im_end_coords   = NULL;
3701 
3702     GX_Blend  blend = face->blend;
3703 
3704     FT_UInt  point_count;
3705     FT_UInt  spoint_count = 0;
3706 
3707     FT_UShort*  sharedpoints = NULL;
3708     FT_UShort*  localpoints  = NULL;
3709     FT_UShort*  points;
3710 
3711     FT_Fixed*  deltas_x       = NULL;
3712     FT_Fixed*  deltas_y       = NULL;
3713     FT_Fixed*  point_deltas_x = NULL;
3714     FT_Fixed*  point_deltas_y = NULL;
3715 
3716 
3717     if ( !face->doblend || !blend )
3718       return FT_THROW( Invalid_Argument );
3719 
3720     if ( glyph_index >= blend->gv_glyphcnt      ||
3721          blend->glyphoffsets[glyph_index] ==
3722            blend->glyphoffsets[glyph_index + 1] )
3723     {
3724       FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
3725                   " no variation data for this glyph\n" ));
3726       return FT_Err_Ok;
3727     }
3728 
3729     if ( FT_NEW_ARRAY( points_org, n_points ) ||
3730          FT_NEW_ARRAY( points_out, n_points ) ||
3731          FT_NEW_ARRAY( has_delta, n_points )  )
3732       goto Fail1;
3733 
3734     dataSize = blend->glyphoffsets[glyph_index + 1] -
3735                  blend->glyphoffsets[glyph_index];
3736 
3737     if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] ) ||
3738          FT_FRAME_ENTER( dataSize )                         )

3739       goto Fail1;
3740 
3741     glyph_start = FT_Stream_FTell( stream );
3742 
3743     /* each set of glyph variation data is formatted similarly to `cvar' */
3744 
3745     if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis )    ||
3746          FT_NEW_ARRAY( im_start_coords, blend->num_axis ) ||
3747          FT_NEW_ARRAY( im_end_coords, blend->num_axis )   )
3748       goto Fail2;
3749 
3750     tupleCount   = FT_GET_USHORT();
3751     offsetToData = FT_GET_USHORT();
3752 
3753     /* rough sanity test */
3754     if ( offsetToData > dataSize                                ||
3755          ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) * 4 > dataSize )
3756     {
3757       FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
3758                   " invalid glyph variation array header\n" ));
3759 
3760       error = FT_THROW( Invalid_Table );
3761       goto Fail2;
3762     }
3763 
3764     offsetToData += glyph_start;
3765 
3766     if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS )
3767     {
3768       here = FT_Stream_FTell( stream );
3769 
3770       FT_Stream_SeekSet( stream, offsetToData );
3771 
3772       sharedpoints = ft_var_readpackedpoints( stream,
3773                                               blend->gvar_size,
3774                                               &spoint_count );
3775       offsetToData = FT_Stream_FTell( stream );
3776 
3777       FT_Stream_SeekSet( stream, here );
3778     }
3779 
3780     FT_TRACE5(( "gvar: there %s %d tuple%s:\n",
3781                 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "is" : "are",
3782                 tupleCount & GX_TC_TUPLE_COUNT_MASK,
3783                 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" ));
3784 
3785     if ( FT_NEW_ARRAY( point_deltas_x, n_points ) ||
3786          FT_NEW_ARRAY( point_deltas_y, n_points ) )
3787       goto Fail3;
3788 
3789     for ( j = 0; j < n_points; j++ )
3790     {
3791       points_org[j].x = FT_intToFixed( outline->points[j].x );
3792       points_org[j].y = FT_intToFixed( outline->points[j].y );
3793     }
3794 
3795     for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ )
3796     {
3797       FT_UInt   tupleDataSize;
3798       FT_UInt   tupleIndex;
3799       FT_Fixed  apply;
3800 
3801 
3802       FT_TRACE6(( "  tuple %d:\n", i ));
3803 
3804       tupleDataSize = FT_GET_USHORT();
3805       tupleIndex    = FT_GET_USHORT();
3806 
3807       if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
3808       {
3809         for ( j = 0; j < blend->num_axis; j++ )
3810           tuple_coords[j] = FT_GET_SHORT() * 4;   /* convert from        */
3811                                                   /* short frac to fixed */
3812       }
3813       else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount )
3814       {
3815         FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
3816                     " invalid tuple index\n" ));
3817 
3818         error = FT_THROW( Invalid_Table );
3819         goto Fail3;
3820       }
3821       else
3822         FT_MEM_COPY(
3823           tuple_coords,
3824           blend->tuplecoords +
3825             ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis,
3826           blend->num_axis * sizeof ( FT_Fixed ) );
3827 
3828       if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
3829       {
3830         for ( j = 0; j < blend->num_axis; j++ )
3831           im_start_coords[j] = FT_GET_SHORT() * 4;
3832         for ( j = 0; j < blend->num_axis; j++ )
3833           im_end_coords[j] = FT_GET_SHORT() * 4;
3834       }
3835 
3836       apply = ft_var_apply_tuple( blend,
3837                                   (FT_UShort)tupleIndex,
3838                                   tuple_coords,
3839                                   im_start_coords,
3840                                   im_end_coords );
3841 
3842       if ( apply == 0 )              /* tuple isn't active for our blend */
3843       {
3844         offsetToData += tupleDataSize;
3845         continue;


3869       deltas_y = ft_var_readpackeddeltas( stream,
3870                                           blend->gvar_size,
3871                                           point_count == 0 ? n_points
3872                                                            : point_count );
3873 
3874       if ( !points || !deltas_y || !deltas_x )
3875         ; /* failure, ignore it */
3876 
3877       else if ( points == ALL_POINTS )
3878       {
3879 #ifdef FT_DEBUG_LEVEL_TRACE
3880         int  count = 0;
3881 #endif
3882 
3883 
3884         FT_TRACE7(( "    point deltas:\n" ));
3885 
3886         /* this means that there are deltas for every point in the glyph */
3887         for ( j = 0; j < n_points; j++ )
3888         {
3889           FT_Fixed  old_point_delta_x = point_deltas_x[j];
3890           FT_Fixed  old_point_delta_y = point_deltas_y[j];
3891 
3892           FT_Fixed  point_delta_x = FT_MulFix( deltas_x[j], apply );
3893           FT_Fixed  point_delta_y = FT_MulFix( deltas_y[j], apply );
3894 
3895 
3896           if ( j < n_points - 4 )
3897           {
3898             point_deltas_x[j] = old_point_delta_x + point_delta_x;
3899             point_deltas_y[j] = old_point_delta_y + point_delta_y;
3900           }
3901           else
3902           {
3903             /* To avoid double adjustment of advance width or height, */
3904             /* adjust phantom points only if there is no HVAR or VVAR */
3905             /* support, respectively.                                 */
3906             if ( j == ( n_points - 4 )        &&
3907                  !( face->variation_support &
3908                     TT_FACE_FLAG_VAR_LSB    ) )
3909               point_deltas_x[j] = old_point_delta_x + point_delta_x;
3910 
3911             else if ( j == ( n_points - 3 )          &&
3912                       !( face->variation_support   &
3913                          TT_FACE_FLAG_VAR_HADVANCE ) )
3914               point_deltas_x[j] = old_point_delta_x + point_delta_x;
3915 
3916             else if ( j == ( n_points - 2 )        &&
3917                       !( face->variation_support &
3918                          TT_FACE_FLAG_VAR_TSB    ) )
3919               point_deltas_y[j] = old_point_delta_y + point_delta_y;
3920 
3921             else if ( j == ( n_points - 1 )          &&
3922                       !( face->variation_support   &
3923                          TT_FACE_FLAG_VAR_VADVANCE ) )
3924               point_deltas_y[j] = old_point_delta_y + point_delta_y;
3925           }
3926 
3927 #ifdef FT_DEBUG_LEVEL_TRACE
3928           if ( point_delta_x || point_delta_y )
3929           {
3930             FT_TRACE7(( "      %d: (%f, %f) -> (%f, %f)\n",
3931                         j,
3932                         ( FT_intToFixed( outline->points[j].x ) +
3933                           old_point_delta_x ) / 65536.0,
3934                         ( FT_intToFixed( outline->points[j].y ) +
3935                           old_point_delta_y ) / 65536.0,
3936                         ( FT_intToFixed( outline->points[j].x ) +
3937                           point_deltas_x[j] ) / 65536.0,
3938                         ( FT_intToFixed( outline->points[j].y ) +
3939                           point_deltas_y[j] ) / 65536.0 ));
3940             count++;
3941           }
3942 #endif
3943         }
3944 
3945 #ifdef FT_DEBUG_LEVEL_TRACE
3946         if ( !count )
3947           FT_TRACE7(( "      none\n" ));
3948 #endif
3949       }
3950 
3951       else
3952       {
3953 #ifdef FT_DEBUG_LEVEL_TRACE
3954         int  count = 0;
3955 #endif
3956 
3957 
3958         /* we have to interpolate the missing deltas similar to the */
3959         /* IUP bytecode instruction                                 */


3971           if ( idx >= n_points )
3972             continue;
3973 
3974           has_delta[idx] = TRUE;
3975 
3976           points_out[idx].x += FT_MulFix( deltas_x[j], apply );
3977           points_out[idx].y += FT_MulFix( deltas_y[j], apply );
3978         }
3979 
3980         /* no need to handle phantom points here,      */
3981         /* since solitary points can't be interpolated */
3982         tt_interpolate_deltas( outline,
3983                                points_out,
3984                                points_org,
3985                                has_delta );
3986 
3987         FT_TRACE7(( "    point deltas:\n" ));
3988 
3989         for ( j = 0; j < n_points; j++ )
3990         {
3991           FT_Fixed  old_point_delta_x = point_deltas_x[j];
3992           FT_Fixed  old_point_delta_y = point_deltas_y[j];
3993 
3994           FT_Pos  point_delta_x = points_out[j].x - points_org[j].x;
3995           FT_Pos  point_delta_y = points_out[j].y - points_org[j].y;
3996 
3997 
3998           if ( j < n_points - 4 )
3999           {
4000             point_deltas_x[j] = old_point_delta_x + point_delta_x;
4001             point_deltas_y[j] = old_point_delta_y + point_delta_y;
4002           }
4003           else
4004           {
4005             /* To avoid double adjustment of advance width or height, */
4006             /* adjust phantom points only if there is no HVAR or VVAR */
4007             /* support, respectively.                                 */
4008             if ( j == ( n_points - 4 )        &&
4009                  !( face->variation_support &
4010                     TT_FACE_FLAG_VAR_LSB    ) )
4011               point_deltas_x[j] = old_point_delta_x + point_delta_x;
4012 
4013             else if ( j == ( n_points - 3 )          &&
4014                       !( face->variation_support   &
4015                          TT_FACE_FLAG_VAR_HADVANCE ) )
4016               point_deltas_x[j] = old_point_delta_x + point_delta_x;
4017 
4018             else if ( j == ( n_points - 2 )        &&
4019                       !( face->variation_support &
4020                          TT_FACE_FLAG_VAR_TSB    ) )
4021               point_deltas_y[j] = old_point_delta_y + point_delta_y;
4022 
4023             else if ( j == ( n_points - 1 )          &&
4024                       !( face->variation_support   &
4025                          TT_FACE_FLAG_VAR_VADVANCE ) )
4026               point_deltas_y[j] = old_point_delta_y + point_delta_y;
4027           }
4028 
4029 #ifdef FT_DEBUG_LEVEL_TRACE
4030           if ( point_delta_x || point_delta_y )
4031           {
4032             FT_TRACE7(( "      %d: (%f, %f) -> (%f, %f)\n",
4033                         j,
4034                         ( FT_intToFixed( outline->points[j].x ) +
4035                           old_point_delta_x ) / 65536.0,
4036                         ( FT_intToFixed( outline->points[j].y ) +
4037                           old_point_delta_y ) / 65536.0,
4038                         ( FT_intToFixed( outline->points[j].x ) +
4039                           point_deltas_x[j] ) / 65536.0,
4040                         ( FT_intToFixed( outline->points[j].y ) +
4041                           point_deltas_y[j] ) / 65536.0 ));
4042             count++;
4043           }
4044 #endif
4045         }
4046 
4047 #ifdef FT_DEBUG_LEVEL_TRACE
4048         if ( !count )
4049           FT_TRACE7(( "      none\n" ));
4050 #endif
4051       }
4052 
4053       if ( localpoints != ALL_POINTS )
4054         FT_FREE( localpoints );
4055       FT_FREE( deltas_x );
4056       FT_FREE( deltas_y );
4057 
4058       offsetToData += tupleDataSize;
4059 
4060       FT_Stream_SeekSet( stream, here );
4061     }
4062 
4063     FT_TRACE5(( "\n" ));
4064 
4065     for ( i = 0; i < n_points; i++ )
4066     {
4067       outline->points[i].x += FT_fixedToInt( point_deltas_x[i] );
4068       outline->points[i].y += FT_fixedToInt( point_deltas_y[i] );
4069     }
4070 
4071   Fail3:
4072     FT_FREE( point_deltas_x );
4073     FT_FREE( point_deltas_y );
4074 
4075   Fail2:
4076     if ( sharedpoints != ALL_POINTS )
4077       FT_FREE( sharedpoints );
4078     FT_FREE( tuple_coords );
4079     FT_FREE( im_start_coords );
4080     FT_FREE( im_end_coords );
4081 
4082     FT_FRAME_EXIT();
4083 
4084   Fail1:
4085     FT_FREE( points_org );
4086     FT_FREE( points_out );
4087     FT_FREE( has_delta );
4088 
4089     return error;
4090   }
4091 
4092 
4093   /**************************************************************************
4094    *
4095    * @Function:
4096    *   tt_get_var_blend
4097    *
4098    * @Description:
4099    *   An extended internal version of `TT_Get_MM_Blend' that returns
4100    *   pointers instead of copying data, without any initialization of
4101    *   the MM machinery in case it isn't loaded yet.
4102    */
4103   FT_LOCAL_DEF( FT_Error )
4104   tt_get_var_blend( TT_Face      face,
4105                     FT_UInt     *num_coords,
4106                     FT_Fixed*   *coords,
4107                     FT_Fixed*   *normalizedcoords,
4108                     FT_MM_Var*  *mm_var )
4109   {
4110     if ( face->blend )
4111     {
4112       if ( num_coords )
4113         *num_coords       = face->blend->num_axis;
4114       if ( coords )
4115         *coords           = face->blend->coords;
4116       if ( normalizedcoords )
4117         *normalizedcoords = face->blend->normalizedcoords;
4118       if ( mm_var )
4119         *mm_var           = face->blend->mmvar;
4120     }
4121     else
4122     {


4144     {
4145       for ( i = 0; i < itemStore->dataCount; i++ )
4146       {
4147         FT_FREE( itemStore->varData[i].regionIndices );
4148         FT_FREE( itemStore->varData[i].deltaSet );
4149       }
4150 
4151       FT_FREE( itemStore->varData );
4152     }
4153 
4154     if ( itemStore->varRegionList )
4155     {
4156       for ( i = 0; i < itemStore->regionCount; i++ )
4157         FT_FREE( itemStore->varRegionList[i].axisList );
4158 
4159       FT_FREE( itemStore->varRegionList );
4160     }
4161   }
4162 
4163 
4164   /**************************************************************************
4165    *
4166    * @Function:
4167    *   tt_done_blend
4168    *
4169    * @Description:
4170    *   Free the blend internal data structure.
4171    */
4172   FT_LOCAL_DEF( void )
4173   tt_done_blend( TT_Face  face )
4174   {
4175     FT_Memory  memory = FT_FACE_MEMORY( face );
4176     GX_Blend   blend  = face->blend;
4177 
4178 
4179     if ( blend )
4180     {
4181       FT_UInt  i, num_axes;
4182 
4183 
4184       /* blend->num_axis might not be set up yet */
4185       num_axes = blend->mmvar->num_axis;
4186 
4187       FT_FREE( blend->coords );
4188       FT_FREE( blend->normalizedcoords );
4189       FT_FREE( blend->normalized_stylecoords );
4190       FT_FREE( blend->mmvar );
4191 


< prev index next >