Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

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