ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

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, 2010 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 || i + runcnt >= n )
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 || i + runcnt >= n )
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 = NULL;
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            /* axisCount limit implied by 16-bit instanceSize */
00686            fvar_head.axisCount > 0x3FFE                                   ||
00687            fvar_head.instanceSize != 4 + 4 * fvar_head.axisCount          ||
00688            /* instanceCount limit implied by limited range of name IDs */
00689            fvar_head.instanceCount > 0x7EFF                               ||
00690            fvar_head.offsetToData + fvar_head.axisCount * 20U +
00691              fvar_head.instanceCount * fvar_head.instanceSize > table_len )
00692       {
00693         error = TT_Err_Invalid_Table;
00694         goto Exit;
00695       }
00696 
00697       if ( FT_NEW( face->blend ) )
00698         goto Exit;
00699 
00700       /* cannot overflow 32-bit arithmetic because of limits above */
00701       face->blend->mmvar_len =
00702         sizeof ( FT_MM_Var ) +
00703         fvar_head.axisCount * sizeof ( FT_Var_Axis ) +
00704         fvar_head.instanceCount * sizeof ( FT_Var_Named_Style ) +
00705         fvar_head.instanceCount * fvar_head.axisCount * sizeof ( FT_Fixed ) +
00706         5 * fvar_head.axisCount;
00707 
00708       if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
00709         goto Exit;
00710       face->blend->mmvar = mmvar;
00711 
00712       mmvar->num_axis =
00713         fvar_head.axisCount;
00714       mmvar->num_designs =
00715         (FT_UInt)-1;           /* meaningless in this context; each glyph */
00716                                /* may have a different number of designs  */
00717                                /* (or tuples, as called by Apple)         */
00718       mmvar->num_namedstyles =
00719         fvar_head.instanceCount;
00720       mmvar->axis =
00721         (FT_Var_Axis*)&(mmvar[1]);
00722       mmvar->namedstyle =
00723         (FT_Var_Named_Style*)&(mmvar->axis[fvar_head.axisCount]);
00724 
00725       next_coords =
00726         (FT_Fixed*)&(mmvar->namedstyle[fvar_head.instanceCount]);
00727       for ( i = 0; i < fvar_head.instanceCount; ++i )
00728       {
00729         mmvar->namedstyle[i].coords  = next_coords;
00730         next_coords                 += fvar_head.axisCount;
00731       }
00732 
00733       next_name = (FT_String*)next_coords;
00734       for ( i = 0; i < fvar_head.axisCount; ++i )
00735       {
00736         mmvar->axis[i].name  = next_name;
00737         next_name           += 5;
00738       }
00739 
00740       if ( FT_STREAM_SEEK( fvar_start + fvar_head.offsetToData ) )
00741         goto Exit;
00742 
00743       a = mmvar->axis;
00744       for ( i = 0; i < fvar_head.axisCount; ++i )
00745       {
00746         GX_FVar_Axis  axis_rec;
00747 
00748 
00749         if ( FT_STREAM_READ_FIELDS( fvaraxis_fields, &axis_rec ) )
00750           goto Exit;
00751         a->tag     = axis_rec.axisTag;
00752         a->minimum = axis_rec.minValue;     /* A Fixed */
00753         a->def     = axis_rec.defaultValue; /* A Fixed */
00754         a->maximum = axis_rec.maxValue;     /* A Fixed */
00755         a->strid   = axis_rec.nameID;
00756 
00757         a->name[0] = (FT_String)(   a->tag >> 24 );
00758         a->name[1] = (FT_String)( ( a->tag >> 16 ) & 0xFF );
00759         a->name[2] = (FT_String)( ( a->tag >>  8 ) & 0xFF );
00760         a->name[3] = (FT_String)( ( a->tag       ) & 0xFF );
00761         a->name[4] = 0;
00762 
00763         ++a;
00764       }
00765 
00766       ns = mmvar->namedstyle;
00767       for ( i = 0; i < fvar_head.instanceCount; ++i, ++ns )
00768       {
00769         if ( FT_FRAME_ENTER( 4L + 4L * fvar_head.axisCount ) )
00770           goto Exit;
00771 
00772         ns->strid       =    FT_GET_USHORT();
00773         (void) /* flags = */ FT_GET_USHORT();
00774 
00775         for ( j = 0; j < fvar_head.axisCount; ++j )
00776           ns->coords[j] = FT_GET_ULONG();     /* A Fixed */
00777 
00778         FT_FRAME_EXIT();
00779       }
00780     }
00781 
00782     if ( master != NULL )
00783     {
00784       FT_UInt  n;
00785 
00786 
00787       if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
00788         goto Exit;
00789       FT_MEM_COPY( mmvar, face->blend->mmvar, face->blend->mmvar_len );
00790 
00791       mmvar->axis =
00792         (FT_Var_Axis*)&(mmvar[1]);
00793       mmvar->namedstyle =
00794         (FT_Var_Named_Style*)&(mmvar->axis[mmvar->num_axis]);
00795       next_coords =
00796         (FT_Fixed*)&(mmvar->namedstyle[mmvar->num_namedstyles]);
00797 
00798       for ( n = 0; n < mmvar->num_namedstyles; ++n )
00799       {
00800         mmvar->namedstyle[n].coords  = next_coords;
00801         next_coords                 += mmvar->num_axis;
00802       }
00803 
00804       a = mmvar->axis;
00805       next_name = (FT_String*)next_coords;
00806       for ( n = 0; n < mmvar->num_axis; ++n )
00807       {
00808         a->name = next_name;
00809 
00810         /* standard PostScript names for some standard apple tags */
00811         if ( a->tag == TTAG_wght )
00812           a->name = (char *)"Weight";
00813         else if ( a->tag == TTAG_wdth )
00814           a->name = (char *)"Width";
00815         else if ( a->tag == TTAG_opsz )
00816           a->name = (char *)"OpticalSize";
00817         else if ( a->tag == TTAG_slnt )
00818           a->name = (char *)"Slant";
00819 
00820         next_name += 5;
00821         ++a;
00822       }
00823 
00824       *master = mmvar;
00825     }
00826 
00827   Exit:
00828     return error;
00829   }
00830 
00831 
00832   /*************************************************************************/
00833   /*                                                                       */
00834   /* <Function>                                                            */
00835   /*    TT_Set_MM_Blend                                                    */
00836   /*                                                                       */
00837   /* <Description>                                                         */
00838   /*    Set the blend (normalized) coordinates for this instance of the    */
00839   /*    font.  Check that the `gvar' table is reasonable and does some     */
00840   /*    initial preparation.                                               */
00841   /*                                                                       */
00842   /* <InOut>                                                               */
00843   /*    face       :: The font.                                            */
00844   /*                  Initialize the blend structure with `gvar' data.     */
00845   /*                                                                       */
00846   /* <Input>                                                               */
00847   /*    num_coords :: Must be the axis count of the font.                  */
00848   /*                                                                       */
00849   /*    coords     :: An array of num_coords, each between [-1,1].         */
00850   /*                                                                       */
00851   /* <Return>                                                              */
00852   /*    FreeType error code.  0 means success.                             */
00853   /*                                                                       */
00854   FT_LOCAL_DEF( FT_Error )
00855   TT_Set_MM_Blend( TT_Face    face,
00856                    FT_UInt    num_coords,
00857                    FT_Fixed*  coords )
00858   {
00859     FT_Error    error = TT_Err_Ok;
00860     GX_Blend    blend;
00861     FT_MM_Var*  mmvar;
00862     FT_UInt     i;
00863     FT_Memory   memory = face->root.memory;
00864 
00865     enum
00866     {
00867       mcvt_retain,
00868       mcvt_modify,
00869       mcvt_load
00870 
00871     } manageCvt;
00872 
00873 
00874     face->doblend = FALSE;
00875 
00876     if ( face->blend == NULL )
00877     {
00878       if ( (error = TT_Get_MM_Var( face, NULL)) != 0 )
00879         goto Exit;
00880     }
00881 
00882     blend = face->blend;
00883     mmvar = blend->mmvar;
00884 
00885     if ( num_coords != mmvar->num_axis )
00886     {
00887       error = TT_Err_Invalid_Argument;
00888       goto Exit;
00889     }
00890 
00891     for ( i = 0; i < num_coords; ++i )
00892       if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L )
00893       {
00894         error = TT_Err_Invalid_Argument;
00895         goto Exit;
00896       }
00897 
00898     if ( blend->glyphoffsets == NULL )
00899       if ( (error = ft_var_load_gvar( face )) != 0 )
00900         goto Exit;
00901 
00902     if ( blend->normalizedcoords == NULL )
00903     {
00904       if ( FT_NEW_ARRAY( blend->normalizedcoords, num_coords ) )
00905         goto Exit;
00906 
00907       manageCvt = mcvt_modify;
00908 
00909       /* If we have not set the blend coordinates before this, then the  */
00910       /* cvt table will still be what we read from the `cvt ' table and  */
00911       /* we don't need to reload it.  We may need to change it though... */
00912     }
00913     else
00914     {
00915       manageCvt = mcvt_retain;
00916       for ( i = 0; i < num_coords; ++i )
00917       {
00918         if ( blend->normalizedcoords[i] != coords[i] )
00919         {
00920           manageCvt = mcvt_load;
00921           break;
00922         }
00923       }
00924 
00925       /* If we don't change the blend coords then we don't need to do  */
00926       /* anything to the cvt table.  It will be correct.  Otherwise we */
00927       /* no longer have the original cvt (it was modified when we set  */
00928       /* the blend last time), so we must reload and then modify it.   */
00929     }
00930 
00931     blend->num_axis = num_coords;
00932     FT_MEM_COPY( blend->normalizedcoords,
00933                  coords,
00934                  num_coords * sizeof ( FT_Fixed ) );
00935 
00936     face->doblend = TRUE;
00937 
00938     if ( face->cvt != NULL )
00939     {
00940       switch ( manageCvt )
00941       {
00942       case mcvt_load:
00943         /* The cvt table has been loaded already; every time we change the */
00944         /* blend we may need to reload and remodify the cvt table.         */
00945         FT_FREE( face->cvt );
00946         face->cvt = NULL;
00947 
00948         tt_face_load_cvt( face, face->root.stream );
00949         break;
00950 
00951       case mcvt_modify:
00952         /* The original cvt table is in memory.  All we need to do is */
00953         /* apply the `cvar' table (if any).                           */
00954         tt_face_vary_cvt( face, face->root.stream );
00955         break;
00956 
00957       case mcvt_retain:
00958         /* The cvt table is correct for this set of coordinates. */
00959         break;
00960       }
00961     }
00962 
00963   Exit:
00964     return error;
00965   }
00966 
00967 
00968   /*************************************************************************/
00969   /*                                                                       */
00970   /* <Function>                                                            */
00971   /*    TT_Set_Var_Design                                                  */
00972   /*                                                                       */
00973   /* <Description>                                                         */
00974   /*    Set the coordinates for the instance, measured in the user         */
00975   /*    coordinate system.  Parse the `avar' table (if present) to convert */
00976   /*    from user to normalized coordinates.                               */
00977   /*                                                                       */
00978   /* <InOut>                                                               */
00979   /*    face       :: The font face.                                       */
00980   /*                  Initialize the blend struct with `gvar' data.        */
00981   /*                                                                       */
00982   /* <Input>                                                               */
00983   /*    num_coords :: This must be the axis count of the font.             */
00984   /*                                                                       */
00985   /*    coords     :: A coordinate array with `num_coords' elements.       */
00986   /*                                                                       */
00987   /* <Return>                                                              */
00988   /*    FreeType error code.  0 means success.                             */
00989   /*                                                                       */
00990   FT_LOCAL_DEF( FT_Error )
00991   TT_Set_Var_Design( TT_Face    face,
00992                      FT_UInt    num_coords,
00993                      FT_Fixed*  coords )
00994   {
00995     FT_Error        error      = TT_Err_Ok;
00996     FT_Fixed*       normalized = NULL;
00997     GX_Blend        blend;
00998     FT_MM_Var*      mmvar;
00999     FT_UInt         i, j;
01000     FT_Var_Axis*    a;
01001     GX_AVarSegment  av;
01002     FT_Memory       memory = face->root.memory;
01003 
01004 
01005     if ( face->blend == NULL )
01006     {
01007       if ( (error = TT_Get_MM_Var( face, NULL )) != 0 )
01008         goto Exit;
01009     }
01010 
01011     blend = face->blend;
01012     mmvar = blend->mmvar;
01013 
01014     if ( num_coords != mmvar->num_axis )
01015     {
01016       error = TT_Err_Invalid_Argument;
01017       goto Exit;
01018     }
01019 
01020     /* Axis normalization is a two stage process.  First we normalize */
01021     /* based on the [min,def,max] values for the axis to be [-1,0,1]. */
01022     /* Then, if there's an `avar' table, we renormalize this range.   */
01023 
01024     if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) )
01025       goto Exit;
01026 
01027     a = mmvar->axis;
01028     for ( i = 0; i < mmvar->num_axis; ++i, ++a )
01029     {
01030       if ( coords[i] > a->maximum || coords[i] < a->minimum )
01031       {
01032         error = TT_Err_Invalid_Argument;
01033         goto Exit;
01034       }
01035 
01036       if ( coords[i] < a->def )
01037       {
01038         normalized[i] = -FT_MulDiv( coords[i] - a->def,
01039                                     0x10000L,
01040                                     a->minimum - a->def );
01041       }
01042       else if ( a->maximum == a->def )
01043         normalized[i] = 0;
01044       else
01045       {
01046         normalized[i] = FT_MulDiv( coords[i] - a->def,
01047                                    0x10000L,
01048                                    a->maximum - a->def );
01049       }
01050     }
01051 
01052     if ( !blend->avar_checked )
01053       ft_var_load_avar( face );
01054 
01055     if ( blend->avar_segment != NULL )
01056     {
01057       av = blend->avar_segment;
01058       for ( i = 0; i < mmvar->num_axis; ++i, ++av )
01059       {
01060         for ( j = 1; j < (FT_UInt)av->pairCount; ++j )
01061           if ( normalized[i] < av->correspondence[j].fromCoord )
01062           {
01063             normalized[i] =
01064               FT_MulDiv(
01065                 FT_MulDiv(
01066                   normalized[i] - av->correspondence[j - 1].fromCoord,
01067                   0x10000L,
01068                   av->correspondence[j].fromCoord -
01069                     av->correspondence[j - 1].fromCoord ),
01070                 av->correspondence[j].toCoord -
01071                   av->correspondence[j - 1].toCoord,
01072                 0x10000L ) +
01073               av->correspondence[j - 1].toCoord;
01074             break;
01075           }
01076       }
01077     }
01078 
01079     error = TT_Set_MM_Blend( face, num_coords, normalized );
01080 
01081   Exit:
01082     FT_FREE( normalized );
01083     return error;
01084   }
01085 
01086 
01087   /*************************************************************************/
01088   /*************************************************************************/
01089   /*****                                                               *****/
01090   /*****                     GX VAR PARSING ROUTINES                   *****/
01091   /*****                                                               *****/
01092   /*************************************************************************/
01093   /*************************************************************************/
01094 
01095 
01096   /*************************************************************************/
01097   /*                                                                       */
01098   /* <Function>                                                            */
01099   /*    tt_face_vary_cvt                                                   */
01100   /*                                                                       */
01101   /* <Description>                                                         */
01102   /*    Modify the loaded cvt table according to the `cvar' table and the  */
01103   /*    font's blend.                                                      */
01104   /*                                                                       */
01105   /* <InOut>                                                               */
01106   /*    face   :: A handle to the target face object.                      */
01107   /*                                                                       */
01108   /* <Input>                                                               */
01109   /*    stream :: A handle to the input stream.                            */
01110   /*                                                                       */
01111   /* <Return>                                                              */
01112   /*    FreeType error code.  0 means success.                             */
01113   /*                                                                       */
01114   /*    Most errors are ignored.  It is perfectly valid not to have a      */
01115   /*    `cvar' table even if there is a `gvar' and `fvar' table.           */
01116   /*                                                                       */
01117   FT_LOCAL_DEF( FT_Error )
01118   tt_face_vary_cvt( TT_Face    face,
01119                     FT_Stream  stream )
01120   {
01121     FT_Error    error;
01122     FT_Memory   memory = stream->memory;
01123     FT_ULong    table_start;
01124     FT_ULong    table_len;
01125     FT_UInt     tupleCount;
01126     FT_ULong    offsetToData;
01127     FT_ULong    here;
01128     FT_UInt     i, j;
01129     FT_Fixed*   tuple_coords    = NULL;
01130     FT_Fixed*   im_start_coords = NULL;
01131     FT_Fixed*   im_end_coords   = NULL;
01132     GX_Blend    blend           = face->blend;
01133     FT_UInt     point_count;
01134     FT_UShort*  localpoints;
01135     FT_Short*   deltas;
01136 
01137 
01138     FT_TRACE2(( "CVAR " ));
01139 
01140     if ( blend == NULL )
01141     {
01142       FT_TRACE2(( "tt_face_vary_cvt: no blend specified\n" ));
01143 
01144       error = TT_Err_Ok;
01145       goto Exit;
01146     }
01147 
01148     if ( face->cvt == NULL )
01149     {
01150       FT_TRACE2(( "tt_face_vary_cvt: no `cvt ' table\n" ));
01151 
01152       error = TT_Err_Ok;
01153       goto Exit;
01154     }
01155 
01156     error = face->goto_table( face, TTAG_cvar, stream, &table_len );
01157     if ( error )
01158     {
01159       FT_TRACE2(( "is missing\n" ));
01160 
01161       error = TT_Err_Ok;
01162       goto Exit;
01163     }
01164 
01165     if ( FT_FRAME_ENTER( table_len ) )
01166     {
01167       error = TT_Err_Ok;
01168       goto Exit;
01169     }
01170 
01171     table_start = FT_Stream_FTell( stream );
01172     if ( FT_GET_LONG() != 0x00010000L )
01173     {
01174       FT_TRACE2(( "bad table version\n" ));
01175 
01176       error = TT_Err_Ok;
01177       goto FExit;
01178     }
01179 
01180     if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis )    ||
01181          FT_NEW_ARRAY( im_start_coords, blend->num_axis ) ||
01182          FT_NEW_ARRAY( im_end_coords, blend->num_axis )   )
01183       goto FExit;
01184 
01185     tupleCount   = FT_GET_USHORT();
01186     offsetToData = table_start + FT_GET_USHORT();
01187 
01188     /* The documentation implies there are flags packed into the        */
01189     /* tuplecount, but John Jenkins says that shared points don't apply */
01190     /* to `cvar', and no other flags are defined.                       */
01191 
01192     for ( i = 0; i < ( tupleCount & 0xFFF ); ++i )
01193     {
01194       FT_UInt   tupleDataSize;
01195       FT_UInt   tupleIndex;
01196       FT_Fixed  apply;
01197 
01198 
01199       tupleDataSize = FT_GET_USHORT();
01200       tupleIndex    = FT_GET_USHORT();
01201 
01202       /* There is no provision here for a global tuple coordinate section, */
01203       /* so John says.  There are no tuple indices, just embedded tuples.  */
01204 
01205       if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
01206       {
01207         for ( j = 0; j < blend->num_axis; ++j )
01208           tuple_coords[j] = FT_GET_SHORT() << 2; /* convert from        */
01209                                                  /* short frac to fixed */
01210       }
01211       else
01212       {
01213         /* skip this tuple; it makes no sense */
01214 
01215         if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
01216           for ( j = 0; j < 2 * blend->num_axis; ++j )
01217             (void)FT_GET_SHORT();
01218 
01219         offsetToData += tupleDataSize;
01220         continue;
01221       }
01222 
01223       if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
01224       {
01225         for ( j = 0; j < blend->num_axis; ++j )
01226           im_start_coords[j] = FT_GET_SHORT() << 2;
01227         for ( j = 0; j < blend->num_axis; ++j )
01228           im_end_coords[j] = FT_GET_SHORT() << 2;
01229       }
01230 
01231       apply = ft_var_apply_tuple( blend,
01232                                   (FT_UShort)tupleIndex,
01233                                   tuple_coords,
01234                                   im_start_coords,
01235                                   im_end_coords );
01236       if ( /* tuple isn't active for our blend */
01237            apply == 0                                    ||
01238            /* global points not allowed,           */
01239            /* if they aren't local, makes no sense */
01240            !( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) )
01241       {
01242         offsetToData += tupleDataSize;
01243         continue;
01244       }
01245 
01246       here = FT_Stream_FTell( stream );
01247 
01248       FT_Stream_SeekSet( stream, offsetToData );
01249 
01250       localpoints = ft_var_readpackedpoints( stream, &point_count );
01251       deltas      = ft_var_readpackeddeltas( stream,
01252                                              point_count == 0 ? face->cvt_size
01253                                                               : point_count );
01254       if ( localpoints == NULL || deltas == NULL )
01255         /* failure, ignore it */;
01256 
01257       else if ( localpoints == ALL_POINTS )
01258       {
01259         /* this means that there are deltas for every entry in cvt */
01260         for ( j = 0; j < face->cvt_size; ++j )
01261           face->cvt[j] = (FT_Short)( face->cvt[j] +
01262                                      FT_MulFix( deltas[j], apply ) );
01263       }
01264 
01265       else
01266       {
01267         for ( j = 0; j < point_count; ++j )
01268         {
01269           int  pindex = localpoints[j];
01270 
01271           face->cvt[pindex] = (FT_Short)( face->cvt[pindex] +
01272                                           FT_MulFix( deltas[j], apply ) );
01273         }
01274       }
01275 
01276       if ( localpoints != ALL_POINTS )
01277         FT_FREE( localpoints );
01278       FT_FREE( deltas );
01279 
01280       offsetToData += tupleDataSize;
01281 
01282       FT_Stream_SeekSet( stream, here );
01283     }
01284 
01285   FExit:
01286     FT_FRAME_EXIT();
01287 
01288   Exit:
01289     FT_FREE( tuple_coords );
01290     FT_FREE( im_start_coords );
01291     FT_FREE( im_end_coords );
01292 
01293     return error;
01294   }
01295 
01296 
01297   /*************************************************************************/
01298   /*                                                                       */
01299   /* <Function>                                                            */
01300   /*    TT_Vary_Get_Glyph_Deltas                                           */
01301   /*                                                                       */
01302   /* <Description>                                                         */
01303   /*    Load the appropriate deltas for the current glyph.                 */
01304   /*                                                                       */
01305   /* <Input>                                                               */
01306   /*    face        :: A handle to the target face object.                 */
01307   /*                                                                       */
01308   /*    glyph_index :: The index of the glyph being modified.              */
01309   /*                                                                       */
01310   /*    n_points    :: The number of the points in the glyph, including    */
01311   /*                   phantom points.                                     */
01312   /*                                                                       */
01313   /* <Output>                                                              */
01314   /*    deltas      :: The array of points to change.                      */
01315   /*                                                                       */
01316   /* <Return>                                                              */
01317   /*    FreeType error code.  0 means success.                             */
01318   /*                                                                       */
01319   FT_LOCAL_DEF( FT_Error )
01320   TT_Vary_Get_Glyph_Deltas( TT_Face      face,
01321                             FT_UInt      glyph_index,
01322                             FT_Vector*  *deltas,
01323                             FT_UInt      n_points )
01324   {
01325     FT_Stream   stream = face->root.stream;
01326     FT_Memory   memory = stream->memory;
01327     GX_Blend    blend  = face->blend;
01328     FT_Vector*  delta_xy;
01329 
01330     FT_Error    error;
01331     FT_ULong    glyph_start;
01332     FT_UInt     tupleCount;
01333     FT_ULong    offsetToData;
01334     FT_ULong    here;
01335     FT_UInt     i, j;
01336     FT_Fixed*   tuple_coords    = NULL;
01337     FT_Fixed*   im_start_coords = NULL;
01338     FT_Fixed*   im_end_coords   = NULL;
01339     FT_UInt     point_count, spoint_count = 0;
01340     FT_UShort*  sharedpoints = NULL;
01341     FT_UShort*  localpoints  = NULL;
01342     FT_UShort*  points;
01343     FT_Short    *deltas_x, *deltas_y;
01344 
01345 
01346     if ( !face->doblend || blend == NULL )
01347       return TT_Err_Invalid_Argument;
01348 
01349     /* to be freed by the caller */
01350     if ( FT_NEW_ARRAY( delta_xy, n_points ) )
01351       goto Exit;
01352     *deltas = delta_xy;
01353 
01354     if ( glyph_index >= blend->gv_glyphcnt      ||
01355          blend->glyphoffsets[glyph_index] ==
01356            blend->glyphoffsets[glyph_index + 1] )
01357       return TT_Err_Ok;               /* no variation data for this glyph */
01358 
01359     if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] )   ||
01360          FT_FRAME_ENTER( blend->glyphoffsets[glyph_index + 1] -
01361                            blend->glyphoffsets[glyph_index] ) )
01362       goto Fail1;
01363 
01364     glyph_start = FT_Stream_FTell( stream );
01365 
01366     /* each set of glyph variation data is formatted similarly to `cvar' */
01367     /* (except we get shared points and global tuples)                   */
01368 
01369     if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis )    ||
01370          FT_NEW_ARRAY( im_start_coords, blend->num_axis ) ||
01371          FT_NEW_ARRAY( im_end_coords, blend->num_axis )   )
01372       goto Fail2;
01373 
01374     tupleCount   = FT_GET_USHORT();
01375     offsetToData = glyph_start + FT_GET_USHORT();
01376 
01377     if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS )
01378     {
01379       here = FT_Stream_FTell( stream );
01380 
01381       FT_Stream_SeekSet( stream, offsetToData );
01382 
01383       sharedpoints = ft_var_readpackedpoints( stream, &spoint_count );
01384       offsetToData = FT_Stream_FTell( stream );
01385 
01386       FT_Stream_SeekSet( stream, here );
01387     }
01388 
01389     for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); ++i )
01390     {
01391       FT_UInt   tupleDataSize;
01392       FT_UInt   tupleIndex;
01393       FT_Fixed  apply;
01394 
01395 
01396       tupleDataSize = FT_GET_USHORT();
01397       tupleIndex    = FT_GET_USHORT();
01398 
01399       if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
01400       {
01401         for ( j = 0; j < blend->num_axis; ++j )
01402           tuple_coords[j] = FT_GET_SHORT() << 2;  /* convert from        */
01403                                                   /* short frac to fixed */
01404       }
01405       else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount )
01406       {
01407         error = TT_Err_Invalid_Table;
01408         goto Fail3;
01409       }
01410       else
01411       {
01412         FT_MEM_COPY(
01413           tuple_coords,
01414           &blend->tuplecoords[(tupleIndex & 0xFFF) * blend->num_axis],
01415           blend->num_axis * sizeof ( FT_Fixed ) );
01416       }
01417 
01418       if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
01419       {
01420         for ( j = 0; j < blend->num_axis; ++j )
01421           im_start_coords[j] = FT_GET_SHORT() << 2;
01422         for ( j = 0; j < blend->num_axis; ++j )
01423           im_end_coords[j] = FT_GET_SHORT() << 2;
01424       }
01425 
01426       apply = ft_var_apply_tuple( blend,
01427                                   (FT_UShort)tupleIndex,
01428                                   tuple_coords,
01429                                   im_start_coords,
01430                                   im_end_coords );
01431 
01432       if ( apply == 0 )              /* tuple isn't active for our blend */
01433       {
01434         offsetToData += tupleDataSize;
01435         continue;
01436       }
01437 
01438       here = FT_Stream_FTell( stream );
01439 
01440       if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS )
01441       {
01442         FT_Stream_SeekSet( stream, offsetToData );
01443 
01444         localpoints = ft_var_readpackedpoints( stream, &point_count );
01445         points      = localpoints;
01446       }
01447       else
01448       {
01449         points      = sharedpoints;
01450         point_count = spoint_count;
01451       }
01452 
01453       deltas_x = ft_var_readpackeddeltas( stream,
01454                                           point_count == 0 ? n_points
01455                                                            : point_count );
01456       deltas_y = ft_var_readpackeddeltas( stream,
01457                                           point_count == 0 ? n_points
01458                                                            : point_count );
01459 
01460       if ( points == NULL || deltas_y == NULL || deltas_x == NULL )
01461         ; /* failure, ignore it */
01462 
01463       else if ( points == ALL_POINTS )
01464       {
01465         /* this means that there are deltas for every point in the glyph */
01466         for ( j = 0; j < n_points; ++j )
01467         {
01468           delta_xy[j].x += FT_MulFix( deltas_x[j], apply );
01469           delta_xy[j].y += FT_MulFix( deltas_y[j], apply );
01470         }
01471       }
01472 
01473       else
01474       {
01475         for ( j = 0; j < point_count; ++j )
01476         {
01477           delta_xy[localpoints[j]].x += FT_MulFix( deltas_x[j], apply );
01478           delta_xy[localpoints[j]].y += FT_MulFix( deltas_y[j], apply );
01479         }
01480       }
01481 
01482       if ( localpoints != ALL_POINTS )
01483         FT_FREE( localpoints );
01484       FT_FREE( deltas_x );
01485       FT_FREE( deltas_y );
01486 
01487       offsetToData += tupleDataSize;
01488 
01489       FT_Stream_SeekSet( stream, here );
01490     }
01491 
01492   Fail3:
01493     FT_FREE( tuple_coords );
01494     FT_FREE( im_start_coords );
01495     FT_FREE( im_end_coords );
01496 
01497   Fail2:
01498     FT_FRAME_EXIT();
01499 
01500   Fail1:
01501     if ( error )
01502     {
01503       FT_FREE( delta_xy );
01504       *deltas = NULL;
01505     }
01506 
01507   Exit:
01508     return error;
01509   }
01510 
01511 
01512   /*************************************************************************/
01513   /*                                                                       */
01514   /* <Function>                                                            */
01515   /*    tt_done_blend                                                      */
01516   /*                                                                       */
01517   /* <Description>                                                         */
01518   /*    Frees the blend internal data structure.                           */
01519   /*                                                                       */
01520   FT_LOCAL_DEF( void )
01521   tt_done_blend( FT_Memory  memory,
01522                  GX_Blend   blend )
01523   {
01524     if ( blend != NULL )
01525     {
01526       FT_UInt  i;
01527 
01528 
01529       FT_FREE( blend->normalizedcoords );
01530       FT_FREE( blend->mmvar );
01531 
01532       if ( blend->avar_segment != NULL )
01533       {
01534         for ( i = 0; i < blend->num_axis; ++i )
01535           FT_FREE( blend->avar_segment[i].correspondence );
01536         FT_FREE( blend->avar_segment );
01537       }
01538 
01539       FT_FREE( blend->tuplecoords );
01540       FT_FREE( blend->glyphoffsets );
01541       FT_FREE( blend );
01542     }
01543   }
01544 
01545 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
01546 
01547 
01548 /* END */

Generated on Sun May 27 2012 04:34:03 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.