~ubuntu-branches/ubuntu/utopic/hedgewars/utopic

« back to all changes in this revision

Viewing changes to misc/libfreetype/src/truetype/ttgxvar.c

  • Committer: Package Import Robot
  • Author(s): Gianfranco Costamagna
  • Date: 2014-01-02 12:37:23 UTC
  • mfrom: (19.1.5 sid)
  • Revision ID: package-import@ubuntu.com-20140102123723-6pdhmyj8tb5y8xbg
Tags: 0.9.20.3-1
New upstream minor release, suitable for unstable

Show diffs side-by-side

added added

removed removed

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