zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
ttgxvar.c
Go to the documentation of this file.
1 /***************************************************************************/
2 /* */
3 /* ttgxvar.c */
4 /* */
5 /* TrueType GX Font Variation loader */
6 /* */
7 /* Copyright 2004-2011 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 = NULL;
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;
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  {
346  FT_UShort axisCount;
347  FT_UShort globalCoordCount;
348  FT_ULong offsetToCoord;
349  FT_UShort glyphCount;
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 ),
397  FT_FRAME_ULONG ( offsetToData ),
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  {
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;
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  /* */
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 = NULL;
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 ),
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 ),
661  FT_FRAME_USHORT( nameID ),
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  /* */
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  /* */
992  FT_UInt num_coords,
993  FT_Fixed* coords )
994  {
995  FT_Error error = TT_Err_Ok;
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  /* */
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  /* */
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 = NULL;
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  if ( localpoints[j] >= n_points )
1478  continue;
1479 
1480  delta_xy[localpoints[j]].x += FT_MulFix( deltas_x[j], apply );
1481  delta_xy[localpoints[j]].y += FT_MulFix( deltas_y[j], apply );
1482  }
1483  }
1484 
1485  if ( localpoints != ALL_POINTS )
1486  FT_FREE( localpoints );
1487  FT_FREE( deltas_x );
1488  FT_FREE( deltas_y );
1489 
1490  offsetToData += tupleDataSize;
1491 
1492  FT_Stream_SeekSet( stream, here );
1493  }
1494 
1495  Fail3:
1496  FT_FREE( tuple_coords );
1497  FT_FREE( im_start_coords );
1498  FT_FREE( im_end_coords );
1499 
1500  Fail2:
1501  FT_FRAME_EXIT();
1502 
1503  Fail1:
1504  if ( error )
1505  {
1506  FT_FREE( delta_xy );
1507  *deltas = NULL;
1508  }
1509 
1510  Exit:
1511  return error;
1512  }
1513 
1514 
1515  /*************************************************************************/
1516  /* */
1517  /* <Function> */
1518  /* tt_done_blend */
1519  /* */
1520  /* <Description> */
1521  /* Frees the blend internal data structure. */
1522  /* */
1523  FT_LOCAL_DEF( void )
1524  tt_done_blend( FT_Memory memory,
1525  GX_Blend blend )
1526  {
1527  if ( blend != NULL )
1528  {
1529  FT_UInt i;
1530 
1531 
1532  FT_FREE( blend->normalizedcoords );
1533  FT_FREE( blend->mmvar );
1534 
1535  if ( blend->avar_segment != NULL )
1536  {
1537  for ( i = 0; i < blend->num_axis; ++i )
1538  FT_FREE( blend->avar_segment[i].correspondence );
1539  FT_FREE( blend->avar_segment );
1540  }
1541 
1542  FT_FREE( blend->tuplecoords );
1543  FT_FREE( blend->glyphoffsets );
1544  FT_FREE( blend );
1545  }
1546  }
1547 
1548 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
1549 
1550 
1551 /* END */
#define FT_ALLOC(ptr, size)
Definition: ftmemory.h:260
FT_String * name
Definition: ftmm.h:142
FT_Fixed * coords
Definition: ftmm.h:172
int FT_Error
Definition: fttypes.h:296
#define FT_GET_BYTE()
Definition: ftstream.h:294
#define FT_FRAME_LONG(f)
Definition: ftstream.h:120
signed long FT_Long
Definition: fttypes.h:238
unsigned long FT_ULong
Definition: fttypes.h:249
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
Definition: glew.h:1824
#define NULL
Definition: ftobjs.h:61
signed int FT_Int
Definition: fttypes.h:216
#define TTAG_slnt
Definition: ttgxvar.h:141
GLint GLenum GLboolean normalized
Definition: glew.h:1891
FT_UInt num_namedstyles
Definition: ftmm.h:214
GLuint GLuint stream
Definition: glew.h:6573
GLclampd n
Definition: glew.h:7287
#define TTAG_opsz
Definition: ttgxvar.h:140
#define FT_GET_CHAR()
Definition: ftstream.h:293
#define TTAG_gvar
Definition: tttags.h:61
GLenum GLuint coords
Definition: glew.h:7189
int32_t j
Definition: e_log.c:102
FT_Fixed minimum
Definition: ftmm.h:144
int const char * version
Definition: zlib.h:813
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:8736
TT_Loader_GotoTableFunc goto_table
Definition: tttypes.h:1288
FT_Fixed maximum
Definition: ftmm.h:146
#define TTAG_wdth
Definition: ttgxvar.h:139
FT_Var_Axis * axis
Definition: ftmm.h:215
tt_face_load_cvt(TT_Face face, FT_Stream stream)
Definition: ttpload.c:280
FT_UInt num_axis
Definition: ftmm.h:212
TT_Get_MM_Var(TT_Face face, FT_MM_Var **master)
TT_Vary_Get_Glyph_Deltas(TT_Face face, FT_UInt glyph_index, FT_Vector **deltas, FT_UInt n_points)
GX_AVarCorrespondence correspondence
Definition: ttgxvar.h:59
FT_UInt num_designs
Definition: ftmm.h:213
#define FT_STREAM_READ_FIELDS(fields, object)
Definition: ftstream.h:513
struct FT_MM_Var_ FT_MM_Var
FT_Memory memory
Definition: ftsystem.h:332
#define FT_GET_USHORT()
Definition: ftstream.h:296
#define FT_FREE(ptr)
Definition: ftmemory.h:286
#define FT_FRAME_END
Definition: ftstream.h:118
GLint first
Definition: gl2ext.h:1011
struct FT_Var_Named_Style_ FT_Var_Named_Style
FT_ULong tag
Definition: ftmm.h:148
#define FT_FRAME_USHORT(f)
Definition: ftstream.h:123
#define FT_LOCAL_DEF(x)
Definition: ftconfig.h:467
tt_done_blend(FT_Memory memory, GX_Blend blend)
#define TTAG_avar
Definition: tttags.h:36
FT_MulDiv(FT_Long a, FT_Long b, FT_Long c)
Definition: ftcalc.c:358
FT_Error error
Definition: cffdrivr.c:407
FT_UShort pairCount
Definition: ttgxvar.h:58
FT_Pos x
Definition: ftimage.h:77
char FT_String
Definition: fttypes.h:183
GLenum face
Definition: gl2ext.h:1490
FT_Pos y
Definition: ftimage.h:78
#define FT_TRACE2(varformat)
Definition: ftdebug.h:159
#define TTAG_cvar
Definition: tttags.h:46
#define TTAG_fvar
Definition: tttags.h:55
TT_Set_MM_Blend(TT_Face face, FT_UInt num_coords, FT_Fixed *coords)
TT_Set_Var_Design(TT_Face face, FT_UInt num_coords, FT_Fixed *coords)
#define FALSE
Definition: ftobjs.h:57
#define TTAG_wght
Definition: ttgxvar.h:138
tt_face_vary_cvt(TT_Face face, FT_Stream stream)
signed short FT_Short
Definition: fttypes.h:194
typedefFT_BEGIN_HEADER struct FT_MemoryRec_ * FT_Memory
Definition: ftsystem.h:66
#define FT_FRAME_EXIT()
Definition: ftstream.h:521
sizeof(FT_AutofitterRec)
#define FT_NEW_ARRAY(ptr, count)
Definition: ftmemory.h:290
#define FT_STREAM_SEEK(position)
Definition: ftstream.h:496
FT_MulFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:435
#define FT_STREAM_POS()
Definition: ftstream.h:493
signed long FT_Fixed
Definition: fttypes.h:284
#define FT_FRAME_ULONG(f)
Definition: ftstream.h:121
GLenum GLsizei GLsizei GLsizei GLsizei GLbitfield flags
Definition: glew.h:2767
unsigned int FT_UInt
Definition: fttypes.h:227
#define FT_GET_SHORT()
Definition: ftstream.h:295
#define FT_GET_ULONG()
Definition: ftstream.h:300
GLuint GLdouble GLdouble GLint GLint const GLdouble * points
Definition: glew.h:3337
#define FT_FRAME_ENTER(size)
Definition: ftstream.h:517
#define FT_NEW(ptr)
Definition: ftmemory.h:288
int i
Definition: pngrutil.c:1377
#define FT_MEM_COPY(dest, source, count)
Definition: ftmemory.h:203
FT_Fixed def
Definition: ftmm.h:145
FT_UInt strid
Definition: ftmm.h:173
#define FT_GET_LONG()
Definition: ftstream.h:299
FT_UInt strid
Definition: ftmm.h:149
FT_Var_Named_Style * namedstyle
Definition: ftmm.h:216
unsigned short FT_UShort
Definition: fttypes.h:205
#define FT_FACE_STREAM(x)
Definition: ftobjs.h:530
#define FT_UNUSED(arg)
Definition: ftconfig.h:101
#define TRUE
Definition: ftobjs.h:53
#define FT_FRAME_START(size)
Definition: ftstream.h:117
size_t FT_Offset
Definition: fttypes.h:320