Visualization Library 2.0.0-b5

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
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-2013 by */
8 /* David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. */
9 /* */
10 /* This file is part of the FreeType project, and may only be used, */
11 /* modified, and distributed under the terms of the FreeType project */
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 /* this file you indicate that you have read the license and */
14 /* understand and accept it fully. */
15 /* */
16 /***************************************************************************/
17 
18 
19  /*************************************************************************/
20  /* */
21  /* Apple documents the `fvar', `gvar', `cvar', and `avar' tables at */
22  /* */
23  /* http://developer.apple.com/fonts/TTRefMan/RM06/Chap6[fgca]var.html */
24  /* */
25  /* The documentation for `fvar' is inconsistent. At one point it says */
26  /* that `countSizePairs' should be 3, at another point 2. It should */
27  /* be 2. */
28  /* */
29  /* The documentation for `gvar' is not intelligible; `cvar' refers you */
30  /* to `gvar' and is thus also incomprehensible. */
31  /* */
32  /* The documentation for `avar' appears correct, but Apple has no fonts */
33  /* with an `avar' table, so it is hard to test. */
34  /* */
35  /* Many thanks to John Jenkins (at Apple) in figuring this out. */
36  /* */
37  /* */
38  /* Apple's `kern' table has some references to tuple indices, but as */
39  /* there is no indication where these indices are defined, nor how to */
40  /* interpolate the kerning values (different tuples have different */
41  /* classes) this issue is ignored. */
42  /* */
43  /*************************************************************************/
44 
45 
46 #include <ft2build.h>
47 #include FT_INTERNAL_DEBUG_H
48 #include FT_CONFIG_CONFIG_H
49 #include FT_INTERNAL_STREAM_H
50 #include FT_INTERNAL_SFNT_H
51 #include FT_TRUETYPE_TAGS_H
52 #include FT_MULTIPLE_MASTERS_H
53 
54 #include "ttpload.h"
55 #include "ttgxvar.h"
56 
57 #include "tterrors.h"
58 
59 
60 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
61 
62 
63 #define FT_Stream_FTell( stream ) \
64  ( (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*)( ~0 )
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;
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 = FT_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 = FT_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 = FT_THROW( 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 = 0x10000L;
505 
506 
507  for ( i = 0; i < blend->num_axis; ++i )
508  {
509  if ( tuple_coords[i] == 0 )
510  /* It's not clear why (for intermediate tuples) we don't need */
511  /* to check against start/end -- the documentation says we don't. */
512  /* Similarly, it's unclear why we don't need to scale along the */
513  /* axis. */
514  continue;
515 
516  else if ( blend->normalizedcoords[i] == 0 ||
517  ( blend->normalizedcoords[i] < 0 && tuple_coords[i] > 0 ) ||
518  ( blend->normalizedcoords[i] > 0 && tuple_coords[i] < 0 ) )
519  {
520  apply = 0;
521  break;
522  }
523 
524  else if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) )
525  /* not an intermediate tuple */
526  apply = FT_MulFix( apply,
527  blend->normalizedcoords[i] > 0
528  ? blend->normalizedcoords[i]
529  : -blend->normalizedcoords[i] );
530 
531  else if ( blend->normalizedcoords[i] <= im_start_coords[i] ||
532  blend->normalizedcoords[i] >= im_end_coords[i] )
533  {
534  apply = 0;
535  break;
536  }
537 
538  else if ( blend->normalizedcoords[i] < tuple_coords[i] )
539  apply = FT_MulDiv( apply,
540  blend->normalizedcoords[i] - im_start_coords[i],
541  tuple_coords[i] - im_start_coords[i] );
542 
543  else
544  apply = FT_MulDiv( apply,
545  im_end_coords[i] - blend->normalizedcoords[i],
546  im_end_coords[i] - tuple_coords[i] );
547  }
548 
549  return apply;
550  }
551 
552 
553  /*************************************************************************/
554  /*************************************************************************/
555  /***** *****/
556  /***** MULTIPLE MASTERS SERVICE FUNCTIONS *****/
557  /***** *****/
558  /*************************************************************************/
559  /*************************************************************************/
560 
561 
562  typedef struct GX_FVar_Head_
563  {
565  FT_UShort offsetToData;
566  FT_UShort countSizePairs;
567  FT_UShort axisCount;
568  FT_UShort axisSize;
569  FT_UShort instanceCount;
570  FT_UShort instanceSize;
571 
572  } GX_FVar_Head;
573 
574 
575  typedef struct fvar_axis_
576  {
577  FT_ULong axisTag;
578  FT_ULong minValue;
579  FT_ULong defaultValue;
580  FT_ULong maxValue;
582  FT_UShort nameID;
583 
584  } GX_FVar_Axis;
585 
586 
587  /*************************************************************************/
588  /* */
589  /* <Function> */
590  /* TT_Get_MM_Var */
591  /* */
592  /* <Description> */
593  /* Check that the font's `fvar' table is valid, parse it, and return */
594  /* those data. */
595  /* */
596  /* <InOut> */
597  /* face :: The font face. */
598  /* TT_Get_MM_Var initializes the blend structure. */
599  /* */
600  /* <Output> */
601  /* master :: The `fvar' data (must be freed by caller). */
602  /* */
603  /* <Return> */
604  /* FreeType error code. 0 means success. */
605  /* */
607  TT_Get_MM_Var( TT_Face face,
608  FT_MM_Var* *master )
609  {
610  FT_Stream stream = face->root.stream;
611  FT_Memory memory = face->root.memory;
612  FT_ULong table_len;
613  FT_Error error = FT_Err_Ok;
614  FT_ULong fvar_start;
615  FT_Int i, j;
616  FT_MM_Var* mmvar = NULL;
617  FT_Fixed* next_coords;
618  FT_String* next_name;
619  FT_Var_Axis* a;
620  FT_Var_Named_Style* ns;
621  GX_FVar_Head fvar_head;
622 
623  static const FT_Frame_Field fvar_fields[] =
624  {
625 
626 #undef FT_STRUCTURE
627 #define FT_STRUCTURE GX_FVar_Head
628 
629  FT_FRAME_START( 16 ),
630  FT_FRAME_LONG ( version ),
631  FT_FRAME_USHORT( offsetToData ),
632  FT_FRAME_USHORT( countSizePairs ),
633  FT_FRAME_USHORT( axisCount ),
634  FT_FRAME_USHORT( axisSize ),
635  FT_FRAME_USHORT( instanceCount ),
636  FT_FRAME_USHORT( instanceSize ),
638  };
639 
640  static const FT_Frame_Field fvaraxis_fields[] =
641  {
642 
643 #undef FT_STRUCTURE
644 #define FT_STRUCTURE GX_FVar_Axis
645 
646  FT_FRAME_START( 20 ),
647  FT_FRAME_ULONG ( axisTag ),
648  FT_FRAME_ULONG ( minValue ),
649  FT_FRAME_ULONG ( defaultValue ),
650  FT_FRAME_ULONG ( maxValue ),
652  FT_FRAME_USHORT( nameID ),
654  };
655 
656 
657  if ( face->blend == NULL )
658  {
659  /* both `fvar' and `gvar' must be present */
660  if ( (error = face->goto_table( face, TTAG_gvar,
661  stream, &table_len )) != 0 )
662  goto Exit;
663 
664  if ( (error = face->goto_table( face, TTAG_fvar,
665  stream, &table_len )) != 0 )
666  goto Exit;
667 
668  fvar_start = FT_STREAM_POS( );
669 
670  if ( FT_STREAM_READ_FIELDS( fvar_fields, &fvar_head ) )
671  goto Exit;
672 
673  if ( fvar_head.version != (FT_Long)0x00010000L ||
674  fvar_head.countSizePairs != 2 ||
675  fvar_head.axisSize != 20 ||
676  /* axisCount limit implied by 16-bit instanceSize */
677  fvar_head.axisCount > 0x3FFE ||
678  fvar_head.instanceSize != 4 + 4 * fvar_head.axisCount ||
679  /* instanceCount limit implied by limited range of name IDs */
680  fvar_head.instanceCount > 0x7EFF ||
681  fvar_head.offsetToData + fvar_head.axisCount * 20U +
682  fvar_head.instanceCount * fvar_head.instanceSize > table_len )
683  {
684  error = FT_THROW( Invalid_Table );
685  goto Exit;
686  }
687 
688  if ( FT_NEW( face->blend ) )
689  goto Exit;
690 
691  /* cannot overflow 32-bit arithmetic because of limits above */
692  face->blend->mmvar_len =
693  sizeof ( FT_MM_Var ) +
694  fvar_head.axisCount * sizeof ( FT_Var_Axis ) +
695  fvar_head.instanceCount * sizeof ( FT_Var_Named_Style ) +
696  fvar_head.instanceCount * fvar_head.axisCount * sizeof ( FT_Fixed ) +
697  5 * fvar_head.axisCount;
698 
699  if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
700  goto Exit;
701  face->blend->mmvar = mmvar;
702 
703  mmvar->num_axis =
704  fvar_head.axisCount;
705  mmvar->num_designs =
706  ~0; /* meaningless in this context; each glyph */
707  /* may have a different number of designs */
708  /* (or tuples, as called by Apple) */
709  mmvar->num_namedstyles =
710  fvar_head.instanceCount;
711  mmvar->axis =
712  (FT_Var_Axis*)&(mmvar[1]);
713  mmvar->namedstyle =
714  (FT_Var_Named_Style*)&(mmvar->axis[fvar_head.axisCount]);
715 
716  next_coords =
717  (FT_Fixed*)&(mmvar->namedstyle[fvar_head.instanceCount]);
718  for ( i = 0; i < fvar_head.instanceCount; ++i )
719  {
720  mmvar->namedstyle[i].coords = next_coords;
721  next_coords += fvar_head.axisCount;
722  }
723 
724  next_name = (FT_String*)next_coords;
725  for ( i = 0; i < fvar_head.axisCount; ++i )
726  {
727  mmvar->axis[i].name = next_name;
728  next_name += 5;
729  }
730 
731  if ( FT_STREAM_SEEK( fvar_start + fvar_head.offsetToData ) )
732  goto Exit;
733 
734  a = mmvar->axis;
735  for ( i = 0; i < fvar_head.axisCount; ++i )
736  {
737  GX_FVar_Axis axis_rec;
738 
739 
740  if ( FT_STREAM_READ_FIELDS( fvaraxis_fields, &axis_rec ) )
741  goto Exit;
742  a->tag = axis_rec.axisTag;
743  a->minimum = axis_rec.minValue; /* A Fixed */
744  a->def = axis_rec.defaultValue; /* A Fixed */
745  a->maximum = axis_rec.maxValue; /* A Fixed */
746  a->strid = axis_rec.nameID;
747 
748  a->name[0] = (FT_String)( a->tag >> 24 );
749  a->name[1] = (FT_String)( ( a->tag >> 16 ) & 0xFF );
750  a->name[2] = (FT_String)( ( a->tag >> 8 ) & 0xFF );
751  a->name[3] = (FT_String)( ( a->tag ) & 0xFF );
752  a->name[4] = 0;
753 
754  ++a;
755  }
756 
757  ns = mmvar->namedstyle;
758  for ( i = 0; i < fvar_head.instanceCount; ++i, ++ns )
759  {
760  if ( FT_FRAME_ENTER( 4L + 4L * fvar_head.axisCount ) )
761  goto Exit;
762 
763  ns->strid = FT_GET_USHORT();
764  (void) /* flags = */ FT_GET_USHORT();
765 
766  for ( j = 0; j < fvar_head.axisCount; ++j )
767  ns->coords[j] = FT_GET_ULONG(); /* A Fixed */
768 
769  FT_FRAME_EXIT();
770  }
771  }
772 
773  if ( master != NULL )
774  {
775  FT_UInt n;
776 
777 
778  if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
779  goto Exit;
780  FT_MEM_COPY( mmvar, face->blend->mmvar, face->blend->mmvar_len );
781 
782  mmvar->axis =
783  (FT_Var_Axis*)&(mmvar[1]);
784  mmvar->namedstyle =
785  (FT_Var_Named_Style*)&(mmvar->axis[mmvar->num_axis]);
786  next_coords =
787  (FT_Fixed*)&(mmvar->namedstyle[mmvar->num_namedstyles]);
788 
789  for ( n = 0; n < mmvar->num_namedstyles; ++n )
790  {
791  mmvar->namedstyle[n].coords = next_coords;
792  next_coords += mmvar->num_axis;
793  }
794 
795  a = mmvar->axis;
796  next_name = (FT_String*)next_coords;
797  for ( n = 0; n < mmvar->num_axis; ++n )
798  {
799  a->name = next_name;
800 
801  /* standard PostScript names for some standard apple tags */
802  if ( a->tag == TTAG_wght )
803  a->name = (char *)"Weight";
804  else if ( a->tag == TTAG_wdth )
805  a->name = (char *)"Width";
806  else if ( a->tag == TTAG_opsz )
807  a->name = (char *)"OpticalSize";
808  else if ( a->tag == TTAG_slnt )
809  a->name = (char *)"Slant";
810 
811  next_name += 5;
812  ++a;
813  }
814 
815  *master = mmvar;
816  }
817 
818  Exit:
819  return error;
820  }
821 
822 
823  /*************************************************************************/
824  /* */
825  /* <Function> */
826  /* TT_Set_MM_Blend */
827  /* */
828  /* <Description> */
829  /* Set the blend (normalized) coordinates for this instance of the */
830  /* font. Check that the `gvar' table is reasonable and does some */
831  /* initial preparation. */
832  /* */
833  /* <InOut> */
834  /* face :: The font. */
835  /* Initialize the blend structure with `gvar' data. */
836  /* */
837  /* <Input> */
838  /* num_coords :: Must be the axis count of the font. */
839  /* */
840  /* coords :: An array of num_coords, each between [-1,1]. */
841  /* */
842  /* <Return> */
843  /* FreeType error code. 0 means success. */
844  /* */
846  TT_Set_MM_Blend( TT_Face face,
847  FT_UInt num_coords,
848  FT_Fixed* coords )
849  {
850  FT_Error error = FT_Err_Ok;
851  GX_Blend blend;
852  FT_MM_Var* mmvar;
853  FT_UInt i;
854  FT_Memory memory = face->root.memory;
855 
856  enum
857  {
858  mcvt_retain,
859  mcvt_modify,
860  mcvt_load
861 
862  } manageCvt;
863 
864 
865  face->doblend = FALSE;
866 
867  if ( face->blend == NULL )
868  {
869  if ( (error = TT_Get_MM_Var( face, NULL)) != 0 )
870  goto Exit;
871  }
872 
873  blend = face->blend;
874  mmvar = blend->mmvar;
875 
876  if ( num_coords != mmvar->num_axis )
877  {
878  error = FT_THROW( Invalid_Argument );
879  goto Exit;
880  }
881 
882  for ( i = 0; i < num_coords; ++i )
883  if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L )
884  {
885  error = FT_THROW( Invalid_Argument );
886  goto Exit;
887  }
888 
889  if ( blend->glyphoffsets == NULL )
890  if ( (error = ft_var_load_gvar( face )) != 0 )
891  goto Exit;
892 
893  if ( blend->normalizedcoords == NULL )
894  {
895  if ( FT_NEW_ARRAY( blend->normalizedcoords, num_coords ) )
896  goto Exit;
897 
898  manageCvt = mcvt_modify;
899 
900  /* If we have not set the blend coordinates before this, then the */
901  /* cvt table will still be what we read from the `cvt ' table and */
902  /* we don't need to reload it. We may need to change it though... */
903  }
904  else
905  {
906  manageCvt = mcvt_retain;
907  for ( i = 0; i < num_coords; ++i )
908  {
909  if ( blend->normalizedcoords[i] != coords[i] )
910  {
911  manageCvt = mcvt_load;
912  break;
913  }
914  }
915 
916  /* If we don't change the blend coords then we don't need to do */
917  /* anything to the cvt table. It will be correct. Otherwise we */
918  /* no longer have the original cvt (it was modified when we set */
919  /* the blend last time), so we must reload and then modify it. */
920  }
921 
922  blend->num_axis = num_coords;
923  FT_MEM_COPY( blend->normalizedcoords,
924  coords,
925  num_coords * sizeof ( FT_Fixed ) );
926 
927  face->doblend = TRUE;
928 
929  if ( face->cvt != NULL )
930  {
931  switch ( manageCvt )
932  {
933  case mcvt_load:
934  /* The cvt table has been loaded already; every time we change the */
935  /* blend we may need to reload and remodify the cvt table. */
936  FT_FREE( face->cvt );
937  face->cvt = NULL;
938 
939  tt_face_load_cvt( face, face->root.stream );
940  break;
941 
942  case mcvt_modify:
943  /* The original cvt table is in memory. All we need to do is */
944  /* apply the `cvar' table (if any). */
945  tt_face_vary_cvt( face, face->root.stream );
946  break;
947 
948  case mcvt_retain:
949  /* The cvt table is correct for this set of coordinates. */
950  break;
951  }
952  }
953 
954  Exit:
955  return error;
956  }
957 
958 
959  /*************************************************************************/
960  /* */
961  /* <Function> */
962  /* TT_Set_Var_Design */
963  /* */
964  /* <Description> */
965  /* Set the coordinates for the instance, measured in the user */
966  /* coordinate system. Parse the `avar' table (if present) to convert */
967  /* from user to normalized coordinates. */
968  /* */
969  /* <InOut> */
970  /* face :: The font face. */
971  /* Initialize the blend struct with `gvar' data. */
972  /* */
973  /* <Input> */
974  /* num_coords :: This must be the axis count of the font. */
975  /* */
976  /* coords :: A coordinate array with `num_coords' elements. */
977  /* */
978  /* <Return> */
979  /* FreeType error code. 0 means success. */
980  /* */
983  FT_UInt num_coords,
984  FT_Fixed* coords )
985  {
986  FT_Error error = FT_Err_Ok;
988  GX_Blend blend;
989  FT_MM_Var* mmvar;
990  FT_UInt i, j;
991  FT_Var_Axis* a;
992  GX_AVarSegment av;
993  FT_Memory memory = face->root.memory;
994 
995 
996  if ( face->blend == NULL )
997  {
998  if ( (error = TT_Get_MM_Var( face, NULL )) != 0 )
999  goto Exit;
1000  }
1001 
1002  blend = face->blend;
1003  mmvar = blend->mmvar;
1004 
1005  if ( num_coords != mmvar->num_axis )
1006  {
1007  error = FT_THROW( Invalid_Argument );
1008  goto Exit;
1009  }
1010 
1011  /* Axis normalization is a two stage process. First we normalize */
1012  /* based on the [min,def,max] values for the axis to be [-1,0,1]. */
1013  /* Then, if there's an `avar' table, we renormalize this range. */
1014 
1015  if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) )
1016  goto Exit;
1017 
1018  a = mmvar->axis;
1019  for ( i = 0; i < mmvar->num_axis; ++i, ++a )
1020  {
1021  if ( coords[i] > a->maximum || coords[i] < a->minimum )
1022  {
1023  error = FT_THROW( Invalid_Argument );
1024  goto Exit;
1025  }
1026 
1027  if ( coords[i] < a->def )
1028  normalized[i] = -FT_DivFix( coords[i] - a->def, a->minimum - a->def );
1029  else if ( a->maximum == a->def )
1030  normalized[i] = 0;
1031  else
1032  normalized[i] = FT_DivFix( coords[i] - a->def, a->maximum - a->def );
1033  }
1034 
1035  if ( !blend->avar_checked )
1036  ft_var_load_avar( face );
1037 
1038  if ( blend->avar_segment != NULL )
1039  {
1040  av = blend->avar_segment;
1041  for ( i = 0; i < mmvar->num_axis; ++i, ++av )
1042  {
1043  for ( j = 1; j < (FT_UInt)av->pairCount; ++j )
1044  if ( normalized[i] < av->correspondence[j].fromCoord )
1045  {
1046  normalized[i] =
1047  FT_MulDiv( normalized[i] - av->correspondence[j - 1].fromCoord,
1048  av->correspondence[j].toCoord -
1049  av->correspondence[j - 1].toCoord,
1050  av->correspondence[j].fromCoord -
1051  av->correspondence[j - 1].fromCoord ) +
1052  av->correspondence[j - 1].toCoord;
1053  break;
1054  }
1055  }
1056  }
1057 
1058  error = TT_Set_MM_Blend( face, num_coords, normalized );
1059 
1060  Exit:
1061  FT_FREE( normalized );
1062  return error;
1063  }
1064 
1065 
1066  /*************************************************************************/
1067  /*************************************************************************/
1068  /***** *****/
1069  /***** GX VAR PARSING ROUTINES *****/
1070  /***** *****/
1071  /*************************************************************************/
1072  /*************************************************************************/
1073 
1074 
1075  /*************************************************************************/
1076  /* */
1077  /* <Function> */
1078  /* tt_face_vary_cvt */
1079  /* */
1080  /* <Description> */
1081  /* Modify the loaded cvt table according to the `cvar' table and the */
1082  /* font's blend. */
1083  /* */
1084  /* <InOut> */
1085  /* face :: A handle to the target face object. */
1086  /* */
1087  /* <Input> */
1088  /* stream :: A handle to the input stream. */
1089  /* */
1090  /* <Return> */
1091  /* FreeType error code. 0 means success. */
1092  /* */
1093  /* Most errors are ignored. It is perfectly valid not to have a */
1094  /* `cvar' table even if there is a `gvar' and `fvar' table. */
1095  /* */
1097  tt_face_vary_cvt( TT_Face face,
1098  FT_Stream stream )
1099  {
1100  FT_Error error;
1101  FT_Memory memory = stream->memory;
1102  FT_ULong table_start;
1103  FT_ULong table_len;
1104  FT_UInt tupleCount;
1105  FT_ULong offsetToData;
1106  FT_ULong here;
1107  FT_UInt i, j;
1108  FT_Fixed* tuple_coords = NULL;
1109  FT_Fixed* im_start_coords = NULL;
1110  FT_Fixed* im_end_coords = NULL;
1111  GX_Blend blend = face->blend;
1112  FT_UInt point_count;
1113  FT_UShort* localpoints;
1114  FT_Short* deltas;
1115 
1116 
1117  FT_TRACE2(( "CVAR " ));
1118 
1119  if ( blend == NULL )
1120  {
1121  FT_TRACE2(( "tt_face_vary_cvt: no blend specified\n" ));
1122 
1123  error = FT_Err_Ok;
1124  goto Exit;
1125  }
1126 
1127  if ( face->cvt == NULL )
1128  {
1129  FT_TRACE2(( "tt_face_vary_cvt: no `cvt ' table\n" ));
1130 
1131  error = FT_Err_Ok;
1132  goto Exit;
1133  }
1134 
1135  error = face->goto_table( face, TTAG_cvar, stream, &table_len );
1136  if ( error )
1137  {
1138  FT_TRACE2(( "is missing\n" ));
1139 
1140  error = FT_Err_Ok;
1141  goto Exit;
1142  }
1143 
1144  if ( FT_FRAME_ENTER( table_len ) )
1145  {
1146  error = FT_Err_Ok;
1147  goto Exit;
1148  }
1149 
1150  table_start = FT_Stream_FTell( stream );
1151  if ( FT_GET_LONG() != 0x00010000L )
1152  {
1153  FT_TRACE2(( "bad table version\n" ));
1154 
1155  error = FT_Err_Ok;
1156  goto FExit;
1157  }
1158 
1159  if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) ||
1160  FT_NEW_ARRAY( im_start_coords, blend->num_axis ) ||
1161  FT_NEW_ARRAY( im_end_coords, blend->num_axis ) )
1162  goto FExit;
1163 
1164  tupleCount = FT_GET_USHORT();
1165  offsetToData = table_start + FT_GET_USHORT();
1166 
1167  /* The documentation implies there are flags packed into the */
1168  /* tuplecount, but John Jenkins says that shared points don't apply */
1169  /* to `cvar', and no other flags are defined. */
1170 
1171  for ( i = 0; i < ( tupleCount & 0xFFF ); ++i )
1172  {
1173  FT_UInt tupleDataSize;
1174  FT_UInt tupleIndex;
1175  FT_Fixed apply;
1176 
1177 
1178  tupleDataSize = FT_GET_USHORT();
1179  tupleIndex = FT_GET_USHORT();
1180 
1181  /* There is no provision here for a global tuple coordinate section, */
1182  /* so John says. There are no tuple indices, just embedded tuples. */
1183 
1184  if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
1185  {
1186  for ( j = 0; j < blend->num_axis; ++j )
1187  tuple_coords[j] = FT_GET_SHORT() << 2; /* convert from */
1188  /* short frac to fixed */
1189  }
1190  else
1191  {
1192  /* skip this tuple; it makes no sense */
1193 
1194  if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
1195  for ( j = 0; j < 2 * blend->num_axis; ++j )
1196  (void)FT_GET_SHORT();
1197 
1198  offsetToData += tupleDataSize;
1199  continue;
1200  }
1201 
1202  if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
1203  {
1204  for ( j = 0; j < blend->num_axis; ++j )
1205  im_start_coords[j] = FT_GET_SHORT() << 2;
1206  for ( j = 0; j < blend->num_axis; ++j )
1207  im_end_coords[j] = FT_GET_SHORT() << 2;
1208  }
1209 
1210  apply = ft_var_apply_tuple( blend,
1211  (FT_UShort)tupleIndex,
1212  tuple_coords,
1213  im_start_coords,
1214  im_end_coords );
1215  if ( /* tuple isn't active for our blend */
1216  apply == 0 ||
1217  /* global points not allowed, */
1218  /* if they aren't local, makes no sense */
1219  !( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) )
1220  {
1221  offsetToData += tupleDataSize;
1222  continue;
1223  }
1224 
1225  here = FT_Stream_FTell( stream );
1226 
1227  FT_Stream_SeekSet( stream, offsetToData );
1228 
1229  localpoints = ft_var_readpackedpoints( stream, &point_count );
1230  deltas = ft_var_readpackeddeltas( stream,
1231  point_count == 0 ? face->cvt_size
1232  : point_count );
1233  if ( localpoints == NULL || deltas == NULL )
1234  /* failure, ignore it */;
1235 
1236  else if ( localpoints == ALL_POINTS )
1237  {
1238  /* this means that there are deltas for every entry in cvt */
1239  for ( j = 0; j < face->cvt_size; ++j )
1240  face->cvt[j] = (FT_Short)( face->cvt[j] +
1241  FT_MulFix( deltas[j], apply ) );
1242  }
1243 
1244  else
1245  {
1246  for ( j = 0; j < point_count; ++j )
1247  {
1248  int pindex = localpoints[j];
1249 
1250  face->cvt[pindex] = (FT_Short)( face->cvt[pindex] +
1251  FT_MulFix( deltas[j], apply ) );
1252  }
1253  }
1254 
1255  if ( localpoints != ALL_POINTS )
1256  FT_FREE( localpoints );
1257  FT_FREE( deltas );
1258 
1259  offsetToData += tupleDataSize;
1260 
1261  FT_Stream_SeekSet( stream, here );
1262  }
1263 
1264  FExit:
1265  FT_FRAME_EXIT();
1266 
1267  Exit:
1268  FT_FREE( tuple_coords );
1269  FT_FREE( im_start_coords );
1270  FT_FREE( im_end_coords );
1271 
1272  return error;
1273  }
1274 
1275 
1276  /*************************************************************************/
1277  /* */
1278  /* <Function> */
1279  /* TT_Vary_Get_Glyph_Deltas */
1280  /* */
1281  /* <Description> */
1282  /* Load the appropriate deltas for the current glyph. */
1283  /* */
1284  /* <Input> */
1285  /* face :: A handle to the target face object. */
1286  /* */
1287  /* glyph_index :: The index of the glyph being modified. */
1288  /* */
1289  /* n_points :: The number of the points in the glyph, including */
1290  /* phantom points. */
1291  /* */
1292  /* <Output> */
1293  /* deltas :: The array of points to change. */
1294  /* */
1295  /* <Return> */
1296  /* FreeType error code. 0 means success. */
1297  /* */
1300  FT_UInt glyph_index,
1301  FT_Vector* *deltas,
1302  FT_UInt n_points )
1303  {
1304  FT_Stream stream = face->root.stream;
1305  FT_Memory memory = stream->memory;
1306  GX_Blend blend = face->blend;
1307  FT_Vector* delta_xy = NULL;
1308 
1309  FT_Error error;
1310  FT_ULong glyph_start;
1311  FT_UInt tupleCount;
1312  FT_ULong offsetToData;
1313  FT_ULong here;
1314  FT_UInt i, j;
1315  FT_Fixed* tuple_coords = NULL;
1316  FT_Fixed* im_start_coords = NULL;
1317  FT_Fixed* im_end_coords = NULL;
1318  FT_UInt point_count, spoint_count = 0;
1319  FT_UShort* sharedpoints = NULL;
1320  FT_UShort* localpoints = NULL;
1321  FT_UShort* points;
1322  FT_Short *deltas_x, *deltas_y;
1323 
1324 
1325  if ( !face->doblend || blend == NULL )
1326  return FT_THROW( Invalid_Argument );
1327 
1328  /* to be freed by the caller */
1329  if ( FT_NEW_ARRAY( delta_xy, n_points ) )
1330  goto Exit;
1331  *deltas = delta_xy;
1332 
1333  if ( glyph_index >= blend->gv_glyphcnt ||
1334  blend->glyphoffsets[glyph_index] ==
1335  blend->glyphoffsets[glyph_index + 1] )
1336  return FT_Err_Ok; /* no variation data for this glyph */
1337 
1338  if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] ) ||
1339  FT_FRAME_ENTER( blend->glyphoffsets[glyph_index + 1] -
1340  blend->glyphoffsets[glyph_index] ) )
1341  goto Fail1;
1342 
1343  glyph_start = FT_Stream_FTell( stream );
1344 
1345  /* each set of glyph variation data is formatted similarly to `cvar' */
1346  /* (except we get shared points and global tuples) */
1347 
1348  if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) ||
1349  FT_NEW_ARRAY( im_start_coords, blend->num_axis ) ||
1350  FT_NEW_ARRAY( im_end_coords, blend->num_axis ) )
1351  goto Fail2;
1352 
1353  tupleCount = FT_GET_USHORT();
1354  offsetToData = glyph_start + FT_GET_USHORT();
1355 
1356  if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS )
1357  {
1358  here = FT_Stream_FTell( stream );
1359 
1360  FT_Stream_SeekSet( stream, offsetToData );
1361 
1362  sharedpoints = ft_var_readpackedpoints( stream, &spoint_count );
1363  offsetToData = FT_Stream_FTell( stream );
1364 
1365  FT_Stream_SeekSet( stream, here );
1366  }
1367 
1368  for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); ++i )
1369  {
1370  FT_UInt tupleDataSize;
1371  FT_UInt tupleIndex;
1372  FT_Fixed apply;
1373 
1374 
1375  tupleDataSize = FT_GET_USHORT();
1376  tupleIndex = FT_GET_USHORT();
1377 
1378  if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
1379  {
1380  for ( j = 0; j < blend->num_axis; ++j )
1381  tuple_coords[j] = FT_GET_SHORT() << 2; /* convert from */
1382  /* short frac to fixed */
1383  }
1384  else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount )
1385  {
1386  error = FT_THROW( Invalid_Table );
1387  goto Fail3;
1388  }
1389  else
1390  {
1391  FT_MEM_COPY(
1392  tuple_coords,
1393  &blend->tuplecoords[(tupleIndex & 0xFFF) * blend->num_axis],
1394  blend->num_axis * sizeof ( FT_Fixed ) );
1395  }
1396 
1397  if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
1398  {
1399  for ( j = 0; j < blend->num_axis; ++j )
1400  im_start_coords[j] = FT_GET_SHORT() << 2;
1401  for ( j = 0; j < blend->num_axis; ++j )
1402  im_end_coords[j] = FT_GET_SHORT() << 2;
1403  }
1404 
1405  apply = ft_var_apply_tuple( blend,
1406  (FT_UShort)tupleIndex,
1407  tuple_coords,
1408  im_start_coords,
1409  im_end_coords );
1410 
1411  if ( apply == 0 ) /* tuple isn't active for our blend */
1412  {
1413  offsetToData += tupleDataSize;
1414  continue;
1415  }
1416 
1417  here = FT_Stream_FTell( stream );
1418 
1419  if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS )
1420  {
1421  FT_Stream_SeekSet( stream, offsetToData );
1422 
1423  localpoints = ft_var_readpackedpoints( stream, &point_count );
1424  points = localpoints;
1425  }
1426  else
1427  {
1428  points = sharedpoints;
1429  point_count = spoint_count;
1430  }
1431 
1432  deltas_x = ft_var_readpackeddeltas( stream,
1433  point_count == 0 ? n_points
1434  : point_count );
1435  deltas_y = ft_var_readpackeddeltas( stream,
1436  point_count == 0 ? n_points
1437  : point_count );
1438 
1439  if ( points == NULL || deltas_y == NULL || deltas_x == NULL )
1440  ; /* failure, ignore it */
1441 
1442  else if ( points == ALL_POINTS )
1443  {
1444  /* this means that there are deltas for every point in the glyph */
1445  for ( j = 0; j < n_points; ++j )
1446  {
1447  delta_xy[j].x += FT_MulFix( deltas_x[j], apply );
1448  delta_xy[j].y += FT_MulFix( deltas_y[j], apply );
1449  }
1450  }
1451 
1452  else
1453  {
1454  for ( j = 0; j < point_count; ++j )
1455  {
1456  if ( localpoints[j] >= n_points )
1457  continue;
1458 
1459  delta_xy[localpoints[j]].x += FT_MulFix( deltas_x[j], apply );
1460  delta_xy[localpoints[j]].y += FT_MulFix( deltas_y[j], apply );
1461  }
1462  }
1463 
1464  if ( localpoints != ALL_POINTS )
1465  FT_FREE( localpoints );
1466  FT_FREE( deltas_x );
1467  FT_FREE( deltas_y );
1468 
1469  offsetToData += tupleDataSize;
1470 
1471  FT_Stream_SeekSet( stream, here );
1472  }
1473 
1474  Fail3:
1475  FT_FREE( tuple_coords );
1476  FT_FREE( im_start_coords );
1477  FT_FREE( im_end_coords );
1478 
1479  Fail2:
1480  FT_FRAME_EXIT();
1481 
1482  Fail1:
1483  if ( error )
1484  {
1485  FT_FREE( delta_xy );
1486  *deltas = NULL;
1487  }
1488 
1489  Exit:
1490  return error;
1491  }
1492 
1493 
1494  /*************************************************************************/
1495  /* */
1496  /* <Function> */
1497  /* tt_done_blend */
1498  /* */
1499  /* <Description> */
1500  /* Frees the blend internal data structure. */
1501  /* */
1502  FT_LOCAL_DEF( void )
1503  tt_done_blend( FT_Memory memory,
1504  GX_Blend blend )
1505  {
1506  if ( blend != NULL )
1507  {
1508  FT_UInt i;
1509 
1510 
1511  FT_FREE( blend->normalizedcoords );
1512  FT_FREE( blend->mmvar );
1513 
1514  if ( blend->avar_segment != NULL )
1515  {
1516  for ( i = 0; i < blend->num_axis; ++i )
1517  FT_FREE( blend->avar_segment[i].correspondence );
1518  FT_FREE( blend->avar_segment );
1519  }
1520 
1521  FT_FREE( blend->tuplecoords );
1522  FT_FREE( blend->glyphoffsets );
1523  FT_FREE( blend );
1524  }
1525  }
1526 
1527 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
1528 
1529 
1530 /* 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:287
FT_DivFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:586
GLuint GLuint stream
#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
GLboolean GLboolean GLboolean GLboolean a
GLsizei const GLfloat * points
#define NULL
Definition: ftobjs.h:61
signed int FT_Int
Definition: fttypes.h:216
#define TTAG_slnt
Definition: ttgxvar.h:141
FT_UInt num_namedstyles
Definition: ftmm.h:214
sizeof(AF_ModuleRec)
#define TTAG_opsz
Definition: ttgxvar.h:140
return FT_THROW(Missing_Property)
#define FT_GET_CHAR()
Definition: ftstream.h:286
#define TTAG_gvar
Definition: tttags.h:61
#define FT_UNUSED(arg)
Definition: ftconfig.h:76
FT_Short * cvt
Definition: tttypes.h:1357
FT_Fixed minimum
Definition: ftmm.h:144
return FT_Err_Ok
Definition: ftbbox.c:645
typedef void(APIENTRY *GLDEBUGPROCARB)(GLenum source
TT_Loader_GotoTableFunc goto_table
Definition: tttypes.h:1288
FT_Fixed maximum
Definition: ftmm.h:146
png_uint_32 i
Definition: png.h:2640
#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
GLenum GLuint GLint GLenum face
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:506
struct FT_MM_Var_ FT_MM_Var
FT_Memory memory
Definition: ftsystem.h:332
#define FT_GET_USHORT()
Definition: ftstream.h:289
#define FT_FREE(ptr)
Definition: ftmemory.h:286
#define FT_FRAME_END
Definition: ftstream.h:118
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
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:412
FT_Error error
Definition: cffdrivr.c:411
FT_UShort pairCount
Definition: ttgxvar.h:58
FT_Pos x
Definition: ftimage.h:77
char FT_String
Definition: fttypes.h:183
GLbitfield flags
FT_Pos y
Definition: ftimage.h:78
FT_ULong cvt_size
Definition: tttypes.h:1356
GLdouble n
#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)
int const char * version
Definition: zlib.h:813
const GLint * first
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
FT_FaceRec root
Definition: tttypes.h:1260
#define FT_FRAME_EXIT()
Definition: ftstream.h:514
#define FT_NEW_ARRAY(ptr, count)
Definition: ftmemory.h:290
#define FT_STREAM_SEEK(position)
Definition: ftstream.h:489
FT_MulFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:485
#define FT_STREAM_POS()
Definition: ftstream.h:486
signed long FT_Fixed
Definition: fttypes.h:284
#define FT_FRAME_ULONG(f)
Definition: ftstream.h:121
unsigned int FT_UInt
Definition: fttypes.h:227
#define FT_GET_SHORT()
Definition: ftstream.h:288
#define FT_GET_ULONG()
Definition: ftstream.h:293
#define FT_FRAME_ENTER(size)
Definition: ftstream.h:510
#define FT_NEW(ptr)
Definition: ftmemory.h:288
#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:292
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:564
FT_Stream stream
Definition: freetype.h:964
GLuint coords
#define TRUE
Definition: ftobjs.h:53
#define FT_FRAME_START(size)
Definition: ftstream.h:117
#define FT_LOCAL_DEF(x)
Definition: ftconfig.h:236
FT_Memory memory
Definition: freetype.h:963
size_t FT_Offset
Definition: fttypes.h:320
GLint GLenum GLboolean normalized