ttgxvar.c
上传用户:yisoukefu
上传日期:2020-08-09
资源大小:39506k
文件大小:55k
源码类别:

其他游戏

开发平台:

Visual C++

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