ttgxvar.c

Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  ttgxvar.c                                                              */
00004 /*                                                                         */
00005 /*    TrueType GX Font Variation loader                                    */
00006 /*                                                                         */
00007 /*  Copyright 2004, 2005, 2006, 2007, 2008, 2009 by                        */
00008 /*  David Turner, Robert Wilhelm, Werner Lemberg, and George Williams.     */
00009 /*                                                                         */
00010 /*  This file is part of the FreeType project, and may only be used,       */
00011 /*  modified, and distributed under the terms of the FreeType project      */
00012 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00013 /*  this file you indicate that you have read the license and              */
00014 /*  understand and accept it fully.                                        */
00015 /*                                                                         */
00016 /***************************************************************************/
00017 
00018 
00019   /*************************************************************************/
00020   /*                                                                       */
00021   /* Apple documents the `fvar', `gvar', `cvar', and `avar' tables at      */
00022   /*                                                                       */
00023   /*   http://developer.apple.com/fonts/TTRefMan/RM06/Chap6[fgca]var.html  */
00024   /*                                                                       */
00025   /* The documentation for `fvar' is inconsistent.  At one point it says   */
00026   /* that `countSizePairs' should be 3, at another point 2.  It should     */
00027   /* be 2.                                                                 */
00028   /*                                                                       */
00029   /* The documentation for `gvar' is not intelligible; `cvar' refers you   */
00030   /* to `gvar' and is thus also incomprehensible.                          */
00031   /*                                                                       */
00032   /* The documentation for `avar' appears correct, but Apple has no fonts  */
00033   /* with an `avar' table, so it is hard to test.                          */
00034   /*                                                                       */
00035   /* Many thanks to John Jenkins (at Apple) in figuring this out.          */
00036   /*                                                                       */
00037   /*                                                                       */
00038   /* Apple's `kern' table has some references to tuple indices, but as     */
00039   /* there is no indication where these indices are defined, nor how to    */
00040   /* interpolate the kerning values (different tuples have different       */
00041   /* classes) this issue is ignored.                                       */
00042   /*                                                                       */
00043   /*************************************************************************/
00044 
00045 
00046 #include <ft2build.h>
00047 #include FT_INTERNAL_DEBUG_H
00048 #include FT_CONFIG_CONFIG_H
00049 #include FT_INTERNAL_STREAM_H
00050 #include FT_INTERNAL_SFNT_H
00051 #include FT_TRUETYPE_TAGS_H
00052 #include FT_MULTIPLE_MASTERS_H
00053 
00054 #include "ttpload.h"
00055 #include "ttgxvar.h"
00056 
00057 #include "tterrors.h"
00058 
00059 
00060 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
00061 
00062 
00063 #define FT_Stream_FTell( stream )  \
00064           ( (stream)->cursor - (stream)->base )
00065 #define FT_Stream_SeekSet( stream, off ) \
00066               ( (stream)->cursor = (stream)->base+(off) )
00067 
00068 
00069   /*************************************************************************/
00070   /*                                                                       */
00071   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
00072   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
00073   /* messages during execution.                                            */
00074   /*                                                                       */
00075 #undef  FT_COMPONENT
00076 #define FT_COMPONENT  trace_ttgxvar
00077 
00078 
00079   /*************************************************************************/
00080   /*************************************************************************/
00081   /*****                                                               *****/
00082   /*****                       Internal Routines                       *****/
00083   /*****                                                               *****/
00084   /*************************************************************************/
00085   /*************************************************************************/
00086 
00087 
00088   /*************************************************************************/
00089   /*                                                                       */
00090   /* The macro ALL_POINTS is used in `ft_var_readpackedpoints'.  It        */
00091   /* indicates that there is a delta for every point without needing to    */
00092   /* enumerate all of them.                                                */
00093   /*                                                                       */
00094 #define ALL_POINTS  (FT_UShort*)( -1 )
00095 
00096 
00097 #define GX_PT_POINTS_ARE_WORDS      0x80
00098 #define GX_PT_POINT_RUN_COUNT_MASK  0x7F
00099 
00100 
00101   /*************************************************************************/
00102   /*                                                                       */
00103   /* <Function>                                                            */
00104   /*    ft_var_readpackedpoints                                            */
00105   /*                                                                       */
00106   /* <Description>                                                         */
00107   /*    Read a set of points to which the following deltas will apply.     */
00108   /*    Points are packed with a run length encoding.                      */
00109   /*                                                                       */
00110   /* <Input>                                                               */
00111   /*    stream    :: The data stream.                                      */
00112   /*                                                                       */
00113   /* <Output>                                                              */
00114   /*    point_cnt :: The number of points read.  A zero value means that   */
00115   /*                 all points in the glyph will be affected, without     */
00116   /*                 enumerating them individually.                        */
00117   /*                                                                       */
00118   /* <Return>                                                              */
00119   /*    An array of FT_UShort containing the affected points or the        */
00120   /*    special value ALL_POINTS.                                          */
00121   /*                                                                       */
00122   static FT_UShort*
00123   ft_var_readpackedpoints( FT_Stream  stream,
00124                            FT_UInt   *point_cnt )
00125   {
00126     FT_UShort *points;
00127     FT_Int     n;
00128     FT_Int     runcnt;
00129     FT_Int     i;
00130     FT_Int     j;
00131     FT_Int     first;
00132     FT_Memory  memory = stream->memory;
00133     FT_Error   error = TT_Err_Ok;
00134 
00135     FT_UNUSED( error );
00136 
00137 
00138     *point_cnt = n = FT_GET_BYTE();
00139     if ( n == 0 )
00140       return ALL_POINTS;
00141 
00142     if ( n & GX_PT_POINTS_ARE_WORDS )
00143       n = FT_GET_BYTE() | ( ( n & GX_PT_POINT_RUN_COUNT_MASK ) << 8 );
00144 
00145     if ( FT_NEW_ARRAY( points, n ) )
00146       return NULL;
00147 
00148     i = 0;
00149     while ( i < n )
00150     {
00151       runcnt = FT_GET_BYTE();
00152       if ( runcnt & GX_PT_POINTS_ARE_WORDS )
00153       {
00154         runcnt = runcnt & GX_PT_POINT_RUN_COUNT_MASK;
00155         first  = points[i++] = FT_GET_USHORT();
00156 
00157         if ( runcnt < 1 )
00158           goto Exit;
00159 
00160         /* first point not included in runcount */
00161         for ( j = 0; j < runcnt; ++j )
00162           points[i++] = (FT_UShort)( first += FT_GET_USHORT() );
00163       }
00164       else
00165       {
00166         first = points[i++] = FT_GET_BYTE();
00167 
00168         if ( runcnt < 1 )
00169           goto Exit;
00170 
00171         for ( j = 0; j < runcnt; ++j )
00172           points[i++] = (FT_UShort)( first += FT_GET_BYTE() );
00173       }
00174     }
00175 
00176   Exit:
00177     return points;
00178   }
00179 
00180 
00181   enum
00182   {
00183     GX_DT_DELTAS_ARE_ZERO      = 0x80,
00184     GX_DT_DELTAS_ARE_WORDS     = 0x40,
00185     GX_DT_DELTA_RUN_COUNT_MASK = 0x3F
00186   };
00187 
00188 
00189   /*************************************************************************/
00190   /*                                                                       */
00191   /* <Function>                                                            */
00192   /*    ft_var_readpackeddeltas                                            */
00193   /*                                                                       */
00194   /* <Description>                                                         */
00195   /*    Read a set of deltas.  These are packed slightly differently than  */
00196   /*    points.  In particular there is no overall count.                  */
00197   /*                                                                       */
00198   /* <Input>                                                               */
00199   /*    stream    :: The data stream.                                      */
00200   /*                                                                       */
00201   /*    delta_cnt :: The number of to be read.                             */
00202   /*                                                                       */
00203   /* <Return>                                                              */
00204   /*    An array of FT_Short containing the deltas for the affected        */
00205   /*    points.  (This only gets the deltas for one dimension.  It will    */
00206   /*    generally be called twice, once for x, once for y.  When used in   */
00207   /*    cvt table, it will only be called once.)                           */
00208   /*                                                                       */
00209   static FT_Short*
00210   ft_var_readpackeddeltas( FT_Stream  stream,
00211                            FT_Offset  delta_cnt )
00212   {
00213     FT_Short  *deltas;
00214     FT_UInt    runcnt;
00215     FT_Offset  i;
00216     FT_UInt    j;
00217     FT_Memory  memory = stream->memory;
00218     FT_Error   error = TT_Err_Ok;
00219 
00220     FT_UNUSED( error );
00221 
00222 
00223     if ( FT_NEW_ARRAY( deltas, delta_cnt ) )
00224       return NULL;
00225 
00226     i = 0;
00227     while ( i < delta_cnt )
00228     {
00229       runcnt = FT_GET_BYTE();
00230       if ( runcnt & GX_DT_DELTAS_ARE_ZERO )
00231       {
00232         /* runcnt zeroes get added */
00233         for ( j = 0;
00234               j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt;
00235               ++j )
00236           deltas[i++] = 0;
00237       }
00238       else if ( runcnt & GX_DT_DELTAS_ARE_WORDS )
00239       {
00240         /* runcnt shorts from the stack */
00241         for ( j = 0;
00242               j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt;
00243               ++j )
00244           deltas[i++] = FT_GET_SHORT();
00245       }
00246       else
00247       {
00248         /* runcnt signed bytes from the stack */
00249         for ( j = 0;
00250               j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt;
00251               ++j )
00252           deltas[i++] = FT_GET_CHAR();
00253       }
00254 
00255       if ( j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) )
00256       {
00257         /* Bad format */
00258         FT_FREE( deltas );
00259         return NULL;
00260       }
00261     }
00262 
00263     return deltas;
00264   }
00265 
00266 
00267   /*************************************************************************/
00268   /*                                                                       */
00269   /* <Function>                                                            */
00270   /*    ft_var_load_avar                                                   */
00271   /*                                                                       */
00272   /* <Description>                                                         */
00273   /*    Parse the `avar' table if present.  It need not be, so we return   */
00274   /*    nothing.                                                           */
00275   /*                                                                       */
00276   /* <InOut>                                                               */
00277   /*    face :: The font face.                                             */
00278   /*                                                                       */
00279   static void
00280   ft_var_load_avar( TT_Face  face )
00281   {
00282     FT_Stream       stream = FT_FACE_STREAM(face);
00283     FT_Memory       memory = stream->memory;
00284     GX_Blend        blend  = face->blend;
00285     GX_AVarSegment  segment;
00286     FT_Error        error = TT_Err_Ok;
00287     FT_ULong        version;
00288     FT_Long         axisCount;
00289     FT_Int          i, j;
00290     FT_ULong        table_len;
00291 
00292     FT_UNUSED( error );
00293 
00294 
00295     blend->avar_checked = TRUE;
00296     if ( (error = face->goto_table( face, TTAG_avar, stream, &table_len )) != 0 )
00297       return;
00298 
00299     if ( FT_FRAME_ENTER( table_len ) )
00300       return;
00301 
00302     version   = FT_GET_LONG();
00303     axisCount = FT_GET_LONG();
00304 
00305     if ( version != 0x00010000L                       ||
00306          axisCount != (FT_Long)blend->mmvar->num_axis )
00307       goto Exit;
00308 
00309     if ( FT_NEW_ARRAY( blend->avar_segment, axisCount ) )
00310       goto Exit;
00311 
00312     segment = &blend->avar_segment[0];
00313     for ( i = 0; i < axisCount; ++i, ++segment )
00314     {
00315       segment->pairCount = FT_GET_USHORT();
00316       if ( FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) )
00317       {
00318         /* Failure.  Free everything we have done so far.  We must do */
00319         /* it right now since loading the `avar' table is optional.   */
00320 
00321         for ( j = i - 1; j >= 0; --j )
00322           FT_FREE( blend->avar_segment[j].correspondence );
00323 
00324         FT_FREE( blend->avar_segment );
00325         blend->avar_segment = NULL;
00326         goto Exit;
00327       }
00328 
00329       for ( j = 0; j < segment->pairCount; ++j )
00330       {
00331         segment->correspondence[j].fromCoord =
00332           FT_GET_SHORT() << 2;    /* convert to Fixed */
00333         segment->correspondence[j].toCoord =
00334           FT_GET_SHORT()<<2;    /* convert to Fixed */
00335       }
00336     }
00337 
00338   Exit:
00339     FT_FRAME_EXIT();
00340   }
00341 
00342 
00343   typedef struct  GX_GVar_Head_
00344   {
00345     FT_Long    version;
00346     FT_UShort  axisCount;
00347     FT_UShort  globalCoordCount;
00348     FT_ULong   offsetToCoord;
00349     FT_UShort  glyphCount;
00350     FT_UShort  flags;
00351     FT_ULong   offsetToData;
00352 
00353   } GX_GVar_Head;
00354 
00355 
00356   /*************************************************************************/
00357   /*                                                                       */
00358   /* <Function>                                                            */
00359   /*    ft_var_load_gvar                                                   */
00360   /*                                                                       */
00361   /* <Description>                                                         */
00362   /*    Parses the `gvar' table if present.  If `fvar' is there, `gvar'    */
00363   /*    had better be there too.                                           */
00364   /*                                                                       */
00365   /* <InOut>                                                               */
00366   /*    face :: The font face.                                             */
00367   /*                                                                       */
00368   /* <Return>                                                              */
00369   /*    FreeType error code.  0 means success.                             */
00370   /*                                                                       */
00371   static FT_Error
00372   ft_var_load_gvar( TT_Face  face )
00373   {
00374     FT_Stream     stream = FT_FACE_STREAM(face);
00375     FT_Memory     memory = stream->memory;
00376     GX_Blend      blend  = face->blend;
00377     FT_Error      error;
00378     FT_UInt       i, j;
00379     FT_ULong      table_len;
00380     FT_ULong      gvar_start;
00381     FT_ULong      offsetToData;
00382     GX_GVar_Head  gvar_head;
00383 
00384     static const FT_Frame_Field  gvar_fields[] =
00385     {
00386 
00387 #undef  FT_STRUCTURE
00388 #define FT_STRUCTURE  GX_GVar_Head
00389 
00390       FT_FRAME_START( 20 ),
00391         FT_FRAME_LONG  ( version ),
00392         FT_FRAME_USHORT( axisCount ),
00393         FT_FRAME_USHORT( globalCoordCount ),
00394         FT_FRAME_ULONG ( offsetToCoord ),
00395         FT_FRAME_USHORT( glyphCount ),
00396         FT_FRAME_USHORT( flags ),
00397         FT_FRAME_ULONG ( offsetToData ),
00398       FT_FRAME_END
00399     };
00400 
00401     if ( (error = face->goto_table( face, TTAG_gvar, stream, &table_len )) != 0 )
00402       goto Exit;
00403 
00404     gvar_start = FT_STREAM_POS( );
00405     if ( FT_STREAM_READ_FIELDS( gvar_fields, &gvar_head ) )
00406       goto Exit;
00407 
00408     blend->tuplecount  = gvar_head.globalCoordCount;
00409     blend->gv_glyphcnt = gvar_head.glyphCount;
00410     offsetToData       = gvar_start + gvar_head.offsetToData;
00411 
00412     if ( gvar_head.version   != (FT_Long)0x00010000L              ||
00413          gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis )
00414     {
00415       error = TT_Err_Invalid_Table;
00416       goto Exit;
00417     }
00418 
00419     if ( FT_NEW_ARRAY( blend->glyphoffsets, blend->gv_glyphcnt + 1 ) )
00420       goto Exit;
00421 
00422     if ( gvar_head.flags & 1 )
00423     {
00424       /* long offsets (one more offset than glyphs, to mark size of last) */
00425       if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 4L ) )
00426         goto Exit;
00427 
00428       for ( i = 0; i <= blend->gv_glyphcnt; ++i )
00429         blend->glyphoffsets[i] = offsetToData + FT_GET_LONG();
00430 
00431       FT_FRAME_EXIT();
00432     }
00433     else
00434     {
00435       /* short offsets (one more offset than glyphs, to mark size of last) */
00436       if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 2L ) )
00437         goto Exit;
00438 
00439       for ( i = 0; i <= blend->gv_glyphcnt; ++i )
00440         blend->glyphoffsets[i] = offsetToData + FT_GET_USHORT() * 2;
00441                                               /* XXX: Undocumented: `*2'! */
00442 
00443       FT_FRAME_EXIT();
00444     }
00445 
00446     if ( blend->tuplecount != 0 )
00447     {
00448       if ( FT_NEW_ARRAY( blend->tuplecoords,
00449                          gvar_head.axisCount * blend->tuplecount ) )
00450         goto Exit;
00451 
00452       if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord )       ||
00453            FT_FRAME_ENTER( blend->tuplecount * gvar_head.axisCount * 2L )                   )
00454         goto Exit;
00455 
00456       for ( i = 0; i < blend->tuplecount; ++i )
00457         for ( j = 0 ; j < (FT_UInt)gvar_head.axisCount; ++j )
00458           blend->tuplecoords[i * gvar_head.axisCount + j] =
00459             FT_GET_SHORT() << 2;                /* convert to FT_Fixed */
00460 
00461       FT_FRAME_EXIT();
00462     }
00463 
00464   Exit:
00465     return error;
00466   }
00467 
00468 
00469   /*************************************************************************/
00470   /*                                                                       */
00471   /* <Function>                                                            */
00472   /*    ft_var_apply_tuple                                                 */
00473   /*                                                                       */
00474   /* <Description>                                                         */
00475   /*    Figure out whether a given tuple (design) applies to the current   */
00476   /*    blend, and if so, what is the scaling factor.                      */
00477   /*                                                                       */
00478   /* <Input>                                                               */
00479   /*    blend           :: The current blend of the font.                  */
00480   /*                                                                       */
00481   /*    tupleIndex      :: A flag saying whether this is an intermediate   */
00482   /*                       tuple or not.                                   */
00483   /*                                                                       */
00484   /*    tuple_coords    :: The coordinates of the tuple in normalized axis */
00485   /*                       units.                                          */
00486   /*                                                                       */
00487   /*    im_start_coords :: The initial coordinates where this tuple starts */
00488   /*                       to apply (for intermediate coordinates).        */
00489   /*                                                                       */
00490   /*    im_end_coords   :: The final coordinates after which this tuple no */
00491   /*                       longer applies (for intermediate coordinates).  */
00492   /*                                                                       */
00493   /* <Return>                                                              */
00494   /*    An FT_Fixed value containing the scaling factor.                   */
00495   /*                                                                       */
00496   static FT_Fixed
00497   ft_var_apply_tuple( GX_Blend   blend,
00498                       FT_UShort  tupleIndex,
00499                       FT_Fixed*  tuple_coords,
00500                       FT_Fixed*  im_start_coords,
00501                       FT_Fixed*  im_end_coords )
00502   {
00503     FT_UInt   i;
00504     FT_Fixed  apply;
00505     FT_Fixed  temp;
00506 
00507 
00508     apply = 0x10000L;
00509     for ( i = 0; i < blend->num_axis; ++i )
00510     {
00511       if ( tuple_coords[i] == 0 )
00512         /* It's not clear why (for intermediate tuples) we don't need     */
00513         /* to check against start/end -- the documentation says we don't. */
00514         /* Similarly, it's unclear why we don't need to scale along the   */
00515         /* axis.                                                          */
00516         continue;
00517 
00518       else if ( blend->normalizedcoords[i] == 0                           ||
00519                 ( blend->normalizedcoords[i] < 0 && tuple_coords[i] > 0 ) ||
00520                 ( blend->normalizedcoords[i] > 0 && tuple_coords[i] < 0 ) )
00521       {
00522         apply = 0;
00523         break;
00524       }
00525 
00526       else if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) )
00527         /* not an intermediate tuple */
00528         apply = FT_MulDiv( apply,
00529                            blend->normalizedcoords[i] > 0
00530                              ? blend->normalizedcoords[i]
00531                              : -blend->normalizedcoords[i],
00532                            0x10000L );
00533 
00534       else if ( blend->normalizedcoords[i] <= im_start_coords[i] ||
00535                 blend->normalizedcoords[i] >= im_end_coords[i]   )
00536       {
00537         apply = 0;
00538         break;
00539       }
00540 
00541       else if ( blend->normalizedcoords[i] < tuple_coords[i] )
00542       {
00543         temp = FT_MulDiv( blend->normalizedcoords[i] - im_start_coords[i],
00544                           0x10000L,
00545                           tuple_coords[i] - im_start_coords[i]);
00546         apply = FT_MulDiv( apply, temp, 0x10000L );
00547       }
00548 
00549       else
00550       {
00551         temp = FT_MulDiv( im_end_coords[i] - blend->normalizedcoords[i],
00552                           0x10000L,
00553                           im_end_coords[i] - tuple_coords[i] );
00554         apply = FT_MulDiv( apply, temp, 0x10000L );
00555       }
00556     }
00557 
00558     return apply;
00559   }
00560 
00561 
00562   /*************************************************************************/
00563   /*************************************************************************/
00564   /*****                                                               *****/
00565   /*****               MULTIPLE MASTERS SERVICE FUNCTIONS              *****/
00566   /*****                                                               *****/
00567   /*************************************************************************/
00568   /*************************************************************************/
00569 
00570 
00571   typedef struct  GX_FVar_Head_
00572   {
00573     FT_Long    version;
00574     FT_UShort  offsetToData;
00575     FT_UShort  countSizePairs;
00576     FT_UShort  axisCount;
00577     FT_UShort  axisSize;
00578     FT_UShort  instanceCount;
00579     FT_UShort  instanceSize;
00580 
00581   } GX_FVar_Head;
00582 
00583 
00584   typedef struct  fvar_axis_
00585   {
00586     FT_ULong   axisTag;
00587     FT_ULong   minValue;
00588     FT_ULong   defaultValue;
00589     FT_ULong   maxValue;
00590     FT_UShort  flags;
00591     FT_UShort  nameID;
00592 
00593   } GX_FVar_Axis;
00594 
00595 
00596   /*************************************************************************/
00597   /*                                                                       */
00598   /* <Function>                                                            */
00599   /*    TT_Get_MM_Var                                                      */
00600   /*                                                                       */
00601   /* <Description>                                                         */
00602   /*    Check that the font's `fvar' table is valid, parse it, and return  */
00603   /*    those data.                                                        */
00604   /*                                                                       */
00605   /* <InOut>                                                               */
00606   /*    face   :: The font face.                                           */
00607   /*              TT_Get_MM_Var initializes the blend structure.           */
00608   /*                                                                       */
00609   /* <Output>                                                              */
00610   /*    master :: The `fvar' data (must be freed by caller).               */
00611   /*                                                                       */
00612   /* <Return>                                                              */
00613   /*    FreeType error code.  0 means success.                             */
00614   /*                                                                       */
00615   FT_LOCAL_DEF( FT_Error )
00616   TT_Get_MM_Var( TT_Face      face,
00617                  FT_MM_Var*  *master )
00618   {
00619     FT_Stream            stream = face->root.stream;
00620     FT_Memory            memory = face->root.memory;
00621     FT_ULong             table_len;
00622     FT_Error             error  = TT_Err_Ok;
00623     FT_ULong             fvar_start;
00624     FT_Int               i, j;
00625     FT_MM_Var*           mmvar;
00626     FT_Fixed*            next_coords;
00627     FT_String*           next_name;
00628     FT_Var_Axis*         a;
00629     FT_Var_Named_Style*  ns;
00630     GX_FVar_Head         fvar_head;
00631 
00632     static const FT_Frame_Field  fvar_fields[] =
00633     {
00634 
00635 #undef  FT_STRUCTURE
00636 #define FT_STRUCTURE  GX_FVar_Head
00637 
00638       FT_FRAME_START( 16 ),
00639         FT_FRAME_LONG  ( version ),
00640         FT_FRAME_USHORT( offsetToData ),
00641         FT_FRAME_USHORT( countSizePairs ),
00642         FT_FRAME_USHORT( axisCount ),
00643         FT_FRAME_USHORT( axisSize ),
00644         FT_FRAME_USHORT( instanceCount ),
00645         FT_FRAME_USHORT( instanceSize ),
00646       FT_FRAME_END
00647     };
00648 
00649     static const FT_Frame_Field  fvaraxis_fields[] =
00650     {
00651 
00652 #undef  FT_STRUCTURE
00653 #define FT_STRUCTURE  GX_FVar_Axis
00654 
00655       FT_FRAME_START( 20 ),
00656         FT_FRAME_ULONG ( axisTag ),
00657         FT_FRAME_ULONG ( minValue ),
00658         FT_FRAME_ULONG ( defaultValue ),
00659         FT_FRAME_ULONG ( maxValue ),
00660         FT_FRAME_USHORT( flags ),
00661         FT_FRAME_USHORT( nameID ),
00662       FT_FRAME_END
00663     };
00664 
00665 
00666     if ( face->blend == NULL )
00667     {
00668       /* both `fvar' and `gvar' must be present */
00669       if ( (error = face->goto_table( face, TTAG_gvar,
00670                                       stream, &table_len )) != 0 )
00671         goto Exit;
00672 
00673       if ( (error = face->goto_table( face, TTAG_fvar,
00674                                       stream, &table_len )) != 0 )
00675         goto Exit;
00676 
00677       fvar_start = FT_STREAM_POS( );
00678 
00679       if ( FT_STREAM_READ_FIELDS( fvar_fields, &fvar_head ) )
00680         goto Exit;
00681 
00682       if ( fvar_head.version != (FT_Long)0x00010000L                      ||
00683            fvar_head.countSizePairs != 2                                  ||
00684            fvar_head.axisSize != 20                                       ||
00685            fvar_head.instanceSize != 4 + 4 * fvar_head.axisCount          ||
00686            fvar_head.offsetToData + fvar_head.axisCount * 20U +
00687              fvar_head.instanceCount * fvar_head.instanceSize > table_len )
00688       {
00689         error = TT_Err_Invalid_Table;
00690         goto Exit;
00691       }
00692 
00693       if ( FT_NEW( face->blend ) )
00694         goto Exit;
00695 
00696       /* XXX: TODO - check for overflows */
00697       face->blend->mmvar_len =
00698         sizeof ( FT_MM_Var ) +
00699         fvar_head.axisCount * sizeof ( FT_Var_Axis ) +
00700         fvar_head.instanceCount * sizeof ( FT_Var_Named_Style ) +
00701         fvar_head.instanceCount * fvar_head.axisCount * sizeof ( FT_Fixed ) +
00702         5 * fvar_head.axisCount;
00703 
00704       if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
00705         goto Exit;
00706       face->blend->mmvar = mmvar;
00707 
00708       mmvar->num_axis =
00709         fvar_head.axisCount;
00710       mmvar->num_designs =
00711         (FT_UInt)-1;           /* meaningless in this context; each glyph */
00712                                /* may have a different number of designs  */
00713                                /* (or tuples, as called by Apple)         */
00714       mmvar->num_namedstyles =
00715         fvar_head.instanceCount;
00716       mmvar->axis =
00717         (FT_Var_Axis*)&(mmvar[1]);
00718       mmvar->namedstyle =
00719         (FT_Var_Named_Style*)&(mmvar->axis[fvar_head.axisCount]);
00720 
00721       next_coords =
00722         (FT_Fixed*)&(mmvar->namedstyle[fvar_head.instanceCount]);
00723       for ( i = 0; i < fvar_head.instanceCount; ++i )
00724       {
00725         mmvar->namedstyle[i].coords  = next_coords;
00726         next_coords                 += fvar_head.axisCount;
00727       }
00728 
00729       next_name = (FT_String*)next_coords;
00730       for ( i = 0; i < fvar_head.axisCount; ++i )
00731       {
00732         mmvar->axis[i].name  = next_name;
00733         next_name           += 5;
00734       }
00735 
00736       if ( FT_STREAM_SEEK( fvar_start + fvar_head.offsetToData ) )
00737         goto Exit;
00738 
00739       a = mmvar->axis;
00740       for ( i = 0; i < fvar_head.axisCount; ++i )
00741       {
00742         GX_FVar_Axis  axis_rec;
00743 
00744 
00745         if ( FT_STREAM_READ_FIELDS( fvaraxis_fields, &axis_rec ) )
00746           goto Exit;
00747         a->tag     = axis_rec.axisTag;
00748         a->minimum = axis_rec.minValue;     /* A Fixed */
00749         a->def     = axis_rec.defaultValue; /* A Fixed */
00750         a->maximum = axis_rec.maxValue;     /* A Fixed */
00751         a->strid   = axis_rec.nameID;
00752 
00753         a->name[0] = (FT_String)(   a->tag >> 24 );
00754         a->name[1] = (FT_String)( ( a->tag >> 16 ) & 0xFF );
00755         a->name[2] = (FT_String)( ( a->tag >>  8 ) & 0xFF );
00756         a->name[3] = (FT_String)( ( a->tag       ) & 0xFF );
00757         a->name[4] = 0;
00758 
00759         ++a;
00760       }
00761 
00762       ns = mmvar->namedstyle;
00763       for ( i = 0; i < fvar_head.instanceCount; ++i, ++ns )
00764       {
00765         if ( FT_FRAME_ENTER( 4L + 4L * fvar_head.axisCount ) )
00766           goto Exit;
00767 
00768         ns->strid       =    FT_GET_USHORT();
00769         (void) /* flags = */ FT_GET_USHORT();
00770 
00771         for ( j = 0; j < fvar_head.axisCount; ++j )
00772           ns->coords[j] = FT_GET_ULONG();     /* A Fixed */
00773 
00774         FT_FRAME_EXIT();
00775       }
00776     }
00777 
00778     if ( master != NULL )
00779     {
00780       FT_UInt  n;
00781 
00782 
00783       if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
00784         goto Exit;
00785       FT_MEM_COPY( mmvar, face->blend->mmvar, face->blend->mmvar_len );
00786 
00787       mmvar->axis =
00788         (FT_Var_Axis*)&(mmvar[1]);
00789       mmvar->namedstyle =
00790         (FT_Var_Named_Style*)&(mmvar->axis[mmvar->num_axis]);
00791       next_coords =
00792         (FT_Fixed*)&(mmvar->namedstyle[mmvar->num_namedstyles]);
00793 
00794       for ( n = 0; n < mmvar->num_namedstyles; ++n )
00795       {
00796         mmvar->namedstyle[n].coords  = next_coords;
00797         next_coords                 += mmvar->num_axis;
00798       }
00799 
00800       a = mmvar->axis;
00801       next_name = (FT_String*)next_coords;
00802       for ( n = 0; n < mmvar->num_axis; ++n )
00803       {
00804         a->name = next_name;
00805 
00806         /* standard PostScript names for some standard apple tags */
00807         if ( a->tag == TTAG_wght )
00808           a->name = (char *)"Weight";
00809         else if ( a->tag == TTAG_wdth )
00810           a->name = (char *)"Width";
00811         else if ( a->tag == TTAG_opsz )
00812           a->name = (char *)"OpticalSize";
00813         else if ( a->tag == TTAG_slnt )
00814           a->name = (char *)"Slant";
00815 
00816         next_name += 5;
00817         ++a;
00818       }
00819 
00820       *master = mmvar;
00821     }
00822 
00823   Exit:
00824     return error;
00825   }
00826 
00827 
00828   /*************************************************************************/
00829   /*                                                                       */
00830   /* <Function>                                                            */
00831   /*    TT_Set_MM_Blend                                                    */
00832   /*                                                                       */
00833   /* <Description>                                                         */
00834   /*    Set the blend (normalized) coordinates for this instance of the    */
00835   /*    font.  Check that the `gvar' table is reasonable and does some     */
00836   /*    initial preparation.                                               */
00837   /*                                                                       */
00838   /* <InOut>                                                               */
00839   /*    face       :: The font.                                            */
00840   /*                  Initialize the blend structure with `gvar' data.     */
00841   /*                                                                       */
00842   /* <Input>                                                               */
00843   /*    num_coords :: Must be the axis count of the font.                  */
00844   /*                                                                       */
00845   /*    coords     :: An array of num_coords, each between [-1,1].         */
00846   /*                                                                       */
00847   /* <Return>                                                              */
00848   /*    FreeType error code.  0 means success.                             */
00849   /*                                                                       */
00850   FT_LOCAL_DEF( FT_Error )
00851   TT_Set_MM_Blend( TT_Face    face,
00852                    FT_UInt    num_coords,
00853                    FT_Fixed*  coords )
00854   {
00855     FT_Error    error = TT_Err_Ok;
00856     GX_Blend    blend;
00857     FT_MM_Var*  mmvar;
00858     FT_UInt     i;
00859     FT_Memory   memory = face->root.memory;
00860 
00861     enum
00862     {
00863       mcvt_retain,
00864       mcvt_modify,
00865       mcvt_load
00866 
00867     } manageCvt;
00868 
00869 
00870     face->doblend = FALSE;
00871 
00872     if ( face->blend == NULL )
00873     {
00874       if ( (error = TT_Get_MM_Var( face, NULL)) != 0 )
00875         goto Exit;
00876     }
00877 
00878     blend = face->blend;
00879     mmvar = blend->mmvar;
00880 
00881     if ( num_coords != mmvar->num_axis )
00882     {
00883       error = TT_Err_Invalid_Argument;
00884       goto Exit;
00885     }
00886 
00887     for ( i = 0; i < num_coords; ++i )
00888       if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L )
00889       {
00890         error = TT_Err_Invalid_Argument;
00891         goto Exit;
00892       }
00893 
00894     if ( blend->glyphoffsets == NULL )
00895       if ( (error = ft_var_load_gvar( face )) != 0 )
00896         goto Exit;
00897 
00898     if ( blend->normalizedcoords == NULL )
00899     {
00900       if ( FT_NEW_ARRAY( blend->normalizedcoords, num_coords ) )
00901         goto Exit;
00902 
00903       manageCvt = mcvt_modify;
00904 
00905       /* If we have not set the blend coordinates before this, then the  */
00906       /* cvt table will still be what we read from the `cvt ' table and  */
00907       /* we don't need to reload it.  We may need to change it though... */
00908     }
00909     else
00910     {
00911       manageCvt = mcvt_retain;
00912       for ( i = 0; i < num_coords; ++i )
00913       {
00914         if ( blend->normalizedcoords[i] != coords[i] )
00915         {
00916           manageCvt = mcvt_load;
00917           break;
00918         }
00919       }
00920 
00921       /* If we don't change the blend coords then we don't need to do  */
00922       /* anything to the cvt table.  It will be correct.  Otherwise we */
00923       /* no longer have the original cvt (it was modified when we set  */
00924       /* the blend last time), so we must reload and then modify it.   */
00925     }
00926 
00927     blend->num_axis = num_coords;
00928     FT_MEM_COPY( blend->normalizedcoords,
00929                  coords,
00930                  num_coords * sizeof ( FT_Fixed ) );
00931 
00932     face->doblend = TRUE;
00933 
00934     if ( face->cvt != NULL )
00935     {
00936       switch ( manageCvt )
00937       {
00938       case mcvt_load:
00939         /* The cvt table has been loaded already; every time we change the */
00940         /* blend we may need to reload and remodify the cvt table.         */
00941         FT_FREE( face->cvt );
00942         face->cvt = NULL;
00943 
00944         tt_face_load_cvt( face, face->root.stream );
00945         break;
00946 
00947       case mcvt_modify:
00948         /* The original cvt table is in memory.  All we need to do is */
00949         /* apply the `cvar' table (if any).                           */
00950         tt_face_vary_cvt( face, face->root.stream );
00951         break;
00952 
00953       case mcvt_retain:
00954         /* The cvt table is correct for this set of coordinates. */
00955         break;
00956       }
00957     }
00958 
00959   Exit:
00960     return error;
00961   }
00962 
00963 
00964   /*************************************************************************/
00965   /*                                                                       */
00966   /* <Function>                                                            */
00967   /*    TT_Set_Var_Design                                                  */
00968   /*                                                                       */
00969   /* <Description>                                                         */
00970   /*    Set the coordinates for the instance, measured in the user         */
00971   /*    coordinate system.  Parse the `avar' table (if present) to convert */
00972   /*    from user to normalized coordinates.                               */
00973   /*                                                                       */
00974   /* <InOut>                                                               */
00975   /*    face       :: The font face.                                       */
00976   /*                  Initialize the blend struct with `gvar' data.        */
00977   /*                                                                       */
00978   /* <Input>                                                               */
00979   /*    num_coords :: This must be the axis count of the font.             */
00980   /*                                                                       */
00981   /*    coords     :: A coordinate array with `num_coords' elements.       */
00982   /*                                                                       */
00983   /* <Return>                                                              */
00984   /*    FreeType error code.  0 means success.                             */
00985   /*                                                                       */
00986   FT_LOCAL_DEF( FT_Error )
00987   TT_Set_Var_Design( TT_Face    face,
00988                      FT_UInt    num_coords,
00989                      FT_Fixed*  coords )
00990   {
00991     FT_Error        error      = TT_Err_Ok;
00992     FT_Fixed*       normalized = NULL;
00993     GX_Blend        blend;
00994     FT_MM_Var*      mmvar;
00995     FT_UInt         i, j;
00996     FT_Var_Axis*    a;
00997     GX_AVarSegment  av;
00998     FT_Memory       memory = face->root.memory;
00999 
01000 
01001     if ( face->blend == NULL )
01002     {
01003       if ( (error = TT_Get_MM_Var( face, NULL )) != 0 )
01004         goto Exit;
01005     }
01006 
01007     blend = face->blend;
01008     mmvar = blend->mmvar;
01009 
01010     if ( num_coords != mmvar->num_axis )
01011     {
01012       error = TT_Err_Invalid_Argument;
01013       goto Exit;
01014     }
01015 
01016     /* Axis normalization is a two stage process.  First we normalize */
01017     /* based on the [min,def,max] values for the axis to be [-1,0,1]. */
01018     /* Then, if there's an `avar' table, we renormalize this range.   */
01019 
01020     if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) )
01021       goto Exit;
01022 
01023     a = mmvar->axis;
01024     for ( i = 0; i < mmvar->num_axis; ++i, ++a )
01025     {
01026       if ( coords[i] > a->maximum || coords[i] < a->minimum )
01027       {
01028         error = TT_Err_Invalid_Argument;
01029         goto Exit;
01030       }
01031 
01032       if ( coords[i] < a->def )
01033       {
01034         normalized[i] = -FT_MulDiv( coords[i] - a->def,
01035                                     0x10000L,
01036                                     a->minimum - a->def );
01037       }
01038       else if ( a->maximum == a->def )
01039         normalized[i] = 0;
01040       else
01041       {
01042         normalized[i] = FT_MulDiv( coords[i] - a->def,
01043                                    0x10000L,
01044                                    a->maximum - a->def );
01045       }
01046     }
01047 
01048     if ( !blend->avar_checked )
01049       ft_var_load_avar( face );
01050 
01051     if ( blend->avar_segment != NULL )
01052     {
01053       av = blend->avar_segment;
01054       for ( i = 0; i < mmvar->num_axis; ++i, ++av )
01055       {
01056         for ( j = 1; j < (FT_UInt)av->pairCount; ++j )
01057           if ( normalized[i] < av->correspondence[j].fromCoord )
01058           {
01059             normalized[i] =
01060               FT_MulDiv(
01061                 FT_MulDiv(
01062                   normalized[i] - av->correspondence[j - 1].fromCoord,
01063                   0x10000L,
01064                   av->correspondence[j].fromCoord -
01065                     av->correspondence[j - 1].fromCoord ),
01066                 av->correspondence[j].toCoord -
01067                   av->correspondence[j - 1].toCoord,
01068                 0x10000L ) +
01069               av->correspondence[j - 1].toCoord;
01070             break;
01071           }
01072       }
01073     }
01074 
01075     error = TT_Set_MM_Blend( face, num_coords, normalized );
01076 
01077   Exit:
01078     FT_FREE( normalized );
01079     return error;
01080   }
01081 
01082 
01083   /*************************************************************************/
01084   /*************************************************************************/
01085   /*****                                                               *****/
01086   /*****                     GX VAR PARSING ROUTINES                   *****/
01087   /*****                                                               *****/
01088   /*************************************************************************/
01089   /*************************************************************************/
01090 
01091 
01092   /*************************************************************************/
01093   /*                                                                       */
01094   /* <Function>                                                            */
01095   /*    tt_face_vary_cvt                                                   */
01096   /*                                                                       */
01097   /* <Description>                                                         */
01098   /*    Modify the loaded cvt table according to the `cvar' table and the  */
01099   /*    font's blend.                                                      */
01100   /*                                                                       */
01101   /* <InOut>                                                               */
01102   /*    face   :: A handle to the target face object.                      */
01103   /*                                                                       */
01104   /* <Input>                                                               */
01105   /*    stream :: A handle to the input stream.                            */
01106   /*                                                                       */
01107   /* <Return>                                                              */
01108   /*    FreeType error code.  0 means success.                             */
01109   /*                                                                       */
01110   /*    Most errors are ignored.  It is perfectly valid not to have a      */
01111   /*    `cvar' table even if there is a `gvar' and `fvar' table.           */
01112   /*                                                                       */
01113   FT_LOCAL_DEF( FT_Error )
01114   tt_face_vary_cvt( TT_Face    face,
01115                     FT_Stream  stream )
01116   {
01117     FT_Error    error;
01118     FT_Memory   memory = stream->memory;
01119     FT_ULong    table_start;
01120     FT_ULong    table_len;
01121     FT_UInt     tupleCount;
01122     FT_ULong    offsetToData;
01123     FT_ULong    here;
01124     FT_UInt     i, j;
01125     FT_Fixed*   tuple_coords    = NULL;
01126     FT_Fixed*   im_start_coords = NULL;
01127     FT_Fixed*   im_end_coords   = NULL;
01128     GX_Blend    blend           = face->blend;
01129     FT_UInt     point_count;
01130     FT_UShort*  localpoints;
01131     FT_Short*   deltas;
01132 
01133 
01134     FT_TRACE2(( "CVAR " ));
01135 
01136     if ( blend == NULL )
01137     {
01138       FT_TRACE2(( "tt_face_vary_cvt: no blend specified\n" ));
01139 
01140       error = TT_Err_Ok;
01141       goto Exit;
01142     }
01143 
01144     if ( face->cvt == NULL )
01145     {
01146       FT_TRACE2(( "tt_face_vary_cvt: no `cvt ' table\n" ));
01147 
01148       error = TT_Err_Ok;
01149       goto Exit;
01150     }
01151 
01152     error = face->goto_table( face, TTAG_cvar, stream, &table_len );
01153     if ( error )
01154     {
01155       FT_TRACE2(( "is missing\n" ));
01156 
01157       error = TT_Err_Ok;
01158       goto Exit;
01159     }
01160 
01161     if ( FT_FRAME_ENTER( table_len ) )
01162     {
01163       error = TT_Err_Ok;
01164       goto Exit;
01165     }
01166 
01167     table_start = FT_Stream_FTell( stream );
01168     if ( FT_GET_LONG() != 0x00010000L )
01169     {
01170       FT_TRACE2(( "bad table version\n" ));
01171 
01172       error = TT_Err_Ok;
01173       goto FExit;
01174     }
01175 
01176     if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis )    ||
01177          FT_NEW_ARRAY( im_start_coords, blend->num_axis ) ||
01178          FT_NEW_ARRAY( im_end_coords, blend->num_axis )   )
01179       goto FExit;
01180 
01181     tupleCount   = FT_GET_USHORT();
01182     offsetToData = table_start + FT_GET_USHORT();
01183 
01184     /* The documentation implies there are flags packed into the        */
01185     /* tuplecount, but John Jenkins says that shared points don't apply */
01186     /* to `cvar', and no other flags are defined.                       */
01187 
01188     for ( i = 0; i < ( tupleCount & 0xFFF ); ++i )
01189     {
01190       FT_UInt   tupleDataSize;
01191       FT_UInt   tupleIndex;
01192       FT_Fixed  apply;
01193 
01194 
01195       tupleDataSize = FT_GET_USHORT();
01196       tupleIndex    = FT_GET_USHORT();
01197 
01198       /* There is no provision here for a global tuple coordinate section, */
01199       /* so John says.  There are no tuple indices, just embedded tuples.  */
01200 
01201       if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
01202       {
01203         for ( j = 0; j < blend->num_axis; ++j )
01204           tuple_coords[j] = FT_GET_SHORT() << 2; /* convert from        */
01205                                                  /* short frac to fixed */
01206       }
01207       else
01208       {
01209         /* skip this tuple; it makes no sense */
01210 
01211         if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
01212           for ( j = 0; j < 2 * blend->num_axis; ++j )
01213             (void)FT_GET_SHORT();
01214 
01215         offsetToData += tupleDataSize;
01216         continue;
01217       }
01218 
01219       if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
01220       {
01221         for ( j = 0; j < blend->num_axis; ++j )
01222           im_start_coords[j] = FT_GET_SHORT() << 2;
01223         for ( j = 0; j < blend->num_axis; ++j )
01224           im_end_coords[j] = FT_GET_SHORT() << 2;
01225       }
01226 
01227       apply = ft_var_apply_tuple( blend,
01228                                   (FT_UShort)tupleIndex,
01229                                   tuple_coords,
01230                                   im_start_coords,
01231                                   im_end_coords );
01232       if ( /* tuple isn't active for our blend */
01233            apply == 0                                    ||
01234            /* global points not allowed,           */
01235            /* if they aren't local, makes no sense */
01236            !( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) )
01237       {
01238         offsetToData += tupleDataSize;
01239         continue;
01240       }
01241 
01242       here = FT_Stream_FTell( stream );
01243 
01244       FT_Stream_SeekSet( stream, offsetToData );
01245 
01246       localpoints = ft_var_readpackedpoints( stream, &point_count );
01247       deltas      = ft_var_readpackeddeltas( stream,
01248                                              point_count == 0 ? face->cvt_size
01249                                                               : point_count );
01250       if ( localpoints == NULL || deltas == NULL )
01251         /* failure, ignore it */;
01252 
01253       else if ( localpoints == ALL_POINTS )
01254       {
01255         /* this means that there are deltas for every entry in cvt */
01256         for ( j = 0; j < face->cvt_size; ++j )
01257           face->cvt[j] = (FT_Short)( face->cvt[j] +
01258                                      FT_MulFix( deltas[j], apply ) );
01259       }
01260 
01261       else
01262       {
01263         for ( j = 0; j < point_count; ++j )
01264         {
01265           int  pindex = localpoints[j];
01266 
01267           face->cvt[pindex] = (FT_Short)( face->cvt[pindex] +
01268                                           FT_MulFix( deltas[j], apply ) );
01269         }
01270       }
01271 
01272       if ( localpoints != ALL_POINTS )
01273         FT_FREE( localpoints );
01274       FT_FREE( deltas );
01275 
01276       offsetToData += tupleDataSize;
01277 
01278       FT_Stream_SeekSet( stream, here );
01279     }
01280 
01281   FExit:
01282     FT_FRAME_EXIT();
01283 
01284   Exit:
01285     FT_FREE( tuple_coords );
01286     FT_FREE( im_start_coords );
01287     FT_FREE( im_end_coords );
01288 
01289     return error;
01290   }
01291 
01292 
01293   /*************************************************************************/
01294   /*                                                                       */
01295   /* <Function>                                                            */
01296   /*    TT_Vary_Get_Glyph_Deltas                                           */
01297   /*                                                                       */
01298   /* <Description>                                                         */
01299   /*    Load the appropriate deltas for the current glyph.                 */
01300   /*                                                                       */
01301   /* <Input>                                                               */
01302   /*    face        :: A handle to the target face object.                 */
01303   /*                                                                       */
01304   /*    glyph_index :: The index of the glyph being modified.              */
01305   /*                                                                       */
01306   /*    n_points    :: The number of the points in the glyph, including    */
01307   /*                   phantom points.                                     */
01308   /*                                                                       */
01309   /* <Output>                                                              */
01310   /*    deltas      :: The array of points to change.                      */
01311   /*                                                                       */
01312   /* <Return>                                                              */
01313   /*    FreeType error code.  0 means success.                             */
01314   /*                                                                       */
01315   FT_LOCAL_DEF( FT_Error )
01316   TT_Vary_Get_Glyph_Deltas( TT_Face      face,
01317                             FT_UInt      glyph_index,
01318                             FT_Vector*  *deltas,
01319                             FT_UInt      n_points )
01320   {
01321     FT_Stream   stream = face->root.stream;
01322     FT_Memory   memory = stream->memory;
01323     GX_Blend    blend  = face->blend;
01324     FT_Vector*  delta_xy;
01325 
01326     FT_Error    error;
01327     FT_ULong    glyph_start;
01328     FT_UInt     tupleCount;
01329     FT_ULong    offsetToData;
01330     FT_ULong    here;
01331     FT_UInt     i, j;
01332     FT_Fixed*   tuple_coords    = NULL;
01333     FT_Fixed*   im_start_coords = NULL;
01334     FT_Fixed*   im_end_coords   = NULL;
01335     FT_UInt     point_count, spoint_count = 0;
01336     FT_UShort*  sharedpoints = NULL;
01337     FT_UShort*  localpoints  = NULL;
01338     FT_UShort*  points;
01339     FT_Short    *deltas_x, *deltas_y;
01340 
01341 
01342     if ( !face->doblend || blend == NULL )
01343       return TT_Err_Invalid_Argument;
01344 
01345     /* to be freed by the caller */
01346     if ( FT_NEW_ARRAY( delta_xy, n_points ) )
01347       goto Exit;
01348     *deltas = delta_xy;
01349 
01350     if ( glyph_index >= blend->gv_glyphcnt      ||
01351          blend->glyphoffsets[glyph_index] ==
01352            blend->glyphoffsets[glyph_index + 1] )
01353       return TT_Err_Ok;               /* no variation data for this glyph */
01354 
01355     if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] )   ||
01356          FT_FRAME_ENTER( blend->glyphoffsets[glyph_index + 1] -
01357                            blend->glyphoffsets[glyph_index] ) )
01358       goto Fail1;
01359 
01360     glyph_start = FT_Stream_FTell( stream );
01361 
01362     /* each set of glyph variation data is formatted similarly to `cvar' */
01363     /* (except we get shared points and global tuples)                   */
01364 
01365     if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis )    ||
01366          FT_NEW_ARRAY( im_start_coords, blend->num_axis ) ||
01367          FT_NEW_ARRAY( im_end_coords, blend->num_axis )   )
01368       goto Fail2;
01369 
01370     tupleCount   = FT_GET_USHORT();
01371     offsetToData = glyph_start + FT_GET_USHORT();
01372 
01373     if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS )
01374     {
01375       here = FT_Stream_FTell( stream );
01376 
01377       FT_Stream_SeekSet( stream, offsetToData );
01378 
01379       sharedpoints = ft_var_readpackedpoints( stream, &spoint_count );
01380       offsetToData = FT_Stream_FTell( stream );
01381 
01382       FT_Stream_SeekSet( stream, here );
01383     }
01384 
01385     for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); ++i )
01386     {
01387       FT_UInt   tupleDataSize;
01388       FT_UInt   tupleIndex;
01389       FT_Fixed  apply;
01390 
01391 
01392       tupleDataSize = FT_GET_USHORT();
01393       tupleIndex    = FT_GET_USHORT();
01394 
01395       if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
01396       {
01397         for ( j = 0; j < blend->num_axis; ++j )
01398           tuple_coords[j] = FT_GET_SHORT() << 2;  /* convert from        */
01399                                                   /* short frac to fixed */
01400       }
01401       else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount )
01402       {
01403         error = TT_Err_Invalid_Table;
01404         goto Fail3;
01405       }
01406       else
01407       {
01408         FT_MEM_COPY(
01409           tuple_coords,
01410           &blend->tuplecoords[(tupleIndex & 0xFFF) * blend->num_axis],
01411           blend->num_axis * sizeof ( FT_Fixed ) );
01412       }
01413 
01414       if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
01415       {
01416         for ( j = 0; j < blend->num_axis; ++j )
01417           im_start_coords[j] = FT_GET_SHORT() << 2;
01418         for ( j = 0; j < blend->num_axis; ++j )
01419           im_end_coords[j] = FT_GET_SHORT() << 2;
01420       }
01421 
01422       apply = ft_var_apply_tuple( blend,
01423                                   (FT_UShort)tupleIndex,
01424                                   tuple_coords,
01425                                   im_start_coords,
01426                                   im_end_coords );
01427 
01428       if ( apply == 0 )              /* tuple isn't active for our blend */
01429       {
01430         offsetToData += tupleDataSize;
01431         continue;
01432       }
01433 
01434       here = FT_Stream_FTell( stream );
01435 
01436       if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS )
01437       {
01438         FT_Stream_SeekSet( stream, offsetToData );
01439 
01440         localpoints = ft_var_readpackedpoints( stream, &point_count );
01441         points      = localpoints;
01442       }
01443       else
01444       {
01445         points      = sharedpoints;
01446         point_count = spoint_count;
01447       }
01448 
01449       deltas_x = ft_var_readpackeddeltas( stream,
01450                                           point_count == 0 ? n_points
01451                                                            : point_count );
01452       deltas_y = ft_var_readpackeddeltas( stream,
01453                                           point_count == 0 ? n_points
01454                                                            : point_count );
01455 
01456       if ( points == NULL || deltas_y == NULL || deltas_x == NULL )
01457         ; /* failure, ignore it */
01458 
01459       else if ( points == ALL_POINTS )
01460       {
01461         /* this means that there are deltas for every point in the glyph */
01462         for ( j = 0; j < n_points; ++j )
01463         {
01464           delta_xy[j].x += FT_MulFix( deltas_x[j], apply );
01465           delta_xy[j].y += FT_MulFix( deltas_y[j], apply );
01466         }
01467       }
01468 
01469       else
01470       {
01471         for ( j = 0; j < point_count; ++j )
01472         {
01473           delta_xy[localpoints[j]].x += FT_MulFix( deltas_x[j], apply );
01474           delta_xy[localpoints[j]].y += FT_MulFix( deltas_y[j], apply );
01475         }
01476       }
01477 
01478       if ( localpoints != ALL_POINTS )
01479         FT_FREE( localpoints );
01480       FT_FREE( deltas_x );
01481       FT_FREE( deltas_y );
01482 
01483       offsetToData += tupleDataSize;
01484 
01485       FT_Stream_SeekSet( stream, here );
01486     }
01487 
01488   Fail3:
01489     FT_FREE( tuple_coords );
01490     FT_FREE( im_start_coords );
01491     FT_FREE( im_end_coords );
01492 
01493   Fail2:
01494     FT_FRAME_EXIT();
01495 
01496   Fail1:
01497     if ( error )
01498     {
01499       FT_FREE( delta_xy );
01500       *deltas = NULL;
01501     }
01502 
01503   Exit:
01504     return error;
01505   }
01506 
01507 
01508   /*************************************************************************/
01509   /*                                                                       */
01510   /* <Function>                                                            */
01511   /*    tt_done_blend                                                      */
01512   /*                                                                       */
01513   /* <Description>                                                         */
01514   /*    Frees the blend internal data structure.                           */
01515   /*                                                                       */
01516   FT_LOCAL_DEF( void )
01517   tt_done_blend( FT_Memory  memory,
01518                  GX_Blend   blend )
01519   {
01520     if ( blend != NULL )
01521     {
01522       FT_UInt  i;
01523 
01524 
01525       FT_FREE( blend->normalizedcoords );
01526       FT_FREE( blend->mmvar );
01527 
01528       if ( blend->avar_segment != NULL )
01529       {
01530         for ( i = 0; i < blend->num_axis; ++i )
01531           FT_FREE( blend->avar_segment[i].correspondence );
01532         FT_FREE( blend->avar_segment );
01533       }
01534 
01535       FT_FREE( blend->tuplecoords );
01536       FT_FREE( blend->glyphoffsets );
01537       FT_FREE( blend );
01538     }
01539   }
01540 
01541 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
01542 
01543 
01544 /* END */

Generated on Tue Jul 5 14:13:53 2011 for ROOT_528-00b_version by  doxygen 1.5.1