misc/libfreetype/src/gxvalid/gxvkern.c
changeset 9372 915436ff64ab
parent 9371 f3840de881bd
child 9373 b769a8e38cbd
equal deleted inserted replaced
9371:f3840de881bd 9372:915436ff64ab
     1 /***************************************************************************/
       
     2 /*                                                                         */
       
     3 /*  gxvkern.c                                                              */
       
     4 /*                                                                         */
       
     5 /*    TrueTypeGX/AAT kern table validation (body).                         */
       
     6 /*                                                                         */
       
     7 /*  Copyright 2004, 2005, 2006, 2007                                       */
       
     8 /*  by suzuki toshiya, Masatake YAMATO, Red Hat K.K.,                      */
       
     9 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
       
    10 /*                                                                         */
       
    11 /*  This file is part of the FreeType project, and may only be used,       */
       
    12 /*  modified, and distributed under the terms of the FreeType project      */
       
    13 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
       
    14 /*  this file you indicate that you have read the license and              */
       
    15 /*  understand and accept it fully.                                        */
       
    16 /*                                                                         */
       
    17 /***************************************************************************/
       
    18 
       
    19 /***************************************************************************/
       
    20 /*                                                                         */
       
    21 /* gxvalid is derived from both gxlayout module and otvalid module.        */
       
    22 /* Development of gxlayout is supported by the Information-technology      */
       
    23 /* Promotion Agency(IPA), Japan.                                           */
       
    24 /*                                                                         */
       
    25 /***************************************************************************/
       
    26 
       
    27 
       
    28 #include "gxvalid.h"
       
    29 #include "gxvcommn.h"
       
    30 
       
    31 #include FT_SFNT_NAMES_H
       
    32 #include FT_SERVICE_GX_VALIDATE_H
       
    33 
       
    34 
       
    35   /*************************************************************************/
       
    36   /*                                                                       */
       
    37   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
       
    38   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
       
    39   /* messages during execution.                                            */
       
    40   /*                                                                       */
       
    41 #undef  FT_COMPONENT
       
    42 #define FT_COMPONENT  trace_gxvkern
       
    43 
       
    44 
       
    45   /*************************************************************************/
       
    46   /*************************************************************************/
       
    47   /*****                                                               *****/
       
    48   /*****                      Data and Types                           *****/
       
    49   /*****                                                               *****/
       
    50   /*************************************************************************/
       
    51   /*************************************************************************/
       
    52 
       
    53   typedef enum  GXV_kern_Version_
       
    54   {
       
    55     KERN_VERSION_CLASSIC = 0x0000,
       
    56     KERN_VERSION_NEW     = 0x0001
       
    57 
       
    58   } GXV_kern_Version;
       
    59 
       
    60 
       
    61   typedef enum GXV_kern_Dialect_
       
    62   {
       
    63     KERN_DIALECT_UNKNOWN = 0,
       
    64     KERN_DIALECT_MS      = FT_VALIDATE_MS,
       
    65     KERN_DIALECT_APPLE   = FT_VALIDATE_APPLE,
       
    66     KERN_DIALECT_ANY     = FT_VALIDATE_CKERN
       
    67 
       
    68   } GXV_kern_Dialect;
       
    69 
       
    70 
       
    71   typedef struct  GXV_kern_DataRec_
       
    72   {
       
    73     GXV_kern_Version  version;
       
    74     void             *subtable_data;
       
    75     GXV_kern_Dialect  dialect_request;
       
    76 
       
    77   } GXV_kern_DataRec, *GXV_kern_Data;
       
    78 
       
    79 
       
    80 #define GXV_KERN_DATA( field )  GXV_TABLE_DATA( kern, field )
       
    81 
       
    82 #define KERN_IS_CLASSIC( valid )                               \
       
    83           ( KERN_VERSION_CLASSIC == GXV_KERN_DATA( version ) )
       
    84 #define KERN_IS_NEW( valid )                                   \
       
    85           ( KERN_VERSION_NEW     == GXV_KERN_DATA( version ) )
       
    86 
       
    87 #define KERN_DIALECT( valid )              \
       
    88           GXV_KERN_DATA( dialect_request )
       
    89 #define KERN_ALLOWS_MS( valid )                       \
       
    90           ( KERN_DIALECT( valid ) & KERN_DIALECT_MS )
       
    91 #define KERN_ALLOWS_APPLE( valid )                       \
       
    92           ( KERN_DIALECT( valid ) & KERN_DIALECT_APPLE )
       
    93 
       
    94 #define GXV_KERN_HEADER_SIZE           ( KERN_IS_NEW( valid ) ? 8 : 4 )
       
    95 #define GXV_KERN_SUBTABLE_HEADER_SIZE  ( KERN_IS_NEW( valid ) ? 8 : 6 )
       
    96 
       
    97 
       
    98   /*************************************************************************/
       
    99   /*************************************************************************/
       
   100   /*****                                                               *****/
       
   101   /*****                      SUBTABLE VALIDATORS                      *****/
       
   102   /*****                                                               *****/
       
   103   /*************************************************************************/
       
   104   /*************************************************************************/
       
   105 
       
   106 
       
   107   /* ============================= format 0 ============================== */
       
   108 
       
   109   static void
       
   110   gxv_kern_subtable_fmt0_pairs_validate( FT_Bytes       table,
       
   111                                          FT_Bytes       limit,
       
   112                                          FT_UShort      nPairs,
       
   113                                          GXV_Validator  valid )
       
   114   {
       
   115     FT_Bytes   p = table;
       
   116     FT_UShort  i;
       
   117 
       
   118     FT_UShort  last_gid_left  = 0;
       
   119     FT_UShort  last_gid_right = 0;
       
   120 
       
   121     FT_UNUSED( limit );
       
   122 
       
   123 
       
   124     GXV_NAME_ENTER( "kern format 0 pairs" );
       
   125 
       
   126     for ( i = 0; i < nPairs; i++ )
       
   127     {
       
   128       FT_UShort  gid_left;
       
   129       FT_UShort  gid_right;
       
   130       FT_Short   kernValue;
       
   131 
       
   132 
       
   133       /* left */
       
   134       gid_left  = FT_NEXT_USHORT( p );
       
   135       gxv_glyphid_validate( gid_left, valid );
       
   136 
       
   137       /* right */
       
   138       gid_right = FT_NEXT_USHORT( p );
       
   139       gxv_glyphid_validate( gid_right, valid );
       
   140 
       
   141       /* Pairs of left and right GIDs must be unique and sorted. */
       
   142       GXV_TRACE(( "left gid = %u, right gid = %u\n", gid_left, gid_right ));
       
   143       if ( gid_left == last_gid_left )
       
   144       {
       
   145         if ( last_gid_right < gid_right )
       
   146           last_gid_right = gid_right;
       
   147         else
       
   148           FT_INVALID_DATA;
       
   149       }
       
   150       else if ( last_gid_left < gid_left )
       
   151       {
       
   152         last_gid_left  = gid_left;
       
   153         last_gid_right = gid_right;
       
   154       }
       
   155       else
       
   156         FT_INVALID_DATA;
       
   157 
       
   158       /* skip the kern value */
       
   159       kernValue = FT_NEXT_SHORT( p );
       
   160     }
       
   161 
       
   162     GXV_EXIT;
       
   163   }
       
   164 
       
   165   static void
       
   166   gxv_kern_subtable_fmt0_validate( FT_Bytes       table,
       
   167                                    FT_Bytes       limit,
       
   168                                    GXV_Validator  valid )
       
   169   {
       
   170     FT_Bytes   p = table + GXV_KERN_SUBTABLE_HEADER_SIZE;
       
   171 
       
   172     FT_UShort  nPairs;
       
   173     FT_UShort  unitSize;
       
   174 
       
   175 
       
   176     GXV_NAME_ENTER( "kern subtable format 0" );
       
   177 
       
   178     unitSize = 2 + 2 + 2;
       
   179     nPairs   = 0;
       
   180 
       
   181     /* nPairs, searchRange, entrySelector, rangeShift */
       
   182     GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 );
       
   183     gxv_BinSrchHeader_validate( p, limit, &unitSize, &nPairs, valid );
       
   184     p += 2 + 2 + 2 + 2;
       
   185 
       
   186     gxv_kern_subtable_fmt0_pairs_validate( p, limit, nPairs, valid );
       
   187 
       
   188     GXV_EXIT;
       
   189   }
       
   190 
       
   191 
       
   192   /* ============================= format 1 ============================== */
       
   193 
       
   194 
       
   195   typedef struct  GXV_kern_fmt1_StateOptRec_
       
   196   {
       
   197     FT_UShort  valueTable;
       
   198     FT_UShort  valueTable_length;
       
   199 
       
   200   } GXV_kern_fmt1_StateOptRec, *GXV_kern_fmt1_StateOptRecData;
       
   201 
       
   202 
       
   203   static void
       
   204   gxv_kern_subtable_fmt1_valueTable_load( FT_Bytes       table,
       
   205                                           FT_Bytes       limit,
       
   206                                           GXV_Validator  valid )
       
   207   {
       
   208     FT_Bytes                       p = table;
       
   209     GXV_kern_fmt1_StateOptRecData  optdata =
       
   210       (GXV_kern_fmt1_StateOptRecData)valid->statetable.optdata;
       
   211 
       
   212 
       
   213     GXV_LIMIT_CHECK( 2 );
       
   214     optdata->valueTable = FT_NEXT_USHORT( p );
       
   215   }
       
   216 
       
   217 
       
   218   /*
       
   219    * passed tables_size covers whole StateTable, including kern fmt1 header
       
   220    */
       
   221   static void
       
   222   gxv_kern_subtable_fmt1_subtable_setup( FT_UShort      table_size,
       
   223                                          FT_UShort      classTable,
       
   224                                          FT_UShort      stateArray,
       
   225                                          FT_UShort      entryTable,
       
   226                                          FT_UShort*     classTable_length_p,
       
   227                                          FT_UShort*     stateArray_length_p,
       
   228                                          FT_UShort*     entryTable_length_p,
       
   229                                          GXV_Validator  valid )
       
   230   {
       
   231     FT_UShort  o[4];
       
   232     FT_UShort  *l[4];
       
   233     FT_UShort  buff[5];
       
   234 
       
   235     GXV_kern_fmt1_StateOptRecData  optdata =
       
   236       (GXV_kern_fmt1_StateOptRecData)valid->statetable.optdata;
       
   237 
       
   238 
       
   239     o[0] = classTable;
       
   240     o[1] = stateArray;
       
   241     o[2] = entryTable;
       
   242     o[3] = optdata->valueTable;
       
   243     l[0] = classTable_length_p;
       
   244     l[1] = stateArray_length_p;
       
   245     l[2] = entryTable_length_p;
       
   246     l[3] = &(optdata->valueTable_length);
       
   247 
       
   248     gxv_set_length_by_ushort_offset( o, l, buff, 4, table_size, valid );
       
   249   }
       
   250 
       
   251 
       
   252   /*
       
   253    * passed table & limit are of whole StateTable, not including subtables
       
   254    */
       
   255   static void
       
   256   gxv_kern_subtable_fmt1_entry_validate(
       
   257     FT_Byte                         state,
       
   258     FT_UShort                       flags,
       
   259     GXV_StateTable_GlyphOffsetCPtr  glyphOffset_p,
       
   260     FT_Bytes                        table,
       
   261     FT_Bytes                        limit,
       
   262     GXV_Validator                   valid )
       
   263   {
       
   264     FT_UShort  push;
       
   265     FT_UShort  dontAdvance;
       
   266     FT_UShort  valueOffset;
       
   267     FT_UShort  kernAction;
       
   268     FT_UShort  kernValue;
       
   269 
       
   270     FT_UNUSED( state );
       
   271     FT_UNUSED( glyphOffset_p );
       
   272 
       
   273 
       
   274     push        = (FT_UShort)( ( flags >> 15 ) & 1      );
       
   275     dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1      );
       
   276     valueOffset = (FT_UShort)(   flags         & 0x3FFF );
       
   277 
       
   278     {
       
   279       GXV_kern_fmt1_StateOptRecData  vt_rec =
       
   280         (GXV_kern_fmt1_StateOptRecData)valid->statetable.optdata;
       
   281       FT_Bytes  p;
       
   282 
       
   283 
       
   284       if ( valueOffset < vt_rec->valueTable )
       
   285         FT_INVALID_OFFSET;
       
   286 
       
   287       p     = table + valueOffset;
       
   288       limit = table + vt_rec->valueTable + vt_rec->valueTable_length;
       
   289 
       
   290       GXV_LIMIT_CHECK( 2 + 2 );
       
   291       kernAction = FT_NEXT_USHORT( p );
       
   292       kernValue  = FT_NEXT_USHORT( p );
       
   293     }
       
   294   }
       
   295 
       
   296 
       
   297   static void
       
   298   gxv_kern_subtable_fmt1_validate( FT_Bytes       table,
       
   299                                    FT_Bytes       limit,
       
   300                                    GXV_Validator  valid )
       
   301   {
       
   302     FT_Bytes                   p = table;
       
   303     GXV_kern_fmt1_StateOptRec  vt_rec;
       
   304 
       
   305 
       
   306     GXV_NAME_ENTER( "kern subtable format 1" );
       
   307 
       
   308     valid->statetable.optdata =
       
   309       &vt_rec;
       
   310     valid->statetable.optdata_load_func =
       
   311       gxv_kern_subtable_fmt1_valueTable_load;
       
   312     valid->statetable.subtable_setup_func =
       
   313       gxv_kern_subtable_fmt1_subtable_setup;
       
   314     valid->statetable.entry_glyphoffset_fmt =
       
   315       GXV_GLYPHOFFSET_NONE;
       
   316     valid->statetable.entry_validate_func =
       
   317       gxv_kern_subtable_fmt1_entry_validate;
       
   318 
       
   319     gxv_StateTable_validate( p, limit, valid );
       
   320 
       
   321     GXV_EXIT;
       
   322   }
       
   323 
       
   324 
       
   325   /* ================ Data for Class-Based Subtables 2, 3 ================ */
       
   326 
       
   327   typedef enum  GXV_kern_ClassSpec_
       
   328   {
       
   329     GXV_KERN_CLS_L = 0,
       
   330     GXV_KERN_CLS_R
       
   331 
       
   332   } GXV_kern_ClassSpec;
       
   333 
       
   334 
       
   335   /* ============================= format 2 ============================== */
       
   336 
       
   337   /* ---------------------- format 2 specific data ----------------------- */
       
   338 
       
   339   typedef struct  GXV_kern_subtable_fmt2_DataRec_
       
   340   {
       
   341     FT_UShort         rowWidth;
       
   342     FT_UShort         array;
       
   343     FT_UShort         offset_min[2];
       
   344     FT_UShort         offset_max[2];
       
   345     const FT_String*  class_tag[2];
       
   346     GXV_odtect_Range  odtect;
       
   347 
       
   348   } GXV_kern_subtable_fmt2_DataRec, *GXV_kern_subtable_fmt2_Data;
       
   349 
       
   350 
       
   351 #define GXV_KERN_FMT2_DATA( field )                         \
       
   352         ( ( (GXV_kern_subtable_fmt2_DataRec *)              \
       
   353               ( GXV_KERN_DATA( subtable_data ) ) )->field )
       
   354 
       
   355 
       
   356   /* -------------------------- utility functions ----------------------- */
       
   357 
       
   358   static void
       
   359   gxv_kern_subtable_fmt2_clstbl_validate( FT_Bytes            table,
       
   360                                           FT_Bytes            limit,
       
   361                                           GXV_kern_ClassSpec  spec,
       
   362                                           GXV_Validator       valid )
       
   363   {
       
   364     const FT_String*  tag    = GXV_KERN_FMT2_DATA( class_tag[spec] );
       
   365     GXV_odtect_Range  odtect = GXV_KERN_FMT2_DATA( odtect );
       
   366 
       
   367     FT_Bytes   p = table;
       
   368     FT_UShort  firstGlyph;
       
   369     FT_UShort  nGlyphs;
       
   370 
       
   371 
       
   372     GXV_NAME_ENTER( "kern format 2 classTable" );
       
   373 
       
   374     GXV_LIMIT_CHECK( 2 + 2 );
       
   375     firstGlyph = FT_NEXT_USHORT( p );
       
   376     nGlyphs    = FT_NEXT_USHORT( p );
       
   377     GXV_TRACE(( " %s firstGlyph=%d, nGlyphs=%d\n",
       
   378                 tag, firstGlyph, nGlyphs ));
       
   379 
       
   380     gxv_glyphid_validate( firstGlyph, valid );
       
   381     gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs - 1 ), valid );
       
   382 
       
   383     gxv_array_getlimits_ushort( p, p + ( 2 * nGlyphs ),
       
   384                                 &( GXV_KERN_FMT2_DATA( offset_min[spec] ) ),
       
   385                                 &( GXV_KERN_FMT2_DATA( offset_max[spec] ) ),
       
   386                                 valid );
       
   387 
       
   388     gxv_odtect_add_range( table, 2 * nGlyphs, tag, odtect );
       
   389 
       
   390     GXV_EXIT;
       
   391   }
       
   392 
       
   393 
       
   394   static void
       
   395   gxv_kern_subtable_fmt2_validate( FT_Bytes       table,
       
   396                                    FT_Bytes       limit,
       
   397                                    GXV_Validator  valid )
       
   398   {
       
   399     GXV_ODTECT( 3, odtect );
       
   400     GXV_kern_subtable_fmt2_DataRec  fmt2_rec =
       
   401       { 0, 0, { 0, 0 }, { 0, 0 }, { "leftClass", "rightClass" }, NULL };
       
   402 
       
   403     FT_Bytes   p = table + GXV_KERN_SUBTABLE_HEADER_SIZE;
       
   404     FT_UShort  leftOffsetTable;
       
   405     FT_UShort  rightOffsetTable;
       
   406 
       
   407 
       
   408     GXV_NAME_ENTER( "kern subtable format 2" );
       
   409 
       
   410     GXV_ODTECT_INIT( odtect );
       
   411     fmt2_rec.odtect = odtect;
       
   412     GXV_KERN_DATA( subtable_data ) = &fmt2_rec;
       
   413 
       
   414     GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 );
       
   415     GXV_KERN_FMT2_DATA( rowWidth ) = FT_NEXT_USHORT( p );
       
   416     leftOffsetTable                = FT_NEXT_USHORT( p );
       
   417     rightOffsetTable               = FT_NEXT_USHORT( p );
       
   418     GXV_KERN_FMT2_DATA( array )    = FT_NEXT_USHORT( p );
       
   419 
       
   420     GXV_TRACE(( "rowWidth = %d\n", GXV_KERN_FMT2_DATA( rowWidth ) ));
       
   421 
       
   422 
       
   423     GXV_LIMIT_CHECK( leftOffsetTable );
       
   424     GXV_LIMIT_CHECK( rightOffsetTable );
       
   425     GXV_LIMIT_CHECK( GXV_KERN_FMT2_DATA( array ) );
       
   426 
       
   427     gxv_kern_subtable_fmt2_clstbl_validate( table + leftOffsetTable, limit,
       
   428                                             GXV_KERN_CLS_L, valid );
       
   429 
       
   430     gxv_kern_subtable_fmt2_clstbl_validate( table + rightOffsetTable, limit,
       
   431                                             GXV_KERN_CLS_R, valid );
       
   432 
       
   433     if ( GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_L] ) +
       
   434            GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_R] )
       
   435          < GXV_KERN_FMT2_DATA( array )                      )
       
   436       FT_INVALID_OFFSET;
       
   437 
       
   438     gxv_odtect_add_range( table + GXV_KERN_FMT2_DATA( array ),
       
   439                           GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_L] )
       
   440                             + GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_R] )
       
   441                             - GXV_KERN_FMT2_DATA( array ),
       
   442                           "array", odtect );
       
   443 
       
   444     gxv_odtect_validate( odtect, valid );
       
   445 
       
   446     GXV_EXIT;
       
   447   }
       
   448 
       
   449 
       
   450   /* ============================= format 3 ============================== */
       
   451 
       
   452   static void
       
   453   gxv_kern_subtable_fmt3_validate( FT_Bytes       table,
       
   454                                    FT_Bytes       limit,
       
   455                                    GXV_Validator  valid )
       
   456   {
       
   457     FT_Bytes   p = table + GXV_KERN_SUBTABLE_HEADER_SIZE;
       
   458     FT_UShort  glyphCount;
       
   459     FT_Byte    kernValueCount;
       
   460     FT_Byte    leftClassCount;
       
   461     FT_Byte    rightClassCount;
       
   462     FT_Byte    flags;
       
   463 
       
   464 
       
   465     GXV_NAME_ENTER( "kern subtable format 3" );
       
   466 
       
   467     GXV_LIMIT_CHECK( 2 + 1 + 1 + 1 + 1 );
       
   468     glyphCount      = FT_NEXT_USHORT( p );
       
   469     kernValueCount  = FT_NEXT_BYTE( p );
       
   470     leftClassCount  = FT_NEXT_BYTE( p );
       
   471     rightClassCount = FT_NEXT_BYTE( p );
       
   472     flags           = FT_NEXT_BYTE( p );
       
   473 
       
   474     if ( valid->face->num_glyphs != glyphCount )
       
   475     {
       
   476       GXV_TRACE(( "maxGID=%d, but glyphCount=%d\n",
       
   477                   valid->face->num_glyphs, glyphCount ));
       
   478       if ( valid->root->level >= FT_VALIDATE_PARANOID )
       
   479         FT_INVALID_GLYPH_ID;
       
   480     }
       
   481 
       
   482     /*
       
   483      * just skip kernValue[kernValueCount]
       
   484      */
       
   485     GXV_LIMIT_CHECK( 2 * kernValueCount );
       
   486     p += 2 * kernValueCount;
       
   487 
       
   488     /*
       
   489      * check leftClass[gid] < leftClassCount
       
   490      */
       
   491     {
       
   492       FT_Byte  min, max;
       
   493 
       
   494 
       
   495       GXV_LIMIT_CHECK( glyphCount );
       
   496       gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, valid );
       
   497       p += valid->subtable_length;
       
   498 
       
   499       if ( leftClassCount < max )
       
   500         FT_INVALID_DATA;
       
   501     }
       
   502 
       
   503     /*
       
   504      * check rightClass[gid] < rightClassCount
       
   505      */
       
   506     {
       
   507       FT_Byte  min, max;
       
   508 
       
   509 
       
   510       GXV_LIMIT_CHECK( glyphCount );
       
   511       gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, valid );
       
   512       p += valid->subtable_length;
       
   513 
       
   514       if ( rightClassCount < max )
       
   515         FT_INVALID_DATA;
       
   516     }
       
   517 
       
   518     /*
       
   519      * check kernIndex[i, j] < kernValueCount
       
   520      */
       
   521     {
       
   522       FT_UShort  i, j;
       
   523 
       
   524 
       
   525       for ( i = 0; i < leftClassCount; i++ )
       
   526       {
       
   527         for ( j = 0; j < rightClassCount; j++ )
       
   528         {
       
   529           GXV_LIMIT_CHECK( 1 );
       
   530           if ( kernValueCount < FT_NEXT_BYTE( p ) )
       
   531             FT_INVALID_OFFSET;
       
   532         }
       
   533       }
       
   534     }
       
   535 
       
   536     valid->subtable_length = p - table;
       
   537 
       
   538     GXV_EXIT;
       
   539   }
       
   540 
       
   541 
       
   542   static FT_Bool
       
   543   gxv_kern_coverage_new_apple_validate( FT_UShort      coverage,
       
   544                                         FT_UShort*     format,
       
   545                                         GXV_Validator  valid )
       
   546   {
       
   547     /* new Apple-dialect */
       
   548     FT_Bool  kernVertical;
       
   549     FT_Bool  kernCrossStream;
       
   550     FT_Bool  kernVariation;
       
   551 
       
   552     FT_UNUSED( valid );
       
   553 
       
   554 
       
   555     /* reserved bits = 0 */
       
   556     if ( coverage & 0x1FFC )
       
   557       return 0;
       
   558 
       
   559     kernVertical    = FT_BOOL( ( coverage >> 15 ) & 1 );
       
   560     kernCrossStream = FT_BOOL( ( coverage >> 14 ) & 1 );
       
   561     kernVariation   = FT_BOOL( ( coverage >> 13 ) & 1 );
       
   562 
       
   563     *format = (FT_UShort)( coverage & 0x0003 );
       
   564 
       
   565     GXV_TRACE(( "new Apple-dialect: "
       
   566                 "horizontal=%d, cross-stream=%d, variation=%d, format=%d\n",
       
   567                  !kernVertical, kernCrossStream, kernVariation, *format ));
       
   568 
       
   569     GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" ));
       
   570 
       
   571     return 1;
       
   572   }
       
   573 
       
   574 
       
   575   static FT_Bool
       
   576   gxv_kern_coverage_classic_apple_validate( FT_UShort      coverage,
       
   577                                             FT_UShort*     format,
       
   578                                             GXV_Validator  valid )
       
   579   {
       
   580     /* classic Apple-dialect */
       
   581     FT_Bool  horizontal;
       
   582     FT_Bool  cross_stream;
       
   583 
       
   584 
       
   585     /* check expected flags, but don't check if MS-dialect is impossible */
       
   586     if ( !( coverage & 0xFD00 ) && KERN_ALLOWS_MS( valid ) )
       
   587       return 0;
       
   588 
       
   589     /* reserved bits = 0 */
       
   590     if ( coverage & 0x02FC )
       
   591       return 0;
       
   592 
       
   593     horizontal   = FT_BOOL( ( coverage >> 15 ) & 1 );
       
   594     cross_stream = FT_BOOL( ( coverage >> 13 ) & 1 );
       
   595 
       
   596     *format = (FT_UShort)( coverage & 0x0003 );
       
   597 
       
   598     GXV_TRACE(( "classic Apple-dialect: "
       
   599                 "horizontal=%d, cross-stream=%d, format=%d\n",
       
   600                  horizontal, cross_stream, *format ));
       
   601 
       
   602     /* format 1 requires GX State Machine, too new for classic */
       
   603     if ( *format == 1 )
       
   604       return 0;
       
   605 
       
   606     GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" ));
       
   607 
       
   608     return 1;
       
   609   }
       
   610 
       
   611 
       
   612   static FT_Bool
       
   613   gxv_kern_coverage_classic_microsoft_validate( FT_UShort      coverage,
       
   614                                                 FT_UShort*     format,
       
   615                                                 GXV_Validator  valid )
       
   616   {
       
   617     /* classic Microsoft-dialect */
       
   618     FT_Bool  horizontal;
       
   619     FT_Bool  minimum;
       
   620     FT_Bool  cross_stream;
       
   621     FT_Bool  override;
       
   622 
       
   623     FT_UNUSED( valid );
       
   624 
       
   625 
       
   626     /* reserved bits = 0 */
       
   627     if ( coverage & 0xFDF0 )
       
   628       return 0;
       
   629 
       
   630     horizontal   = FT_BOOL(   coverage        & 1 );
       
   631     minimum      = FT_BOOL( ( coverage >> 1 ) & 1 );
       
   632     cross_stream = FT_BOOL( ( coverage >> 2 ) & 1 );
       
   633     override     = FT_BOOL( ( coverage >> 3 ) & 1 );
       
   634 
       
   635     *format = (FT_UShort)( ( coverage >> 8 ) & 0x0003 );
       
   636 
       
   637     GXV_TRACE(( "classic Microsoft-dialect: "
       
   638                 "horizontal=%d, minimum=%d, cross-stream=%d, "
       
   639                 "override=%d, format=%d\n",
       
   640                 horizontal, minimum, cross_stream, override, *format ));
       
   641 
       
   642     if ( *format == 2 )
       
   643       GXV_TRACE((
       
   644         "kerning values in Microsoft format 2 subtable are ignored\n" ));
       
   645 
       
   646     return 1;
       
   647   }
       
   648 
       
   649 
       
   650   /*************************************************************************/
       
   651   /*************************************************************************/
       
   652   /*****                                                               *****/
       
   653   /*****                            MAIN                               *****/
       
   654   /*****                                                               *****/
       
   655   /*************************************************************************/
       
   656   /*************************************************************************/
       
   657 
       
   658   static GXV_kern_Dialect
       
   659   gxv_kern_coverage_validate( FT_UShort      coverage,
       
   660                               FT_UShort*     format,
       
   661                               GXV_Validator  valid )
       
   662   {
       
   663     GXV_kern_Dialect  result = KERN_DIALECT_UNKNOWN;
       
   664 
       
   665 
       
   666     GXV_NAME_ENTER( "validating coverage" );
       
   667 
       
   668     GXV_TRACE(( "interprete coverage 0x%04x by Apple style\n", coverage ));
       
   669 
       
   670     if ( KERN_IS_NEW( valid ) )
       
   671     {
       
   672       if ( gxv_kern_coverage_new_apple_validate( coverage,
       
   673                                                  format,
       
   674                                                  valid ) )
       
   675       {
       
   676         result = KERN_DIALECT_APPLE;
       
   677         goto Exit;
       
   678       }
       
   679     }
       
   680 
       
   681     if ( KERN_IS_CLASSIC( valid ) && KERN_ALLOWS_APPLE( valid ) )
       
   682     {
       
   683       if ( gxv_kern_coverage_classic_apple_validate( coverage,
       
   684                                                      format,
       
   685                                                      valid ) )
       
   686       {
       
   687         result = KERN_DIALECT_APPLE;
       
   688         goto Exit;
       
   689       }
       
   690     }
       
   691 
       
   692     if ( KERN_IS_CLASSIC( valid ) && KERN_ALLOWS_MS( valid ) )
       
   693     {
       
   694       if ( gxv_kern_coverage_classic_microsoft_validate( coverage,
       
   695                                                          format,
       
   696                                                          valid ) )
       
   697       {
       
   698         result = KERN_DIALECT_MS;
       
   699         goto Exit;
       
   700       }
       
   701     }
       
   702 
       
   703     GXV_TRACE(( "cannot interprete coverage, broken kern subtable\n" ));
       
   704 
       
   705   Exit:
       
   706     GXV_EXIT;
       
   707     return result;
       
   708   }
       
   709 
       
   710 
       
   711   static void
       
   712   gxv_kern_subtable_validate( FT_Bytes       table,
       
   713                               FT_Bytes       limit,
       
   714                               GXV_Validator  valid )
       
   715   {
       
   716     FT_Bytes   p = table;
       
   717     FT_UShort  version = 0;    /* MS only: subtable version, unused */
       
   718     FT_ULong   length;         /* MS: 16bit, Apple: 32bit*/
       
   719     FT_UShort  coverage;
       
   720     FT_UShort  tupleIndex = 0; /* Apple only */
       
   721     FT_UShort  u16[2];
       
   722     FT_UShort  format = 255;   /* subtable format */
       
   723 
       
   724 
       
   725     GXV_NAME_ENTER( "kern subtable" );
       
   726 
       
   727     GXV_LIMIT_CHECK( 2 + 2 + 2 );
       
   728     u16[0]   = FT_NEXT_USHORT( p ); /* Apple: length_hi MS: version */
       
   729     u16[1]   = FT_NEXT_USHORT( p ); /* Apple: length_lo MS: length */
       
   730     coverage = FT_NEXT_USHORT( p );
       
   731 
       
   732     switch ( gxv_kern_coverage_validate( coverage, &format, valid ) )
       
   733     {
       
   734     case KERN_DIALECT_MS:
       
   735       version    = u16[0];
       
   736       length     = u16[1];
       
   737       tupleIndex = 0;
       
   738       GXV_TRACE(( "Subtable version = %d\n", version ));
       
   739       GXV_TRACE(( "Subtable length = %d\n", length ));
       
   740       break;
       
   741 
       
   742     case KERN_DIALECT_APPLE:
       
   743       version    = 0;
       
   744       length     = ( u16[0] << 16 ) + u16[1];
       
   745       tupleIndex = 0;
       
   746       GXV_TRACE(( "Subtable length = %d\n", length ));
       
   747 
       
   748       if ( KERN_IS_NEW( valid ) )
       
   749       {
       
   750         GXV_LIMIT_CHECK( 2 );
       
   751         tupleIndex = FT_NEXT_USHORT( p );
       
   752         GXV_TRACE(( "Subtable tupleIndex = %d\n", tupleIndex ));
       
   753       }
       
   754       break;
       
   755 
       
   756     default:
       
   757       length = u16[1];
       
   758       GXV_TRACE(( "cannot detect subtable dialect, "
       
   759                   "just skip %d byte\n", length ));
       
   760       goto Exit;
       
   761     }
       
   762 
       
   763     /* formats 1, 2, 3 require the position of the start of this subtable */
       
   764     if ( format == 0 )
       
   765       gxv_kern_subtable_fmt0_validate( table, table + length, valid );
       
   766     else if ( format == 1 )
       
   767       gxv_kern_subtable_fmt1_validate( table, table + length, valid );
       
   768     else if ( format == 2 )
       
   769       gxv_kern_subtable_fmt2_validate( table, table + length, valid );
       
   770     else if ( format == 3 )
       
   771       gxv_kern_subtable_fmt3_validate( table, table + length, valid );
       
   772     else
       
   773       FT_INVALID_DATA;
       
   774 
       
   775   Exit:
       
   776     valid->subtable_length = length;
       
   777     GXV_EXIT;
       
   778   }
       
   779 
       
   780 
       
   781   /*************************************************************************/
       
   782   /*************************************************************************/
       
   783   /*****                                                               *****/
       
   784   /*****                         kern TABLE                            *****/
       
   785   /*****                                                               *****/
       
   786   /*************************************************************************/
       
   787   /*************************************************************************/
       
   788 
       
   789   static void
       
   790   gxv_kern_validate_generic( FT_Bytes          table,
       
   791                              FT_Face           face,
       
   792                              FT_Bool           classic_only,
       
   793                              GXV_kern_Dialect  dialect_request,
       
   794                              FT_Validator      ftvalid )
       
   795   {
       
   796     GXV_ValidatorRec   validrec;
       
   797     GXV_Validator      valid = &validrec;
       
   798 
       
   799     GXV_kern_DataRec   kernrec;
       
   800     GXV_kern_Data      kern = &kernrec;
       
   801 
       
   802     FT_Bytes           p     = table;
       
   803     FT_Bytes           limit = 0;
       
   804 
       
   805     FT_ULong           nTables = 0;
       
   806     FT_UInt            i;
       
   807 
       
   808 
       
   809     valid->root       = ftvalid;
       
   810     valid->table_data = kern;
       
   811     valid->face       = face;
       
   812 
       
   813     FT_TRACE3(( "validating `kern' table\n" ));
       
   814     GXV_INIT;
       
   815     KERN_DIALECT( valid ) = dialect_request;
       
   816 
       
   817     GXV_LIMIT_CHECK( 2 );
       
   818     GXV_KERN_DATA( version ) = (GXV_kern_Version)FT_NEXT_USHORT( p );
       
   819     GXV_TRACE(( "version 0x%04x (higher 16bit)\n",
       
   820                 GXV_KERN_DATA( version ) ));
       
   821 
       
   822     if ( 0x0001 < GXV_KERN_DATA( version ) )
       
   823       FT_INVALID_FORMAT;
       
   824     else if ( KERN_IS_CLASSIC( valid ) )
       
   825     {
       
   826       GXV_LIMIT_CHECK( 2 );
       
   827       nTables = FT_NEXT_USHORT( p );
       
   828     }
       
   829     else if ( KERN_IS_NEW( valid ) )
       
   830     {
       
   831       if ( classic_only )
       
   832         FT_INVALID_FORMAT;
       
   833 
       
   834       if ( 0x0000 != FT_NEXT_USHORT( p ) )
       
   835         FT_INVALID_FORMAT;
       
   836 
       
   837       GXV_LIMIT_CHECK( 4 );
       
   838       nTables = FT_NEXT_ULONG( p );
       
   839     }
       
   840 
       
   841     for ( i = 0; i < nTables; i++ )
       
   842     {
       
   843       GXV_TRACE(( "validating subtable %d/%d\n", i, nTables ));
       
   844       /* p should be 32bit-aligned? */
       
   845       gxv_kern_subtable_validate( p, 0, valid );
       
   846       p += valid->subtable_length;
       
   847     }
       
   848 
       
   849     FT_TRACE4(( "\n" ));
       
   850   }
       
   851 
       
   852 
       
   853   FT_LOCAL_DEF( void )
       
   854   gxv_kern_validate( FT_Bytes      table,
       
   855                      FT_Face       face,
       
   856                      FT_Validator  ftvalid )
       
   857   {
       
   858     gxv_kern_validate_generic( table, face, 0, KERN_DIALECT_ANY, ftvalid );
       
   859   }
       
   860 
       
   861 
       
   862   FT_LOCAL_DEF( void )
       
   863   gxv_kern_validate_classic( FT_Bytes      table,
       
   864                              FT_Face       face,
       
   865                              FT_Int        dialect_flags,
       
   866                              FT_Validator  ftvalid )
       
   867   {
       
   868     GXV_kern_Dialect  dialect_request;
       
   869 
       
   870 
       
   871     dialect_request = (GXV_kern_Dialect)dialect_flags;
       
   872     gxv_kern_validate_generic( table, face, 1, dialect_request, ftvalid );
       
   873   }
       
   874 
       
   875 
       
   876 /* END */