misc/libfreetype/src/truetype/ttgxvar.c
changeset 9372 915436ff64ab
parent 9371 f3840de881bd
child 9373 b769a8e38cbd
equal deleted inserted replaced
9371:f3840de881bd 9372:915436ff64ab
     1 /***************************************************************************/
       
     2 /*                                                                         */
       
     3 /*  ttgxvar.c                                                              */
       
     4 /*                                                                         */
       
     5 /*    TrueType GX Font Variation loader                                    */
       
     6 /*                                                                         */
       
     7 /*  Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010 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   /*   http://developer.apple.com/fonts/TTRefMan/RM06/Chap6[fgca]var.html  */
       
    24   /*                                                                       */
       
    25   /* The documentation for `fvar' is inconsistent.  At one point it says   */
       
    26   /* that `countSizePairs' should be 3, at another point 2.  It should     */
       
    27   /* be 2.                                                                 */
       
    28   /*                                                                       */
       
    29   /* The documentation for `gvar' is not intelligible; `cvar' refers you   */
       
    30   /* to `gvar' and is thus also incomprehensible.                          */
       
    31   /*                                                                       */
       
    32   /* The documentation for `avar' appears correct, but Apple has no fonts  */
       
    33   /* with an `avar' table, so it is hard to test.                          */
       
    34   /*                                                                       */
       
    35   /* Many thanks to John Jenkins (at Apple) in figuring this out.          */
       
    36   /*                                                                       */
       
    37   /*                                                                       */
       
    38   /* Apple's `kern' table has some references to tuple indices, but as     */
       
    39   /* there is no indication where these indices are defined, nor how to    */
       
    40   /* interpolate the kerning values (different tuples have different       */
       
    41   /* classes) this issue is ignored.                                       */
       
    42   /*                                                                       */
       
    43   /*************************************************************************/
       
    44 
       
    45 
       
    46 #include <ft2build.h>
       
    47 #include FT_INTERNAL_DEBUG_H
       
    48 #include FT_CONFIG_CONFIG_H
       
    49 #include FT_INTERNAL_STREAM_H
       
    50 #include FT_INTERNAL_SFNT_H
       
    51 #include FT_TRUETYPE_TAGS_H
       
    52 #include FT_MULTIPLE_MASTERS_H
       
    53 
       
    54 #include "ttpload.h"
       
    55 #include "ttgxvar.h"
       
    56 
       
    57 #include "tterrors.h"
       
    58 
       
    59 
       
    60 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
       
    61 
       
    62 
       
    63 #define FT_Stream_FTell( stream )  \
       
    64           ( (stream)->cursor - (stream)->base )
       
    65 #define FT_Stream_SeekSet( stream, off ) \
       
    66               ( (stream)->cursor = (stream)->base+(off) )
       
    67 
       
    68 
       
    69   /*************************************************************************/
       
    70   /*                                                                       */
       
    71   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
       
    72   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
       
    73   /* messages during execution.                                            */
       
    74   /*                                                                       */
       
    75 #undef  FT_COMPONENT
       
    76 #define FT_COMPONENT  trace_ttgxvar
       
    77 
       
    78 
       
    79   /*************************************************************************/
       
    80   /*************************************************************************/
       
    81   /*****                                                               *****/
       
    82   /*****                       Internal Routines                       *****/
       
    83   /*****                                                               *****/
       
    84   /*************************************************************************/
       
    85   /*************************************************************************/
       
    86 
       
    87 
       
    88   /*************************************************************************/
       
    89   /*                                                                       */
       
    90   /* The macro ALL_POINTS is used in `ft_var_readpackedpoints'.  It        */
       
    91   /* indicates that there is a delta for every point without needing to    */
       
    92   /* enumerate all of them.                                                */
       
    93   /*                                                                       */
       
    94 #define ALL_POINTS  (FT_UShort*)( -1 )
       
    95 
       
    96 
       
    97 #define GX_PT_POINTS_ARE_WORDS      0x80
       
    98 #define GX_PT_POINT_RUN_COUNT_MASK  0x7F
       
    99 
       
   100 
       
   101   /*************************************************************************/
       
   102   /*                                                                       */
       
   103   /* <Function>                                                            */
       
   104   /*    ft_var_readpackedpoints                                            */
       
   105   /*                                                                       */
       
   106   /* <Description>                                                         */
       
   107   /*    Read a set of points to which the following deltas will apply.     */
       
   108   /*    Points are packed with a run length encoding.                      */
       
   109   /*                                                                       */
       
   110   /* <Input>                                                               */
       
   111   /*    stream    :: The data stream.                                      */
       
   112   /*                                                                       */
       
   113   /* <Output>                                                              */
       
   114   /*    point_cnt :: The number of points read.  A zero value means that   */
       
   115   /*                 all points in the glyph will be affected, without     */
       
   116   /*                 enumerating them individually.                        */
       
   117   /*                                                                       */
       
   118   /* <Return>                                                              */
       
   119   /*    An array of FT_UShort containing the affected points or the        */
       
   120   /*    special value ALL_POINTS.                                          */
       
   121   /*                                                                       */
       
   122   static FT_UShort*
       
   123   ft_var_readpackedpoints( FT_Stream  stream,
       
   124                            FT_UInt   *point_cnt )
       
   125   {
       
   126     FT_UShort *points;
       
   127     FT_Int     n;
       
   128     FT_Int     runcnt;
       
   129     FT_Int     i;
       
   130     FT_Int     j;
       
   131     FT_Int     first;
       
   132     FT_Memory  memory = stream->memory;
       
   133     FT_Error   error  = TT_Err_Ok;
       
   134 
       
   135     FT_UNUSED( error );
       
   136 
       
   137 
       
   138     *point_cnt = n = FT_GET_BYTE();
       
   139     if ( n == 0 )
       
   140       return ALL_POINTS;
       
   141 
       
   142     if ( n & GX_PT_POINTS_ARE_WORDS )
       
   143       n = FT_GET_BYTE() | ( ( n & GX_PT_POINT_RUN_COUNT_MASK ) << 8 );
       
   144 
       
   145     if ( FT_NEW_ARRAY( points, n ) )
       
   146       return NULL;
       
   147 
       
   148     i = 0;
       
   149     while ( i < n )
       
   150     {
       
   151       runcnt = FT_GET_BYTE();
       
   152       if ( runcnt & GX_PT_POINTS_ARE_WORDS )
       
   153       {
       
   154         runcnt = runcnt & GX_PT_POINT_RUN_COUNT_MASK;
       
   155         first  = points[i++] = FT_GET_USHORT();
       
   156 
       
   157         if ( runcnt < 1 || i + runcnt >= n )
       
   158           goto Exit;
       
   159 
       
   160         /* first point not included in runcount */
       
   161         for ( j = 0; j < runcnt; ++j )
       
   162           points[i++] = (FT_UShort)( first += FT_GET_USHORT() );
       
   163       }
       
   164       else
       
   165       {
       
   166         first = points[i++] = FT_GET_BYTE();
       
   167 
       
   168         if ( runcnt < 1 || i + runcnt >= n )
       
   169           goto Exit;
       
   170 
       
   171         for ( j = 0; j < runcnt; ++j )
       
   172           points[i++] = (FT_UShort)( first += FT_GET_BYTE() );
       
   173       }
       
   174     }
       
   175 
       
   176   Exit:
       
   177     return points;
       
   178   }
       
   179 
       
   180 
       
   181   enum
       
   182   {
       
   183     GX_DT_DELTAS_ARE_ZERO      = 0x80,
       
   184     GX_DT_DELTAS_ARE_WORDS     = 0x40,
       
   185     GX_DT_DELTA_RUN_COUNT_MASK = 0x3F
       
   186   };
       
   187 
       
   188 
       
   189   /*************************************************************************/
       
   190   /*                                                                       */
       
   191   /* <Function>                                                            */
       
   192   /*    ft_var_readpackeddeltas                                            */
       
   193   /*                                                                       */
       
   194   /* <Description>                                                         */
       
   195   /*    Read a set of deltas.  These are packed slightly differently than  */
       
   196   /*    points.  In particular there is no overall count.                  */
       
   197   /*                                                                       */
       
   198   /* <Input>                                                               */
       
   199   /*    stream    :: The data stream.                                      */
       
   200   /*                                                                       */
       
   201   /*    delta_cnt :: The number of to be read.                             */
       
   202   /*                                                                       */
       
   203   /* <Return>                                                              */
       
   204   /*    An array of FT_Short containing the deltas for the affected        */
       
   205   /*    points.  (This only gets the deltas for one dimension.  It will    */
       
   206   /*    generally be called twice, once for x, once for y.  When used in   */
       
   207   /*    cvt table, it will only be called once.)                           */
       
   208   /*                                                                       */
       
   209   static FT_Short*
       
   210   ft_var_readpackeddeltas( FT_Stream  stream,
       
   211                            FT_Offset  delta_cnt )
       
   212   {
       
   213     FT_Short  *deltas = NULL;
       
   214     FT_UInt    runcnt;
       
   215     FT_Offset  i;
       
   216     FT_UInt    j;
       
   217     FT_Memory  memory = stream->memory;
       
   218     FT_Error   error  = TT_Err_Ok;
       
   219 
       
   220     FT_UNUSED( error );
       
   221 
       
   222 
       
   223     if ( FT_NEW_ARRAY( deltas, delta_cnt ) )
       
   224       return NULL;
       
   225 
       
   226     i = 0;
       
   227     while ( i < delta_cnt )
       
   228     {
       
   229       runcnt = FT_GET_BYTE();
       
   230       if ( runcnt & GX_DT_DELTAS_ARE_ZERO )
       
   231       {
       
   232         /* runcnt zeroes get added */
       
   233         for ( j = 0;
       
   234               j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt;
       
   235               ++j )
       
   236           deltas[i++] = 0;
       
   237       }
       
   238       else if ( runcnt & GX_DT_DELTAS_ARE_WORDS )
       
   239       {
       
   240         /* runcnt shorts from the stack */
       
   241         for ( j = 0;
       
   242               j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt;
       
   243               ++j )
       
   244           deltas[i++] = FT_GET_SHORT();
       
   245       }
       
   246       else
       
   247       {
       
   248         /* runcnt signed bytes from the stack */
       
   249         for ( j = 0;
       
   250               j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt;
       
   251               ++j )
       
   252           deltas[i++] = FT_GET_CHAR();
       
   253       }
       
   254 
       
   255       if ( j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) )
       
   256       {
       
   257         /* Bad format */
       
   258         FT_FREE( deltas );
       
   259         return NULL;
       
   260       }
       
   261     }
       
   262 
       
   263     return deltas;
       
   264   }
       
   265 
       
   266 
       
   267   /*************************************************************************/
       
   268   /*                                                                       */
       
   269   /* <Function>                                                            */
       
   270   /*    ft_var_load_avar                                                   */
       
   271   /*                                                                       */
       
   272   /* <Description>                                                         */
       
   273   /*    Parse the `avar' table if present.  It need not be, so we return   */
       
   274   /*    nothing.                                                           */
       
   275   /*                                                                       */
       
   276   /* <InOut>                                                               */
       
   277   /*    face :: The font face.                                             */
       
   278   /*                                                                       */
       
   279   static void
       
   280   ft_var_load_avar( TT_Face  face )
       
   281   {
       
   282     FT_Stream       stream = FT_FACE_STREAM(face);
       
   283     FT_Memory       memory = stream->memory;
       
   284     GX_Blend        blend  = face->blend;
       
   285     GX_AVarSegment  segment;
       
   286     FT_Error        error = TT_Err_Ok;
       
   287     FT_ULong        version;
       
   288     FT_Long         axisCount;
       
   289     FT_Int          i, j;
       
   290     FT_ULong        table_len;
       
   291 
       
   292     FT_UNUSED( error );
       
   293 
       
   294 
       
   295     blend->avar_checked = TRUE;
       
   296     if ( (error = face->goto_table( face, TTAG_avar, stream, &table_len )) != 0 )
       
   297       return;
       
   298 
       
   299     if ( FT_FRAME_ENTER( table_len ) )
       
   300       return;
       
   301 
       
   302     version   = FT_GET_LONG();
       
   303     axisCount = FT_GET_LONG();
       
   304 
       
   305     if ( version != 0x00010000L                       ||
       
   306          axisCount != (FT_Long)blend->mmvar->num_axis )
       
   307       goto Exit;
       
   308 
       
   309     if ( FT_NEW_ARRAY( blend->avar_segment, axisCount ) )
       
   310       goto Exit;
       
   311 
       
   312     segment = &blend->avar_segment[0];
       
   313     for ( i = 0; i < axisCount; ++i, ++segment )
       
   314     {
       
   315       segment->pairCount = FT_GET_USHORT();
       
   316       if ( FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) )
       
   317       {
       
   318         /* Failure.  Free everything we have done so far.  We must do */
       
   319         /* it right now since loading the `avar' table is optional.   */
       
   320 
       
   321         for ( j = i - 1; j >= 0; --j )
       
   322           FT_FREE( blend->avar_segment[j].correspondence );
       
   323 
       
   324         FT_FREE( blend->avar_segment );
       
   325         blend->avar_segment = NULL;
       
   326         goto Exit;
       
   327       }
       
   328 
       
   329       for ( j = 0; j < segment->pairCount; ++j )
       
   330       {
       
   331         segment->correspondence[j].fromCoord =
       
   332           FT_GET_SHORT() << 2;    /* convert to Fixed */
       
   333         segment->correspondence[j].toCoord =
       
   334           FT_GET_SHORT()<<2;    /* convert to Fixed */
       
   335       }
       
   336     }
       
   337 
       
   338   Exit:
       
   339     FT_FRAME_EXIT();
       
   340   }
       
   341 
       
   342 
       
   343   typedef struct  GX_GVar_Head_
       
   344   {
       
   345     FT_Long    version;
       
   346     FT_UShort  axisCount;
       
   347     FT_UShort  globalCoordCount;
       
   348     FT_ULong   offsetToCoord;
       
   349     FT_UShort  glyphCount;
       
   350     FT_UShort  flags;
       
   351     FT_ULong   offsetToData;
       
   352 
       
   353   } GX_GVar_Head;
       
   354 
       
   355 
       
   356   /*************************************************************************/
       
   357   /*                                                                       */
       
   358   /* <Function>                                                            */
       
   359   /*    ft_var_load_gvar                                                   */
       
   360   /*                                                                       */
       
   361   /* <Description>                                                         */
       
   362   /*    Parses the `gvar' table if present.  If `fvar' is there, `gvar'    */
       
   363   /*    had better be there too.                                           */
       
   364   /*                                                                       */
       
   365   /* <InOut>                                                               */
       
   366   /*    face :: The font face.                                             */
       
   367   /*                                                                       */
       
   368   /* <Return>                                                              */
       
   369   /*    FreeType error code.  0 means success.                             */
       
   370   /*                                                                       */
       
   371   static FT_Error
       
   372   ft_var_load_gvar( TT_Face  face )
       
   373   {
       
   374     FT_Stream     stream = FT_FACE_STREAM(face);
       
   375     FT_Memory     memory = stream->memory;
       
   376     GX_Blend      blend  = face->blend;
       
   377     FT_Error      error;
       
   378     FT_UInt       i, j;
       
   379     FT_ULong      table_len;
       
   380     FT_ULong      gvar_start;
       
   381     FT_ULong      offsetToData;
       
   382     GX_GVar_Head  gvar_head;
       
   383 
       
   384     static const FT_Frame_Field  gvar_fields[] =
       
   385     {
       
   386 
       
   387 #undef  FT_STRUCTURE
       
   388 #define FT_STRUCTURE  GX_GVar_Head
       
   389 
       
   390       FT_FRAME_START( 20 ),
       
   391         FT_FRAME_LONG  ( version ),
       
   392         FT_FRAME_USHORT( axisCount ),
       
   393         FT_FRAME_USHORT( globalCoordCount ),
       
   394         FT_FRAME_ULONG ( offsetToCoord ),
       
   395         FT_FRAME_USHORT( glyphCount ),
       
   396         FT_FRAME_USHORT( flags ),
       
   397         FT_FRAME_ULONG ( offsetToData ),
       
   398       FT_FRAME_END
       
   399     };
       
   400 
       
   401     if ( (error = face->goto_table( face, TTAG_gvar, stream, &table_len )) != 0 )
       
   402       goto Exit;
       
   403 
       
   404     gvar_start = FT_STREAM_POS( );
       
   405     if ( FT_STREAM_READ_FIELDS( gvar_fields, &gvar_head ) )
       
   406       goto Exit;
       
   407 
       
   408     blend->tuplecount  = gvar_head.globalCoordCount;
       
   409     blend->gv_glyphcnt = gvar_head.glyphCount;
       
   410     offsetToData       = gvar_start + gvar_head.offsetToData;
       
   411 
       
   412     if ( gvar_head.version   != (FT_Long)0x00010000L              ||
       
   413          gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis )
       
   414     {
       
   415       error = TT_Err_Invalid_Table;
       
   416       goto Exit;
       
   417     }
       
   418 
       
   419     if ( FT_NEW_ARRAY( blend->glyphoffsets, blend->gv_glyphcnt + 1 ) )
       
   420       goto Exit;
       
   421 
       
   422     if ( gvar_head.flags & 1 )
       
   423     {
       
   424       /* long offsets (one more offset than glyphs, to mark size of last) */
       
   425       if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 4L ) )
       
   426         goto Exit;
       
   427 
       
   428       for ( i = 0; i <= blend->gv_glyphcnt; ++i )
       
   429         blend->glyphoffsets[i] = offsetToData + FT_GET_LONG();
       
   430 
       
   431       FT_FRAME_EXIT();
       
   432     }
       
   433     else
       
   434     {
       
   435       /* short offsets (one more offset than glyphs, to mark size of last) */
       
   436       if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 2L ) )
       
   437         goto Exit;
       
   438 
       
   439       for ( i = 0; i <= blend->gv_glyphcnt; ++i )
       
   440         blend->glyphoffsets[i] = offsetToData + FT_GET_USHORT() * 2;
       
   441                                               /* XXX: Undocumented: `*2'! */
       
   442 
       
   443       FT_FRAME_EXIT();
       
   444     }
       
   445 
       
   446     if ( blend->tuplecount != 0 )
       
   447     {
       
   448       if ( FT_NEW_ARRAY( blend->tuplecoords,
       
   449                          gvar_head.axisCount * blend->tuplecount ) )
       
   450         goto Exit;
       
   451 
       
   452       if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord )       ||
       
   453            FT_FRAME_ENTER( blend->tuplecount * gvar_head.axisCount * 2L )                   )
       
   454         goto Exit;
       
   455 
       
   456       for ( i = 0; i < blend->tuplecount; ++i )
       
   457         for ( j = 0 ; j < (FT_UInt)gvar_head.axisCount; ++j )
       
   458           blend->tuplecoords[i * gvar_head.axisCount + j] =
       
   459             FT_GET_SHORT() << 2;                /* convert to FT_Fixed */
       
   460 
       
   461       FT_FRAME_EXIT();
       
   462     }
       
   463 
       
   464   Exit:
       
   465     return error;
       
   466   }
       
   467 
       
   468 
       
   469   /*************************************************************************/
       
   470   /*                                                                       */
       
   471   /* <Function>                                                            */
       
   472   /*    ft_var_apply_tuple                                                 */
       
   473   /*                                                                       */
       
   474   /* <Description>                                                         */
       
   475   /*    Figure out whether a given tuple (design) applies to the current   */
       
   476   /*    blend, and if so, what is the scaling factor.                      */
       
   477   /*                                                                       */
       
   478   /* <Input>                                                               */
       
   479   /*    blend           :: The current blend of the font.                  */
       
   480   /*                                                                       */
       
   481   /*    tupleIndex      :: A flag saying whether this is an intermediate   */
       
   482   /*                       tuple or not.                                   */
       
   483   /*                                                                       */
       
   484   /*    tuple_coords    :: The coordinates of the tuple in normalized axis */
       
   485   /*                       units.                                          */
       
   486   /*                                                                       */
       
   487   /*    im_start_coords :: The initial coordinates where this tuple starts */
       
   488   /*                       to apply (for intermediate coordinates).        */
       
   489   /*                                                                       */
       
   490   /*    im_end_coords   :: The final coordinates after which this tuple no */
       
   491   /*                       longer applies (for intermediate coordinates).  */
       
   492   /*                                                                       */
       
   493   /* <Return>                                                              */
       
   494   /*    An FT_Fixed value containing the scaling factor.                   */
       
   495   /*                                                                       */
       
   496   static FT_Fixed
       
   497   ft_var_apply_tuple( GX_Blend   blend,
       
   498                       FT_UShort  tupleIndex,
       
   499                       FT_Fixed*  tuple_coords,
       
   500                       FT_Fixed*  im_start_coords,
       
   501                       FT_Fixed*  im_end_coords )
       
   502   {
       
   503     FT_UInt   i;
       
   504     FT_Fixed  apply;
       
   505     FT_Fixed  temp;
       
   506 
       
   507 
       
   508     apply = 0x10000L;
       
   509     for ( i = 0; i < blend->num_axis; ++i )
       
   510     {
       
   511       if ( tuple_coords[i] == 0 )
       
   512         /* It's not clear why (for intermediate tuples) we don't need     */
       
   513         /* to check against start/end -- the documentation says we don't. */
       
   514         /* Similarly, it's unclear why we don't need to scale along the   */
       
   515         /* axis.                                                          */
       
   516         continue;
       
   517 
       
   518       else if ( blend->normalizedcoords[i] == 0                           ||
       
   519                 ( blend->normalizedcoords[i] < 0 && tuple_coords[i] > 0 ) ||
       
   520                 ( blend->normalizedcoords[i] > 0 && tuple_coords[i] < 0 ) )
       
   521       {
       
   522         apply = 0;
       
   523         break;
       
   524       }
       
   525 
       
   526       else if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) )
       
   527         /* not an intermediate tuple */
       
   528         apply = FT_MulDiv( apply,
       
   529                            blend->normalizedcoords[i] > 0
       
   530                              ? blend->normalizedcoords[i]
       
   531                              : -blend->normalizedcoords[i],
       
   532                            0x10000L );
       
   533 
       
   534       else if ( blend->normalizedcoords[i] <= im_start_coords[i] ||
       
   535                 blend->normalizedcoords[i] >= im_end_coords[i]   )
       
   536       {
       
   537         apply = 0;
       
   538         break;
       
   539       }
       
   540 
       
   541       else if ( blend->normalizedcoords[i] < tuple_coords[i] )
       
   542       {
       
   543         temp = FT_MulDiv( blend->normalizedcoords[i] - im_start_coords[i],
       
   544                           0x10000L,
       
   545                           tuple_coords[i] - im_start_coords[i]);
       
   546         apply = FT_MulDiv( apply, temp, 0x10000L );
       
   547       }
       
   548 
       
   549       else
       
   550       {
       
   551         temp = FT_MulDiv( im_end_coords[i] - blend->normalizedcoords[i],
       
   552                           0x10000L,
       
   553                           im_end_coords[i] - tuple_coords[i] );
       
   554         apply = FT_MulDiv( apply, temp, 0x10000L );
       
   555       }
       
   556     }
       
   557 
       
   558     return apply;
       
   559   }
       
   560 
       
   561 
       
   562   /*************************************************************************/
       
   563   /*************************************************************************/
       
   564   /*****                                                               *****/
       
   565   /*****               MULTIPLE MASTERS SERVICE FUNCTIONS              *****/
       
   566   /*****                                                               *****/
       
   567   /*************************************************************************/
       
   568   /*************************************************************************/
       
   569 
       
   570 
       
   571   typedef struct  GX_FVar_Head_
       
   572   {
       
   573     FT_Long    version;
       
   574     FT_UShort  offsetToData;
       
   575     FT_UShort  countSizePairs;
       
   576     FT_UShort  axisCount;
       
   577     FT_UShort  axisSize;
       
   578     FT_UShort  instanceCount;
       
   579     FT_UShort  instanceSize;
       
   580 
       
   581   } GX_FVar_Head;
       
   582 
       
   583 
       
   584   typedef struct  fvar_axis_
       
   585   {
       
   586     FT_ULong   axisTag;
       
   587     FT_ULong   minValue;
       
   588     FT_ULong   defaultValue;
       
   589     FT_ULong   maxValue;
       
   590     FT_UShort  flags;
       
   591     FT_UShort  nameID;
       
   592 
       
   593   } GX_FVar_Axis;
       
   594 
       
   595 
       
   596   /*************************************************************************/
       
   597   /*                                                                       */
       
   598   /* <Function>                                                            */
       
   599   /*    TT_Get_MM_Var                                                      */
       
   600   /*                                                                       */
       
   601   /* <Description>                                                         */
       
   602   /*    Check that the font's `fvar' table is valid, parse it, and return  */
       
   603   /*    those data.                                                        */
       
   604   /*                                                                       */
       
   605   /* <InOut>                                                               */
       
   606   /*    face   :: The font face.                                           */
       
   607   /*              TT_Get_MM_Var initializes the blend structure.           */
       
   608   /*                                                                       */
       
   609   /* <Output>                                                              */
       
   610   /*    master :: The `fvar' data (must be freed by caller).               */
       
   611   /*                                                                       */
       
   612   /* <Return>                                                              */
       
   613   /*    FreeType error code.  0 means success.                             */
       
   614   /*                                                                       */
       
   615   FT_LOCAL_DEF( FT_Error )
       
   616   TT_Get_MM_Var( TT_Face      face,
       
   617                  FT_MM_Var*  *master )
       
   618   {
       
   619     FT_Stream            stream = face->root.stream;
       
   620     FT_Memory            memory = face->root.memory;
       
   621     FT_ULong             table_len;
       
   622     FT_Error             error  = TT_Err_Ok;
       
   623     FT_ULong             fvar_start;
       
   624     FT_Int               i, j;
       
   625     FT_MM_Var*           mmvar;
       
   626     FT_Fixed*            next_coords;
       
   627     FT_String*           next_name;
       
   628     FT_Var_Axis*         a;
       
   629     FT_Var_Named_Style*  ns;
       
   630     GX_FVar_Head         fvar_head;
       
   631 
       
   632     static const FT_Frame_Field  fvar_fields[] =
       
   633     {
       
   634 
       
   635 #undef  FT_STRUCTURE
       
   636 #define FT_STRUCTURE  GX_FVar_Head
       
   637 
       
   638       FT_FRAME_START( 16 ),
       
   639         FT_FRAME_LONG  ( version ),
       
   640         FT_FRAME_USHORT( offsetToData ),
       
   641         FT_FRAME_USHORT( countSizePairs ),
       
   642         FT_FRAME_USHORT( axisCount ),
       
   643         FT_FRAME_USHORT( axisSize ),
       
   644         FT_FRAME_USHORT( instanceCount ),
       
   645         FT_FRAME_USHORT( instanceSize ),
       
   646       FT_FRAME_END
       
   647     };
       
   648 
       
   649     static const FT_Frame_Field  fvaraxis_fields[] =
       
   650     {
       
   651 
       
   652 #undef  FT_STRUCTURE
       
   653 #define FT_STRUCTURE  GX_FVar_Axis
       
   654 
       
   655       FT_FRAME_START( 20 ),
       
   656         FT_FRAME_ULONG ( axisTag ),
       
   657         FT_FRAME_ULONG ( minValue ),
       
   658         FT_FRAME_ULONG ( defaultValue ),
       
   659         FT_FRAME_ULONG ( maxValue ),
       
   660         FT_FRAME_USHORT( flags ),
       
   661         FT_FRAME_USHORT( nameID ),
       
   662       FT_FRAME_END
       
   663     };
       
   664 
       
   665 
       
   666     if ( face->blend == NULL )
       
   667     {
       
   668       /* both `fvar' and `gvar' must be present */
       
   669       if ( (error = face->goto_table( face, TTAG_gvar,
       
   670                                       stream, &table_len )) != 0 )
       
   671         goto Exit;
       
   672 
       
   673       if ( (error = face->goto_table( face, TTAG_fvar,
       
   674                                       stream, &table_len )) != 0 )
       
   675         goto Exit;
       
   676 
       
   677       fvar_start = FT_STREAM_POS( );
       
   678 
       
   679       if ( FT_STREAM_READ_FIELDS( fvar_fields, &fvar_head ) )
       
   680         goto Exit;
       
   681 
       
   682       if ( fvar_head.version != (FT_Long)0x00010000L                      ||
       
   683            fvar_head.countSizePairs != 2                                  ||
       
   684            fvar_head.axisSize != 20                                       ||
       
   685            /* axisCount limit implied by 16-bit instanceSize */
       
   686            fvar_head.axisCount > 0x3FFE                                   ||
       
   687            fvar_head.instanceSize != 4 + 4 * fvar_head.axisCount          ||
       
   688            /* instanceCount limit implied by limited range of name IDs */
       
   689            fvar_head.instanceCount > 0x7EFF                               ||
       
   690            fvar_head.offsetToData + fvar_head.axisCount * 20U +
       
   691              fvar_head.instanceCount * fvar_head.instanceSize > table_len )
       
   692       {
       
   693         error = TT_Err_Invalid_Table;
       
   694         goto Exit;
       
   695       }
       
   696 
       
   697       if ( FT_NEW( face->blend ) )
       
   698         goto Exit;
       
   699 
       
   700       /* cannot overflow 32-bit arithmetic because of limits above */
       
   701       face->blend->mmvar_len =
       
   702         sizeof ( FT_MM_Var ) +
       
   703         fvar_head.axisCount * sizeof ( FT_Var_Axis ) +
       
   704         fvar_head.instanceCount * sizeof ( FT_Var_Named_Style ) +
       
   705         fvar_head.instanceCount * fvar_head.axisCount * sizeof ( FT_Fixed ) +
       
   706         5 * fvar_head.axisCount;
       
   707 
       
   708       if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
       
   709         goto Exit;
       
   710       face->blend->mmvar = mmvar;
       
   711 
       
   712       mmvar->num_axis =
       
   713         fvar_head.axisCount;
       
   714       mmvar->num_designs =
       
   715         (FT_UInt)-1;           /* meaningless in this context; each glyph */
       
   716                                /* may have a different number of designs  */
       
   717                                /* (or tuples, as called by Apple)         */
       
   718       mmvar->num_namedstyles =
       
   719         fvar_head.instanceCount;
       
   720       mmvar->axis =
       
   721         (FT_Var_Axis*)&(mmvar[1]);
       
   722       mmvar->namedstyle =
       
   723         (FT_Var_Named_Style*)&(mmvar->axis[fvar_head.axisCount]);
       
   724 
       
   725       next_coords =
       
   726         (FT_Fixed*)&(mmvar->namedstyle[fvar_head.instanceCount]);
       
   727       for ( i = 0; i < fvar_head.instanceCount; ++i )
       
   728       {
       
   729         mmvar->namedstyle[i].coords  = next_coords;
       
   730         next_coords                 += fvar_head.axisCount;
       
   731       }
       
   732 
       
   733       next_name = (FT_String*)next_coords;
       
   734       for ( i = 0; i < fvar_head.axisCount; ++i )
       
   735       {
       
   736         mmvar->axis[i].name  = next_name;
       
   737         next_name           += 5;
       
   738       }
       
   739 
       
   740       if ( FT_STREAM_SEEK( fvar_start + fvar_head.offsetToData ) )
       
   741         goto Exit;
       
   742 
       
   743       a = mmvar->axis;
       
   744       for ( i = 0; i < fvar_head.axisCount; ++i )
       
   745       {
       
   746         GX_FVar_Axis  axis_rec;
       
   747 
       
   748 
       
   749         if ( FT_STREAM_READ_FIELDS( fvaraxis_fields, &axis_rec ) )
       
   750           goto Exit;
       
   751         a->tag     = axis_rec.axisTag;
       
   752         a->minimum = axis_rec.minValue;     /* A Fixed */
       
   753         a->def     = axis_rec.defaultValue; /* A Fixed */
       
   754         a->maximum = axis_rec.maxValue;     /* A Fixed */
       
   755         a->strid   = axis_rec.nameID;
       
   756 
       
   757         a->name[0] = (FT_String)(   a->tag >> 24 );
       
   758         a->name[1] = (FT_String)( ( a->tag >> 16 ) & 0xFF );
       
   759         a->name[2] = (FT_String)( ( a->tag >>  8 ) & 0xFF );
       
   760         a->name[3] = (FT_String)( ( a->tag       ) & 0xFF );
       
   761         a->name[4] = 0;
       
   762 
       
   763         ++a;
       
   764       }
       
   765 
       
   766       ns = mmvar->namedstyle;
       
   767       for ( i = 0; i < fvar_head.instanceCount; ++i, ++ns )
       
   768       {
       
   769         if ( FT_FRAME_ENTER( 4L + 4L * fvar_head.axisCount ) )
       
   770           goto Exit;
       
   771 
       
   772         ns->strid       =    FT_GET_USHORT();
       
   773         (void) /* flags = */ FT_GET_USHORT();
       
   774 
       
   775         for ( j = 0; j < fvar_head.axisCount; ++j )
       
   776           ns->coords[j] = FT_GET_ULONG();     /* A Fixed */
       
   777 
       
   778         FT_FRAME_EXIT();
       
   779       }
       
   780     }
       
   781 
       
   782     if ( master != NULL )
       
   783     {
       
   784       FT_UInt  n;
       
   785 
       
   786 
       
   787       if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
       
   788         goto Exit;
       
   789       FT_MEM_COPY( mmvar, face->blend->mmvar, face->blend->mmvar_len );
       
   790 
       
   791       mmvar->axis =
       
   792         (FT_Var_Axis*)&(mmvar[1]);
       
   793       mmvar->namedstyle =
       
   794         (FT_Var_Named_Style*)&(mmvar->axis[mmvar->num_axis]);
       
   795       next_coords =
       
   796         (FT_Fixed*)&(mmvar->namedstyle[mmvar->num_namedstyles]);
       
   797 
       
   798       for ( n = 0; n < mmvar->num_namedstyles; ++n )
       
   799       {
       
   800         mmvar->namedstyle[n].coords  = next_coords;
       
   801         next_coords                 += mmvar->num_axis;
       
   802       }
       
   803 
       
   804       a = mmvar->axis;
       
   805       next_name = (FT_String*)next_coords;
       
   806       for ( n = 0; n < mmvar->num_axis; ++n )
       
   807       {
       
   808         a->name = next_name;
       
   809 
       
   810         /* standard PostScript names for some standard apple tags */
       
   811         if ( a->tag == TTAG_wght )
       
   812           a->name = (char *)"Weight";
       
   813         else if ( a->tag == TTAG_wdth )
       
   814           a->name = (char *)"Width";
       
   815         else if ( a->tag == TTAG_opsz )
       
   816           a->name = (char *)"OpticalSize";
       
   817         else if ( a->tag == TTAG_slnt )
       
   818           a->name = (char *)"Slant";
       
   819 
       
   820         next_name += 5;
       
   821         ++a;
       
   822       }
       
   823 
       
   824       *master = mmvar;
       
   825     }
       
   826 
       
   827   Exit:
       
   828     return error;
       
   829   }
       
   830 
       
   831 
       
   832   /*************************************************************************/
       
   833   /*                                                                       */
       
   834   /* <Function>                                                            */
       
   835   /*    TT_Set_MM_Blend                                                    */
       
   836   /*                                                                       */
       
   837   /* <Description>                                                         */
       
   838   /*    Set the blend (normalized) coordinates for this instance of the    */
       
   839   /*    font.  Check that the `gvar' table is reasonable and does some     */
       
   840   /*    initial preparation.                                               */
       
   841   /*                                                                       */
       
   842   /* <InOut>                                                               */
       
   843   /*    face       :: The font.                                            */
       
   844   /*                  Initialize the blend structure with `gvar' data.     */
       
   845   /*                                                                       */
       
   846   /* <Input>                                                               */
       
   847   /*    num_coords :: Must be the axis count of the font.                  */
       
   848   /*                                                                       */
       
   849   /*    coords     :: An array of num_coords, each between [-1,1].         */
       
   850   /*                                                                       */
       
   851   /* <Return>                                                              */
       
   852   /*    FreeType error code.  0 means success.                             */
       
   853   /*                                                                       */
       
   854   FT_LOCAL_DEF( FT_Error )
       
   855   TT_Set_MM_Blend( TT_Face    face,
       
   856                    FT_UInt    num_coords,
       
   857                    FT_Fixed*  coords )
       
   858   {
       
   859     FT_Error    error = TT_Err_Ok;
       
   860     GX_Blend    blend;
       
   861     FT_MM_Var*  mmvar;
       
   862     FT_UInt     i;
       
   863     FT_Memory   memory = face->root.memory;
       
   864 
       
   865     enum
       
   866     {
       
   867       mcvt_retain,
       
   868       mcvt_modify,
       
   869       mcvt_load
       
   870 
       
   871     } manageCvt;
       
   872 
       
   873 
       
   874     face->doblend = FALSE;
       
   875 
       
   876     if ( face->blend == NULL )
       
   877     {
       
   878       if ( (error = TT_Get_MM_Var( face, NULL)) != 0 )
       
   879         goto Exit;
       
   880     }
       
   881 
       
   882     blend = face->blend;
       
   883     mmvar = blend->mmvar;
       
   884 
       
   885     if ( num_coords != mmvar->num_axis )
       
   886     {
       
   887       error = TT_Err_Invalid_Argument;
       
   888       goto Exit;
       
   889     }
       
   890 
       
   891     for ( i = 0; i < num_coords; ++i )
       
   892       if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L )
       
   893       {
       
   894         error = TT_Err_Invalid_Argument;
       
   895         goto Exit;
       
   896       }
       
   897 
       
   898     if ( blend->glyphoffsets == NULL )
       
   899       if ( (error = ft_var_load_gvar( face )) != 0 )
       
   900         goto Exit;
       
   901 
       
   902     if ( blend->normalizedcoords == NULL )
       
   903     {
       
   904       if ( FT_NEW_ARRAY( blend->normalizedcoords, num_coords ) )
       
   905         goto Exit;
       
   906 
       
   907       manageCvt = mcvt_modify;
       
   908 
       
   909       /* If we have not set the blend coordinates before this, then the  */
       
   910       /* cvt table will still be what we read from the `cvt ' table and  */
       
   911       /* we don't need to reload it.  We may need to change it though... */
       
   912     }
       
   913     else
       
   914     {
       
   915       manageCvt = mcvt_retain;
       
   916       for ( i = 0; i < num_coords; ++i )
       
   917       {
       
   918         if ( blend->normalizedcoords[i] != coords[i] )
       
   919         {
       
   920           manageCvt = mcvt_load;
       
   921           break;
       
   922         }
       
   923       }
       
   924 
       
   925       /* If we don't change the blend coords then we don't need to do  */
       
   926       /* anything to the cvt table.  It will be correct.  Otherwise we */
       
   927       /* no longer have the original cvt (it was modified when we set  */
       
   928       /* the blend last time), so we must reload and then modify it.   */
       
   929     }
       
   930 
       
   931     blend->num_axis = num_coords;
       
   932     FT_MEM_COPY( blend->normalizedcoords,
       
   933                  coords,
       
   934                  num_coords * sizeof ( FT_Fixed ) );
       
   935 
       
   936     face->doblend = TRUE;
       
   937 
       
   938     if ( face->cvt != NULL )
       
   939     {
       
   940       switch ( manageCvt )
       
   941       {
       
   942       case mcvt_load:
       
   943         /* The cvt table has been loaded already; every time we change the */
       
   944         /* blend we may need to reload and remodify the cvt table.         */
       
   945         FT_FREE( face->cvt );
       
   946         face->cvt = NULL;
       
   947 
       
   948         tt_face_load_cvt( face, face->root.stream );
       
   949         break;
       
   950 
       
   951       case mcvt_modify:
       
   952         /* The original cvt table is in memory.  All we need to do is */
       
   953         /* apply the `cvar' table (if any).                           */
       
   954         tt_face_vary_cvt( face, face->root.stream );
       
   955         break;
       
   956 
       
   957       case mcvt_retain:
       
   958         /* The cvt table is correct for this set of coordinates. */
       
   959         break;
       
   960       }
       
   961     }
       
   962 
       
   963   Exit:
       
   964     return error;
       
   965   }
       
   966 
       
   967 
       
   968   /*************************************************************************/
       
   969   /*                                                                       */
       
   970   /* <Function>                                                            */
       
   971   /*    TT_Set_Var_Design                                                  */
       
   972   /*                                                                       */
       
   973   /* <Description>                                                         */
       
   974   /*    Set the coordinates for the instance, measured in the user         */
       
   975   /*    coordinate system.  Parse the `avar' table (if present) to convert */
       
   976   /*    from user to normalized coordinates.                               */
       
   977   /*                                                                       */
       
   978   /* <InOut>                                                               */
       
   979   /*    face       :: The font face.                                       */
       
   980   /*                  Initialize the blend struct with `gvar' data.        */
       
   981   /*                                                                       */
       
   982   /* <Input>                                                               */
       
   983   /*    num_coords :: This must be the axis count of the font.             */
       
   984   /*                                                                       */
       
   985   /*    coords     :: A coordinate array with `num_coords' elements.       */
       
   986   /*                                                                       */
       
   987   /* <Return>                                                              */
       
   988   /*    FreeType error code.  0 means success.                             */
       
   989   /*                                                                       */
       
   990   FT_LOCAL_DEF( FT_Error )
       
   991   TT_Set_Var_Design( TT_Face    face,
       
   992                      FT_UInt    num_coords,
       
   993                      FT_Fixed*  coords )
       
   994   {
       
   995     FT_Error        error      = TT_Err_Ok;
       
   996     FT_Fixed*       normalized = NULL;
       
   997     GX_Blend        blend;
       
   998     FT_MM_Var*      mmvar;
       
   999     FT_UInt         i, j;
       
  1000     FT_Var_Axis*    a;
       
  1001     GX_AVarSegment  av;
       
  1002     FT_Memory       memory = face->root.memory;
       
  1003 
       
  1004 
       
  1005     if ( face->blend == NULL )
       
  1006     {
       
  1007       if ( (error = TT_Get_MM_Var( face, NULL )) != 0 )
       
  1008         goto Exit;
       
  1009     }
       
  1010 
       
  1011     blend = face->blend;
       
  1012     mmvar = blend->mmvar;
       
  1013 
       
  1014     if ( num_coords != mmvar->num_axis )
       
  1015     {
       
  1016       error = TT_Err_Invalid_Argument;
       
  1017       goto Exit;
       
  1018     }
       
  1019 
       
  1020     /* Axis normalization is a two stage process.  First we normalize */
       
  1021     /* based on the [min,def,max] values for the axis to be [-1,0,1]. */
       
  1022     /* Then, if there's an `avar' table, we renormalize this range.   */
       
  1023 
       
  1024     if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) )
       
  1025       goto Exit;
       
  1026 
       
  1027     a = mmvar->axis;
       
  1028     for ( i = 0; i < mmvar->num_axis; ++i, ++a )
       
  1029     {
       
  1030       if ( coords[i] > a->maximum || coords[i] < a->minimum )
       
  1031       {
       
  1032         error = TT_Err_Invalid_Argument;
       
  1033         goto Exit;
       
  1034       }
       
  1035 
       
  1036       if ( coords[i] < a->def )
       
  1037       {
       
  1038         normalized[i] = -FT_MulDiv( coords[i] - a->def,
       
  1039                                     0x10000L,
       
  1040                                     a->minimum - a->def );
       
  1041       }
       
  1042       else if ( a->maximum == a->def )
       
  1043         normalized[i] = 0;
       
  1044       else
       
  1045       {
       
  1046         normalized[i] = FT_MulDiv( coords[i] - a->def,
       
  1047                                    0x10000L,
       
  1048                                    a->maximum - a->def );
       
  1049       }
       
  1050     }
       
  1051 
       
  1052     if ( !blend->avar_checked )
       
  1053       ft_var_load_avar( face );
       
  1054 
       
  1055     if ( blend->avar_segment != NULL )
       
  1056     {
       
  1057       av = blend->avar_segment;
       
  1058       for ( i = 0; i < mmvar->num_axis; ++i, ++av )
       
  1059       {
       
  1060         for ( j = 1; j < (FT_UInt)av->pairCount; ++j )
       
  1061           if ( normalized[i] < av->correspondence[j].fromCoord )
       
  1062           {
       
  1063             normalized[i] =
       
  1064               FT_MulDiv(
       
  1065                 FT_MulDiv(
       
  1066                   normalized[i] - av->correspondence[j - 1].fromCoord,
       
  1067                   0x10000L,
       
  1068                   av->correspondence[j].fromCoord -
       
  1069                     av->correspondence[j - 1].fromCoord ),
       
  1070                 av->correspondence[j].toCoord -
       
  1071                   av->correspondence[j - 1].toCoord,
       
  1072                 0x10000L ) +
       
  1073               av->correspondence[j - 1].toCoord;
       
  1074             break;
       
  1075           }
       
  1076       }
       
  1077     }
       
  1078 
       
  1079     error = TT_Set_MM_Blend( face, num_coords, normalized );
       
  1080 
       
  1081   Exit:
       
  1082     FT_FREE( normalized );
       
  1083     return error;
       
  1084   }
       
  1085 
       
  1086 
       
  1087   /*************************************************************************/
       
  1088   /*************************************************************************/
       
  1089   /*****                                                               *****/
       
  1090   /*****                     GX VAR PARSING ROUTINES                   *****/
       
  1091   /*****                                                               *****/
       
  1092   /*************************************************************************/
       
  1093   /*************************************************************************/
       
  1094 
       
  1095 
       
  1096   /*************************************************************************/
       
  1097   /*                                                                       */
       
  1098   /* <Function>                                                            */
       
  1099   /*    tt_face_vary_cvt                                                   */
       
  1100   /*                                                                       */
       
  1101   /* <Description>                                                         */
       
  1102   /*    Modify the loaded cvt table according to the `cvar' table and the  */
       
  1103   /*    font's blend.                                                      */
       
  1104   /*                                                                       */
       
  1105   /* <InOut>                                                               */
       
  1106   /*    face   :: A handle to the target face object.                      */
       
  1107   /*                                                                       */
       
  1108   /* <Input>                                                               */
       
  1109   /*    stream :: A handle to the input stream.                            */
       
  1110   /*                                                                       */
       
  1111   /* <Return>                                                              */
       
  1112   /*    FreeType error code.  0 means success.                             */
       
  1113   /*                                                                       */
       
  1114   /*    Most errors are ignored.  It is perfectly valid not to have a      */
       
  1115   /*    `cvar' table even if there is a `gvar' and `fvar' table.           */
       
  1116   /*                                                                       */
       
  1117   FT_LOCAL_DEF( FT_Error )
       
  1118   tt_face_vary_cvt( TT_Face    face,
       
  1119                     FT_Stream  stream )
       
  1120   {
       
  1121     FT_Error    error;
       
  1122     FT_Memory   memory = stream->memory;
       
  1123     FT_ULong    table_start;
       
  1124     FT_ULong    table_len;
       
  1125     FT_UInt     tupleCount;
       
  1126     FT_ULong    offsetToData;
       
  1127     FT_ULong    here;
       
  1128     FT_UInt     i, j;
       
  1129     FT_Fixed*   tuple_coords    = NULL;
       
  1130     FT_Fixed*   im_start_coords = NULL;
       
  1131     FT_Fixed*   im_end_coords   = NULL;
       
  1132     GX_Blend    blend           = face->blend;
       
  1133     FT_UInt     point_count;
       
  1134     FT_UShort*  localpoints;
       
  1135     FT_Short*   deltas;
       
  1136 
       
  1137 
       
  1138     FT_TRACE2(( "CVAR " ));
       
  1139 
       
  1140     if ( blend == NULL )
       
  1141     {
       
  1142       FT_TRACE2(( "tt_face_vary_cvt: no blend specified\n" ));
       
  1143 
       
  1144       error = TT_Err_Ok;
       
  1145       goto Exit;
       
  1146     }
       
  1147 
       
  1148     if ( face->cvt == NULL )
       
  1149     {
       
  1150       FT_TRACE2(( "tt_face_vary_cvt: no `cvt ' table\n" ));
       
  1151 
       
  1152       error = TT_Err_Ok;
       
  1153       goto Exit;
       
  1154     }
       
  1155 
       
  1156     error = face->goto_table( face, TTAG_cvar, stream, &table_len );
       
  1157     if ( error )
       
  1158     {
       
  1159       FT_TRACE2(( "is missing\n" ));
       
  1160 
       
  1161       error = TT_Err_Ok;
       
  1162       goto Exit;
       
  1163     }
       
  1164 
       
  1165     if ( FT_FRAME_ENTER( table_len ) )
       
  1166     {
       
  1167       error = TT_Err_Ok;
       
  1168       goto Exit;
       
  1169     }
       
  1170 
       
  1171     table_start = FT_Stream_FTell( stream );
       
  1172     if ( FT_GET_LONG() != 0x00010000L )
       
  1173     {
       
  1174       FT_TRACE2(( "bad table version\n" ));
       
  1175 
       
  1176       error = TT_Err_Ok;
       
  1177       goto FExit;
       
  1178     }
       
  1179 
       
  1180     if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis )    ||
       
  1181          FT_NEW_ARRAY( im_start_coords, blend->num_axis ) ||
       
  1182          FT_NEW_ARRAY( im_end_coords, blend->num_axis )   )
       
  1183       goto FExit;
       
  1184 
       
  1185     tupleCount   = FT_GET_USHORT();
       
  1186     offsetToData = table_start + FT_GET_USHORT();
       
  1187 
       
  1188     /* The documentation implies there are flags packed into the        */
       
  1189     /* tuplecount, but John Jenkins says that shared points don't apply */
       
  1190     /* to `cvar', and no other flags are defined.                       */
       
  1191 
       
  1192     for ( i = 0; i < ( tupleCount & 0xFFF ); ++i )
       
  1193     {
       
  1194       FT_UInt   tupleDataSize;
       
  1195       FT_UInt   tupleIndex;
       
  1196       FT_Fixed  apply;
       
  1197 
       
  1198 
       
  1199       tupleDataSize = FT_GET_USHORT();
       
  1200       tupleIndex    = FT_GET_USHORT();
       
  1201 
       
  1202       /* There is no provision here for a global tuple coordinate section, */
       
  1203       /* so John says.  There are no tuple indices, just embedded tuples.  */
       
  1204 
       
  1205       if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
       
  1206       {
       
  1207         for ( j = 0; j < blend->num_axis; ++j )
       
  1208           tuple_coords[j] = FT_GET_SHORT() << 2; /* convert from        */
       
  1209                                                  /* short frac to fixed */
       
  1210       }
       
  1211       else
       
  1212       {
       
  1213         /* skip this tuple; it makes no sense */
       
  1214 
       
  1215         if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
       
  1216           for ( j = 0; j < 2 * blend->num_axis; ++j )
       
  1217             (void)FT_GET_SHORT();
       
  1218 
       
  1219         offsetToData += tupleDataSize;
       
  1220         continue;
       
  1221       }
       
  1222 
       
  1223       if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
       
  1224       {
       
  1225         for ( j = 0; j < blend->num_axis; ++j )
       
  1226           im_start_coords[j] = FT_GET_SHORT() << 2;
       
  1227         for ( j = 0; j < blend->num_axis; ++j )
       
  1228           im_end_coords[j] = FT_GET_SHORT() << 2;
       
  1229       }
       
  1230 
       
  1231       apply = ft_var_apply_tuple( blend,
       
  1232                                   (FT_UShort)tupleIndex,
       
  1233                                   tuple_coords,
       
  1234                                   im_start_coords,
       
  1235                                   im_end_coords );
       
  1236       if ( /* tuple isn't active for our blend */
       
  1237            apply == 0                                    ||
       
  1238            /* global points not allowed,           */
       
  1239            /* if they aren't local, makes no sense */
       
  1240            !( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) )
       
  1241       {
       
  1242         offsetToData += tupleDataSize;
       
  1243         continue;
       
  1244       }
       
  1245 
       
  1246       here = FT_Stream_FTell( stream );
       
  1247 
       
  1248       FT_Stream_SeekSet( stream, offsetToData );
       
  1249 
       
  1250       localpoints = ft_var_readpackedpoints( stream, &point_count );
       
  1251       deltas      = ft_var_readpackeddeltas( stream,
       
  1252                                              point_count == 0 ? face->cvt_size
       
  1253                                                               : point_count );
       
  1254       if ( localpoints == NULL || deltas == NULL )
       
  1255         /* failure, ignore it */;
       
  1256 
       
  1257       else if ( localpoints == ALL_POINTS )
       
  1258       {
       
  1259         /* this means that there are deltas for every entry in cvt */
       
  1260         for ( j = 0; j < face->cvt_size; ++j )
       
  1261           face->cvt[j] = (FT_Short)( face->cvt[j] +
       
  1262                                      FT_MulFix( deltas[j], apply ) );
       
  1263       }
       
  1264 
       
  1265       else
       
  1266       {
       
  1267         for ( j = 0; j < point_count; ++j )
       
  1268         {
       
  1269           int  pindex = localpoints[j];
       
  1270 
       
  1271           face->cvt[pindex] = (FT_Short)( face->cvt[pindex] +
       
  1272                                           FT_MulFix( deltas[j], apply ) );
       
  1273         }
       
  1274       }
       
  1275 
       
  1276       if ( localpoints != ALL_POINTS )
       
  1277         FT_FREE( localpoints );
       
  1278       FT_FREE( deltas );
       
  1279 
       
  1280       offsetToData += tupleDataSize;
       
  1281 
       
  1282       FT_Stream_SeekSet( stream, here );
       
  1283     }
       
  1284 
       
  1285   FExit:
       
  1286     FT_FRAME_EXIT();
       
  1287 
       
  1288   Exit:
       
  1289     FT_FREE( tuple_coords );
       
  1290     FT_FREE( im_start_coords );
       
  1291     FT_FREE( im_end_coords );
       
  1292 
       
  1293     return error;
       
  1294   }
       
  1295 
       
  1296 
       
  1297   /*************************************************************************/
       
  1298   /*                                                                       */
       
  1299   /* <Function>                                                            */
       
  1300   /*    TT_Vary_Get_Glyph_Deltas                                           */
       
  1301   /*                                                                       */
       
  1302   /* <Description>                                                         */
       
  1303   /*    Load the appropriate deltas for the current glyph.                 */
       
  1304   /*                                                                       */
       
  1305   /* <Input>                                                               */
       
  1306   /*    face        :: A handle to the target face object.                 */
       
  1307   /*                                                                       */
       
  1308   /*    glyph_index :: The index of the glyph being modified.              */
       
  1309   /*                                                                       */
       
  1310   /*    n_points    :: The number of the points in the glyph, including    */
       
  1311   /*                   phantom points.                                     */
       
  1312   /*                                                                       */
       
  1313   /* <Output>                                                              */
       
  1314   /*    deltas      :: The array of points to change.                      */
       
  1315   /*                                                                       */
       
  1316   /* <Return>                                                              */
       
  1317   /*    FreeType error code.  0 means success.                             */
       
  1318   /*                                                                       */
       
  1319   FT_LOCAL_DEF( FT_Error )
       
  1320   TT_Vary_Get_Glyph_Deltas( TT_Face      face,
       
  1321                             FT_UInt      glyph_index,
       
  1322                             FT_Vector*  *deltas,
       
  1323                             FT_UInt      n_points )
       
  1324   {
       
  1325     FT_Stream   stream = face->root.stream;
       
  1326     FT_Memory   memory = stream->memory;
       
  1327     GX_Blend    blend  = face->blend;
       
  1328     FT_Vector*  delta_xy;
       
  1329 
       
  1330     FT_Error    error;
       
  1331     FT_ULong    glyph_start;
       
  1332     FT_UInt     tupleCount;
       
  1333     FT_ULong    offsetToData;
       
  1334     FT_ULong    here;
       
  1335     FT_UInt     i, j;
       
  1336     FT_Fixed*   tuple_coords    = NULL;
       
  1337     FT_Fixed*   im_start_coords = NULL;
       
  1338     FT_Fixed*   im_end_coords   = NULL;
       
  1339     FT_UInt     point_count, spoint_count = 0;
       
  1340     FT_UShort*  sharedpoints = NULL;
       
  1341     FT_UShort*  localpoints  = NULL;
       
  1342     FT_UShort*  points;
       
  1343     FT_Short    *deltas_x, *deltas_y;
       
  1344 
       
  1345 
       
  1346     if ( !face->doblend || blend == NULL )
       
  1347       return TT_Err_Invalid_Argument;
       
  1348 
       
  1349     /* to be freed by the caller */
       
  1350     if ( FT_NEW_ARRAY( delta_xy, n_points ) )
       
  1351       goto Exit;
       
  1352     *deltas = delta_xy;
       
  1353 
       
  1354     if ( glyph_index >= blend->gv_glyphcnt      ||
       
  1355          blend->glyphoffsets[glyph_index] ==
       
  1356            blend->glyphoffsets[glyph_index + 1] )
       
  1357       return TT_Err_Ok;               /* no variation data for this glyph */
       
  1358 
       
  1359     if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] )   ||
       
  1360          FT_FRAME_ENTER( blend->glyphoffsets[glyph_index + 1] -
       
  1361                            blend->glyphoffsets[glyph_index] ) )
       
  1362       goto Fail1;
       
  1363 
       
  1364     glyph_start = FT_Stream_FTell( stream );
       
  1365 
       
  1366     /* each set of glyph variation data is formatted similarly to `cvar' */
       
  1367     /* (except we get shared points and global tuples)                   */
       
  1368 
       
  1369     if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis )    ||
       
  1370          FT_NEW_ARRAY( im_start_coords, blend->num_axis ) ||
       
  1371          FT_NEW_ARRAY( im_end_coords, blend->num_axis )   )
       
  1372       goto Fail2;
       
  1373 
       
  1374     tupleCount   = FT_GET_USHORT();
       
  1375     offsetToData = glyph_start + FT_GET_USHORT();
       
  1376 
       
  1377     if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS )
       
  1378     {
       
  1379       here = FT_Stream_FTell( stream );
       
  1380 
       
  1381       FT_Stream_SeekSet( stream, offsetToData );
       
  1382 
       
  1383       sharedpoints = ft_var_readpackedpoints( stream, &spoint_count );
       
  1384       offsetToData = FT_Stream_FTell( stream );
       
  1385 
       
  1386       FT_Stream_SeekSet( stream, here );
       
  1387     }
       
  1388 
       
  1389     for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); ++i )
       
  1390     {
       
  1391       FT_UInt   tupleDataSize;
       
  1392       FT_UInt   tupleIndex;
       
  1393       FT_Fixed  apply;
       
  1394 
       
  1395 
       
  1396       tupleDataSize = FT_GET_USHORT();
       
  1397       tupleIndex    = FT_GET_USHORT();
       
  1398 
       
  1399       if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
       
  1400       {
       
  1401         for ( j = 0; j < blend->num_axis; ++j )
       
  1402           tuple_coords[j] = FT_GET_SHORT() << 2;  /* convert from        */
       
  1403                                                   /* short frac to fixed */
       
  1404       }
       
  1405       else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount )
       
  1406       {
       
  1407         error = TT_Err_Invalid_Table;
       
  1408         goto Fail3;
       
  1409       }
       
  1410       else
       
  1411       {
       
  1412         FT_MEM_COPY(
       
  1413           tuple_coords,
       
  1414           &blend->tuplecoords[(tupleIndex & 0xFFF) * blend->num_axis],
       
  1415           blend->num_axis * sizeof ( FT_Fixed ) );
       
  1416       }
       
  1417 
       
  1418       if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
       
  1419       {
       
  1420         for ( j = 0; j < blend->num_axis; ++j )
       
  1421           im_start_coords[j] = FT_GET_SHORT() << 2;
       
  1422         for ( j = 0; j < blend->num_axis; ++j )
       
  1423           im_end_coords[j] = FT_GET_SHORT() << 2;
       
  1424       }
       
  1425 
       
  1426       apply = ft_var_apply_tuple( blend,
       
  1427                                   (FT_UShort)tupleIndex,
       
  1428                                   tuple_coords,
       
  1429                                   im_start_coords,
       
  1430                                   im_end_coords );
       
  1431 
       
  1432       if ( apply == 0 )              /* tuple isn't active for our blend */
       
  1433       {
       
  1434         offsetToData += tupleDataSize;
       
  1435         continue;
       
  1436       }
       
  1437 
       
  1438       here = FT_Stream_FTell( stream );
       
  1439 
       
  1440       if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS )
       
  1441       {
       
  1442         FT_Stream_SeekSet( stream, offsetToData );
       
  1443 
       
  1444         localpoints = ft_var_readpackedpoints( stream, &point_count );
       
  1445         points      = localpoints;
       
  1446       }
       
  1447       else
       
  1448       {
       
  1449         points      = sharedpoints;
       
  1450         point_count = spoint_count;
       
  1451       }
       
  1452 
       
  1453       deltas_x = ft_var_readpackeddeltas( stream,
       
  1454                                           point_count == 0 ? n_points
       
  1455                                                            : point_count );
       
  1456       deltas_y = ft_var_readpackeddeltas( stream,
       
  1457                                           point_count == 0 ? n_points
       
  1458                                                            : point_count );
       
  1459 
       
  1460       if ( points == NULL || deltas_y == NULL || deltas_x == NULL )
       
  1461         ; /* failure, ignore it */
       
  1462 
       
  1463       else if ( points == ALL_POINTS )
       
  1464       {
       
  1465         /* this means that there are deltas for every point in the glyph */
       
  1466         for ( j = 0; j < n_points; ++j )
       
  1467         {
       
  1468           delta_xy[j].x += FT_MulFix( deltas_x[j], apply );
       
  1469           delta_xy[j].y += FT_MulFix( deltas_y[j], apply );
       
  1470         }
       
  1471       }
       
  1472 
       
  1473       else
       
  1474       {
       
  1475         for ( j = 0; j < point_count; ++j )
       
  1476         {
       
  1477           delta_xy[localpoints[j]].x += FT_MulFix( deltas_x[j], apply );
       
  1478           delta_xy[localpoints[j]].y += FT_MulFix( deltas_y[j], apply );
       
  1479         }
       
  1480       }
       
  1481 
       
  1482       if ( localpoints != ALL_POINTS )
       
  1483         FT_FREE( localpoints );
       
  1484       FT_FREE( deltas_x );
       
  1485       FT_FREE( deltas_y );
       
  1486 
       
  1487       offsetToData += tupleDataSize;
       
  1488 
       
  1489       FT_Stream_SeekSet( stream, here );
       
  1490     }
       
  1491 
       
  1492   Fail3:
       
  1493     FT_FREE( tuple_coords );
       
  1494     FT_FREE( im_start_coords );
       
  1495     FT_FREE( im_end_coords );
       
  1496 
       
  1497   Fail2:
       
  1498     FT_FRAME_EXIT();
       
  1499 
       
  1500   Fail1:
       
  1501     if ( error )
       
  1502     {
       
  1503       FT_FREE( delta_xy );
       
  1504       *deltas = NULL;
       
  1505     }
       
  1506 
       
  1507   Exit:
       
  1508     return error;
       
  1509   }
       
  1510 
       
  1511 
       
  1512   /*************************************************************************/
       
  1513   /*                                                                       */
       
  1514   /* <Function>                                                            */
       
  1515   /*    tt_done_blend                                                      */
       
  1516   /*                                                                       */
       
  1517   /* <Description>                                                         */
       
  1518   /*    Frees the blend internal data structure.                           */
       
  1519   /*                                                                       */
       
  1520   FT_LOCAL_DEF( void )
       
  1521   tt_done_blend( FT_Memory  memory,
       
  1522                  GX_Blend   blend )
       
  1523   {
       
  1524     if ( blend != NULL )
       
  1525     {
       
  1526       FT_UInt  i;
       
  1527 
       
  1528 
       
  1529       FT_FREE( blend->normalizedcoords );
       
  1530       FT_FREE( blend->mmvar );
       
  1531 
       
  1532       if ( blend->avar_segment != NULL )
       
  1533       {
       
  1534         for ( i = 0; i < blend->num_axis; ++i )
       
  1535           FT_FREE( blend->avar_segment[i].correspondence );
       
  1536         FT_FREE( blend->avar_segment );
       
  1537       }
       
  1538 
       
  1539       FT_FREE( blend->tuplecoords );
       
  1540       FT_FREE( blend->glyphoffsets );
       
  1541       FT_FREE( blend );
       
  1542     }
       
  1543   }
       
  1544 
       
  1545 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
       
  1546 
       
  1547 
       
  1548 /* END */