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