misc/libfreetype/src/otvalid/otvgpos.c
branchwebgl
changeset 9521 8054d9d775fd
parent 9282 92af50454cf2
parent 9519 b8b5c82eb61b
child 9950 2759212a27de
equal deleted inserted replaced
9282:92af50454cf2 9521:8054d9d775fd
     1 /***************************************************************************/
       
     2 /*                                                                         */
       
     3 /*  otvgpos.c                                                              */
       
     4 /*                                                                         */
       
     5 /*    OpenType GPOS table validation (body).                               */
       
     6 /*                                                                         */
       
     7 /*  Copyright 2002, 2004, 2005, 2006, 2007, 2008 by                        */
       
     8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
       
     9 /*                                                                         */
       
    10 /*  This file is part of the FreeType project, and may only be used,       */
       
    11 /*  modified, and distributed under the terms of the FreeType project      */
       
    12 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
       
    13 /*  this file you indicate that you have read the license and              */
       
    14 /*  understand and accept it fully.                                        */
       
    15 /*                                                                         */
       
    16 /***************************************************************************/
       
    17 
       
    18 
       
    19 #include "otvalid.h"
       
    20 #include "otvcommn.h"
       
    21 #include "otvgpos.h"
       
    22 
       
    23 
       
    24   /*************************************************************************/
       
    25   /*                                                                       */
       
    26   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
       
    27   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
       
    28   /* messages during execution.                                            */
       
    29   /*                                                                       */
       
    30 #undef  FT_COMPONENT
       
    31 #define FT_COMPONENT  trace_otvgpos
       
    32 
       
    33 
       
    34   static void
       
    35   otv_Anchor_validate( FT_Bytes       table,
       
    36                        OTV_Validator  valid );
       
    37 
       
    38   static void
       
    39   otv_MarkArray_validate( FT_Bytes       table,
       
    40                           OTV_Validator  valid );
       
    41 
       
    42 
       
    43   /*************************************************************************/
       
    44   /*************************************************************************/
       
    45   /*****                                                               *****/
       
    46   /*****                      UTILITY FUNCTIONS                        *****/
       
    47   /*****                                                               *****/
       
    48   /*************************************************************************/
       
    49   /*************************************************************************/
       
    50 
       
    51 #define BaseArrayFunc       otv_x_sxy
       
    52 #define LigatureAttachFunc  otv_x_sxy
       
    53 #define Mark2ArrayFunc      otv_x_sxy
       
    54 
       
    55   /* uses valid->extra1 (counter)                             */
       
    56   /* uses valid->extra2 (boolean to handle NULL anchor field) */
       
    57 
       
    58   static void
       
    59   otv_x_sxy( FT_Bytes       table,
       
    60              OTV_Validator  valid )
       
    61   {
       
    62     FT_Bytes  p = table;
       
    63     FT_UInt   Count, count1, table_size;
       
    64 
       
    65 
       
    66     OTV_ENTER;
       
    67 
       
    68     OTV_LIMIT_CHECK( 2 );
       
    69 
       
    70     Count = FT_NEXT_USHORT( p );
       
    71 
       
    72     OTV_TRACE(( " (Count = %d)\n", Count ));
       
    73 
       
    74     OTV_LIMIT_CHECK( Count * valid->extra1 * 2 );
       
    75 
       
    76     table_size = Count * valid->extra1 * 2 + 2;
       
    77 
       
    78     for ( ; Count > 0; Count-- )
       
    79       for ( count1 = valid->extra1; count1 > 0; count1-- )
       
    80       {
       
    81         OTV_OPTIONAL_TABLE( anchor_offset );
       
    82 
       
    83 
       
    84         OTV_OPTIONAL_OFFSET( anchor_offset );
       
    85 
       
    86         if ( valid->extra2 )
       
    87         {
       
    88           OTV_SIZE_CHECK( anchor_offset );
       
    89           if ( anchor_offset )
       
    90             otv_Anchor_validate( table + anchor_offset, valid );
       
    91         }
       
    92         else
       
    93           otv_Anchor_validate( table + anchor_offset, valid );
       
    94       }
       
    95 
       
    96     OTV_EXIT;
       
    97   }
       
    98 
       
    99 
       
   100 #define MarkBasePosFormat1Func  otv_u_O_O_u_O_O
       
   101 #define MarkLigPosFormat1Func   otv_u_O_O_u_O_O
       
   102 #define MarkMarkPosFormat1Func  otv_u_O_O_u_O_O
       
   103 
       
   104   /* sets valid->extra1 (class count) */
       
   105 
       
   106   static void
       
   107   otv_u_O_O_u_O_O( FT_Bytes       table,
       
   108                    OTV_Validator  valid )
       
   109   {
       
   110     FT_Bytes           p = table;
       
   111     FT_UInt            Coverage1, Coverage2, ClassCount;
       
   112     FT_UInt            Array1, Array2;
       
   113     OTV_Validate_Func  func;
       
   114 
       
   115 
       
   116     OTV_ENTER;
       
   117 
       
   118     p += 2;     /* skip PosFormat */
       
   119 
       
   120     OTV_LIMIT_CHECK( 10 );
       
   121     Coverage1  = FT_NEXT_USHORT( p );
       
   122     Coverage2  = FT_NEXT_USHORT( p );
       
   123     ClassCount = FT_NEXT_USHORT( p );
       
   124     Array1     = FT_NEXT_USHORT( p );
       
   125     Array2     = FT_NEXT_USHORT( p );
       
   126 
       
   127     otv_Coverage_validate( table + Coverage1, valid, -1 );
       
   128     otv_Coverage_validate( table + Coverage2, valid, -1 );
       
   129 
       
   130     otv_MarkArray_validate( table + Array1, valid );
       
   131 
       
   132     valid->nesting_level++;
       
   133     func          = valid->func[valid->nesting_level];
       
   134     valid->extra1 = ClassCount;
       
   135 
       
   136     func( table + Array2, valid );
       
   137 
       
   138     valid->nesting_level--;
       
   139 
       
   140     OTV_EXIT;
       
   141   }
       
   142 
       
   143 
       
   144   /*************************************************************************/
       
   145   /*************************************************************************/
       
   146   /*****                                                               *****/
       
   147   /*****                        VALUE RECORDS                          *****/
       
   148   /*****                                                               *****/
       
   149   /*************************************************************************/
       
   150   /*************************************************************************/
       
   151 
       
   152   static FT_UInt
       
   153   otv_value_length( FT_UInt  format )
       
   154   {
       
   155     FT_UInt  count;
       
   156 
       
   157 
       
   158     count = ( ( format & 0xAA ) >> 1 ) + ( format & 0x55 );
       
   159     count = ( ( count  & 0xCC ) >> 2 ) + ( count  & 0x33 );
       
   160     count = ( ( count  & 0xF0 ) >> 4 ) + ( count  & 0x0F );
       
   161 
       
   162     return count * 2;
       
   163   }
       
   164 
       
   165 
       
   166   /* uses valid->extra3 (pointer to base table) */
       
   167 
       
   168   static void
       
   169   otv_ValueRecord_validate( FT_Bytes       table,
       
   170                             FT_UInt        format,
       
   171                             OTV_Validator  valid )
       
   172   {
       
   173     FT_Bytes  p = table;
       
   174     FT_UInt   count;
       
   175 
       
   176 #ifdef FT_DEBUG_LEVEL_TRACE
       
   177     FT_Int    loop;
       
   178     FT_ULong  res = 0;
       
   179 
       
   180 
       
   181     OTV_NAME_ENTER( "ValueRecord" );
       
   182 
       
   183     /* display `format' in dual representation */
       
   184     for ( loop = 7; loop >= 0; loop-- )
       
   185     {
       
   186       res <<= 4;
       
   187       res  += ( format >> loop ) & 1;
       
   188     }
       
   189 
       
   190     OTV_TRACE(( " (format 0b%08lx)\n", res ));
       
   191 #endif
       
   192 
       
   193     if ( format >= 0x100 )
       
   194       FT_INVALID_FORMAT;
       
   195 
       
   196     for ( count = 4; count > 0; count-- )
       
   197     {
       
   198       if ( format & 1 )
       
   199       {
       
   200         /* XPlacement, YPlacement, XAdvance, YAdvance */
       
   201         OTV_LIMIT_CHECK( 2 );
       
   202         p += 2;
       
   203       }
       
   204 
       
   205       format >>= 1;
       
   206     }
       
   207 
       
   208     for ( count = 4; count > 0; count-- )
       
   209     {
       
   210       if ( format & 1 )
       
   211       {
       
   212         FT_PtrDist  table_size;
       
   213 
       
   214         OTV_OPTIONAL_TABLE( device );
       
   215 
       
   216 
       
   217         /* XPlaDevice, YPlaDevice, XAdvDevice, YAdvDevice */
       
   218         OTV_LIMIT_CHECK( 2 );
       
   219         OTV_OPTIONAL_OFFSET( device );
       
   220 
       
   221         /* XXX: this value is usually too small, especially if the current */
       
   222         /* ValueRecord is part of an array -- getting the correct table    */
       
   223         /* size is probably not worth the trouble                          */
       
   224 
       
   225         table_size = p - valid->extra3;
       
   226 
       
   227         OTV_SIZE_CHECK( device );
       
   228         if ( device )
       
   229           otv_Device_validate( valid->extra3 + device, valid );
       
   230       }
       
   231       format >>= 1;
       
   232     }
       
   233 
       
   234     OTV_EXIT;
       
   235   }
       
   236 
       
   237 
       
   238   /*************************************************************************/
       
   239   /*************************************************************************/
       
   240   /*****                                                               *****/
       
   241   /*****                           ANCHORS                             *****/
       
   242   /*****                                                               *****/
       
   243   /*************************************************************************/
       
   244   /*************************************************************************/
       
   245 
       
   246   static void
       
   247   otv_Anchor_validate( FT_Bytes       table,
       
   248                        OTV_Validator  valid )
       
   249   {
       
   250     FT_Bytes  p = table;
       
   251     FT_UInt   AnchorFormat;
       
   252 
       
   253 
       
   254     OTV_NAME_ENTER( "Anchor");
       
   255 
       
   256     OTV_LIMIT_CHECK( 6 );
       
   257     AnchorFormat = FT_NEXT_USHORT( p );
       
   258 
       
   259     OTV_TRACE(( " (format %d)\n", AnchorFormat ));
       
   260 
       
   261     p += 4;     /* skip XCoordinate and YCoordinate */
       
   262 
       
   263     switch ( AnchorFormat )
       
   264     {
       
   265     case 1:
       
   266       break;
       
   267 
       
   268     case 2:
       
   269       OTV_LIMIT_CHECK( 2 );  /* AnchorPoint */
       
   270       break;
       
   271 
       
   272     case 3:
       
   273       {
       
   274         FT_UInt   table_size;
       
   275 
       
   276         OTV_OPTIONAL_TABLE( XDeviceTable );
       
   277         OTV_OPTIONAL_TABLE( YDeviceTable );
       
   278 
       
   279 
       
   280         OTV_LIMIT_CHECK( 4 );
       
   281         OTV_OPTIONAL_OFFSET( XDeviceTable );
       
   282         OTV_OPTIONAL_OFFSET( YDeviceTable );
       
   283 
       
   284         table_size = 6 + 4;
       
   285 
       
   286         OTV_SIZE_CHECK( XDeviceTable );
       
   287         if ( XDeviceTable )
       
   288           otv_Device_validate( table + XDeviceTable, valid );
       
   289 
       
   290         OTV_SIZE_CHECK( YDeviceTable );
       
   291         if ( YDeviceTable )
       
   292           otv_Device_validate( table + YDeviceTable, valid );
       
   293       }
       
   294       break;
       
   295 
       
   296     default:
       
   297       FT_INVALID_FORMAT;
       
   298     }
       
   299 
       
   300     OTV_EXIT;
       
   301   }
       
   302 
       
   303 
       
   304   /*************************************************************************/
       
   305   /*************************************************************************/
       
   306   /*****                                                               *****/
       
   307   /*****                         MARK ARRAYS                           *****/
       
   308   /*****                                                               *****/
       
   309   /*************************************************************************/
       
   310   /*************************************************************************/
       
   311 
       
   312   static void
       
   313   otv_MarkArray_validate( FT_Bytes       table,
       
   314                           OTV_Validator  valid )
       
   315   {
       
   316     FT_Bytes  p = table;
       
   317     FT_UInt   MarkCount;
       
   318 
       
   319 
       
   320     OTV_NAME_ENTER( "MarkArray" );
       
   321 
       
   322     OTV_LIMIT_CHECK( 2 );
       
   323     MarkCount = FT_NEXT_USHORT( p );
       
   324 
       
   325     OTV_TRACE(( " (MarkCount = %d)\n", MarkCount ));
       
   326 
       
   327     OTV_LIMIT_CHECK( MarkCount * 4 );
       
   328 
       
   329     /* MarkRecord */
       
   330     for ( ; MarkCount > 0; MarkCount-- )
       
   331     {
       
   332       p += 2;   /* skip Class */
       
   333       /* MarkAnchor */
       
   334       otv_Anchor_validate( table + FT_NEXT_USHORT( p ), valid );
       
   335     }
       
   336 
       
   337     OTV_EXIT;
       
   338   }
       
   339 
       
   340 
       
   341   /*************************************************************************/
       
   342   /*************************************************************************/
       
   343   /*****                                                               *****/
       
   344   /*****                     GPOS LOOKUP TYPE 1                        *****/
       
   345   /*****                                                               *****/
       
   346   /*************************************************************************/
       
   347   /*************************************************************************/
       
   348 
       
   349   /* sets valid->extra3 (pointer to base table) */
       
   350 
       
   351   static void
       
   352   otv_SinglePos_validate( FT_Bytes       table,
       
   353                           OTV_Validator  valid )
       
   354   {
       
   355     FT_Bytes  p = table;
       
   356     FT_UInt   PosFormat;
       
   357 
       
   358 
       
   359     OTV_NAME_ENTER( "SinglePos" );
       
   360 
       
   361     OTV_LIMIT_CHECK( 2 );
       
   362     PosFormat = FT_NEXT_USHORT( p );
       
   363 
       
   364     OTV_TRACE(( " (format %d)\n", PosFormat ));
       
   365 
       
   366     valid->extra3 = table;
       
   367 
       
   368     switch ( PosFormat )
       
   369     {
       
   370     case 1:     /* SinglePosFormat1 */
       
   371       {
       
   372         FT_UInt  Coverage, ValueFormat;
       
   373 
       
   374 
       
   375         OTV_LIMIT_CHECK( 4 );
       
   376         Coverage    = FT_NEXT_USHORT( p );
       
   377         ValueFormat = FT_NEXT_USHORT( p );
       
   378 
       
   379         otv_Coverage_validate( table + Coverage, valid, -1 );
       
   380         otv_ValueRecord_validate( p, ValueFormat, valid ); /* Value */
       
   381       }
       
   382       break;
       
   383 
       
   384     case 2:     /* SinglePosFormat2 */
       
   385       {
       
   386         FT_UInt  Coverage, ValueFormat, ValueCount, len_value;
       
   387 
       
   388 
       
   389         OTV_LIMIT_CHECK( 6 );
       
   390         Coverage    = FT_NEXT_USHORT( p );
       
   391         ValueFormat = FT_NEXT_USHORT( p );
       
   392         ValueCount  = FT_NEXT_USHORT( p );
       
   393 
       
   394         OTV_TRACE(( " (ValueCount = %d)\n", ValueCount ));
       
   395 
       
   396         len_value = otv_value_length( ValueFormat );
       
   397 
       
   398         otv_Coverage_validate( table + Coverage, valid, ValueCount );
       
   399 
       
   400         OTV_LIMIT_CHECK( ValueCount * len_value );
       
   401 
       
   402         /* Value */
       
   403         for ( ; ValueCount > 0; ValueCount-- )
       
   404         {
       
   405           otv_ValueRecord_validate( p, ValueFormat, valid );
       
   406           p += len_value;
       
   407         }
       
   408       }
       
   409       break;
       
   410 
       
   411     default:
       
   412       FT_INVALID_FORMAT;
       
   413     }
       
   414 
       
   415     OTV_EXIT;
       
   416   }
       
   417 
       
   418 
       
   419   /*************************************************************************/
       
   420   /*************************************************************************/
       
   421   /*****                                                               *****/
       
   422   /*****                     GPOS LOOKUP TYPE 2                        *****/
       
   423   /*****                                                               *****/
       
   424   /*************************************************************************/
       
   425   /*************************************************************************/
       
   426 
       
   427   static void
       
   428   otv_PairSet_validate( FT_Bytes       table,
       
   429                         FT_UInt        format1,
       
   430                         FT_UInt        format2,
       
   431                         OTV_Validator  valid )
       
   432   {
       
   433     FT_Bytes  p = table;
       
   434     FT_UInt   value_len1, value_len2, PairValueCount;
       
   435 
       
   436 
       
   437     OTV_NAME_ENTER( "PairSet" );
       
   438 
       
   439     OTV_LIMIT_CHECK( 2 );
       
   440     PairValueCount = FT_NEXT_USHORT( p );
       
   441 
       
   442     OTV_TRACE(( " (PairValueCount = %d)\n", PairValueCount ));
       
   443 
       
   444     value_len1 = otv_value_length( format1 );
       
   445     value_len2 = otv_value_length( format2 );
       
   446 
       
   447     OTV_LIMIT_CHECK( PairValueCount * ( value_len1 + value_len2 + 2 ) );
       
   448 
       
   449     /* PairValueRecord */
       
   450     for ( ; PairValueCount > 0; PairValueCount-- )
       
   451     {
       
   452       p += 2;       /* skip SecondGlyph */
       
   453 
       
   454       if ( format1 )
       
   455         otv_ValueRecord_validate( p, format1, valid ); /* Value1 */
       
   456       p += value_len1;
       
   457 
       
   458       if ( format2 )
       
   459         otv_ValueRecord_validate( p, format2, valid ); /* Value2 */
       
   460       p += value_len2;
       
   461     }
       
   462 
       
   463     OTV_EXIT;
       
   464   }
       
   465 
       
   466 
       
   467   /* sets valid->extra3 (pointer to base table) */
       
   468 
       
   469   static void
       
   470   otv_PairPos_validate( FT_Bytes       table,
       
   471                         OTV_Validator  valid )
       
   472   {
       
   473     FT_Bytes  p = table;
       
   474     FT_UInt   PosFormat;
       
   475 
       
   476 
       
   477     OTV_NAME_ENTER( "PairPos" );
       
   478 
       
   479     OTV_LIMIT_CHECK( 2 );
       
   480     PosFormat = FT_NEXT_USHORT( p );
       
   481 
       
   482     OTV_TRACE(( " (format %d)\n", PosFormat ));
       
   483 
       
   484     valid->extra3 = table;
       
   485 
       
   486     switch ( PosFormat )
       
   487     {
       
   488     case 1:     /* PairPosFormat1 */
       
   489       {
       
   490         FT_UInt  Coverage, ValueFormat1, ValueFormat2, PairSetCount;
       
   491 
       
   492 
       
   493         OTV_LIMIT_CHECK( 8 );
       
   494         Coverage     = FT_NEXT_USHORT( p );
       
   495         ValueFormat1 = FT_NEXT_USHORT( p );
       
   496         ValueFormat2 = FT_NEXT_USHORT( p );
       
   497         PairSetCount = FT_NEXT_USHORT( p );
       
   498 
       
   499         OTV_TRACE(( " (PairSetCount = %d)\n", PairSetCount ));
       
   500 
       
   501         otv_Coverage_validate( table + Coverage, valid, -1 );
       
   502 
       
   503         OTV_LIMIT_CHECK( PairSetCount * 2 );
       
   504 
       
   505         /* PairSetOffset */
       
   506         for ( ; PairSetCount > 0; PairSetCount-- )
       
   507           otv_PairSet_validate( table + FT_NEXT_USHORT( p ),
       
   508                                 ValueFormat1, ValueFormat2, valid );
       
   509       }
       
   510       break;
       
   511 
       
   512     case 2:     /* PairPosFormat2 */
       
   513       {
       
   514         FT_UInt  Coverage, ValueFormat1, ValueFormat2, ClassDef1, ClassDef2;
       
   515         FT_UInt  ClassCount1, ClassCount2, len_value1, len_value2, count;
       
   516 
       
   517 
       
   518         OTV_LIMIT_CHECK( 14 );
       
   519         Coverage     = FT_NEXT_USHORT( p );
       
   520         ValueFormat1 = FT_NEXT_USHORT( p );
       
   521         ValueFormat2 = FT_NEXT_USHORT( p );
       
   522         ClassDef1    = FT_NEXT_USHORT( p );
       
   523         ClassDef2    = FT_NEXT_USHORT( p );
       
   524         ClassCount1  = FT_NEXT_USHORT( p );
       
   525         ClassCount2  = FT_NEXT_USHORT( p );
       
   526 
       
   527         OTV_TRACE(( " (ClassCount1 = %d)\n", ClassCount1 ));
       
   528         OTV_TRACE(( " (ClassCount2 = %d)\n", ClassCount2 ));
       
   529 
       
   530         len_value1 = otv_value_length( ValueFormat1 );
       
   531         len_value2 = otv_value_length( ValueFormat2 );
       
   532 
       
   533         otv_Coverage_validate( table + Coverage, valid, -1 );
       
   534         otv_ClassDef_validate( table + ClassDef1, valid );
       
   535         otv_ClassDef_validate( table + ClassDef2, valid );
       
   536 
       
   537         OTV_LIMIT_CHECK( ClassCount1 * ClassCount2 *
       
   538                      ( len_value1 + len_value2 ) );
       
   539 
       
   540         /* Class1Record */
       
   541         for ( ; ClassCount1 > 0; ClassCount1-- )
       
   542         {
       
   543           /* Class2Record */
       
   544           for ( count = ClassCount2; count > 0; count-- )
       
   545           {
       
   546             if ( ValueFormat1 )
       
   547               /* Value1 */
       
   548               otv_ValueRecord_validate( p, ValueFormat1, valid );
       
   549             p += len_value1;
       
   550 
       
   551             if ( ValueFormat2 )
       
   552               /* Value2 */
       
   553               otv_ValueRecord_validate( p, ValueFormat2, valid );
       
   554             p += len_value2;
       
   555           }
       
   556         }
       
   557       }
       
   558       break;
       
   559 
       
   560     default:
       
   561       FT_INVALID_FORMAT;
       
   562     }
       
   563 
       
   564     OTV_EXIT;
       
   565   }
       
   566 
       
   567 
       
   568   /*************************************************************************/
       
   569   /*************************************************************************/
       
   570   /*****                                                               *****/
       
   571   /*****                     GPOS LOOKUP TYPE 3                        *****/
       
   572   /*****                                                               *****/
       
   573   /*************************************************************************/
       
   574   /*************************************************************************/
       
   575 
       
   576   static void
       
   577   otv_CursivePos_validate( FT_Bytes       table,
       
   578                            OTV_Validator  valid )
       
   579   {
       
   580     FT_Bytes  p = table;
       
   581     FT_UInt   PosFormat;
       
   582 
       
   583 
       
   584     OTV_NAME_ENTER( "CursivePos" );
       
   585 
       
   586     OTV_LIMIT_CHECK( 2 );
       
   587     PosFormat = FT_NEXT_USHORT( p );
       
   588 
       
   589     OTV_TRACE(( " (format %d)\n", PosFormat ));
       
   590 
       
   591     switch ( PosFormat )
       
   592     {
       
   593     case 1:     /* CursivePosFormat1 */
       
   594       {
       
   595         FT_UInt   table_size;
       
   596         FT_UInt   Coverage, EntryExitCount;
       
   597 
       
   598         OTV_OPTIONAL_TABLE( EntryAnchor );
       
   599         OTV_OPTIONAL_TABLE( ExitAnchor  );
       
   600 
       
   601 
       
   602         OTV_LIMIT_CHECK( 4 );
       
   603         Coverage       = FT_NEXT_USHORT( p );
       
   604         EntryExitCount = FT_NEXT_USHORT( p );
       
   605 
       
   606         OTV_TRACE(( " (EntryExitCount = %d)\n", EntryExitCount ));
       
   607 
       
   608         otv_Coverage_validate( table + Coverage, valid, EntryExitCount );
       
   609 
       
   610         OTV_LIMIT_CHECK( EntryExitCount * 4 );
       
   611 
       
   612         table_size = EntryExitCount * 4 + 4;
       
   613 
       
   614         /* EntryExitRecord */
       
   615         for ( ; EntryExitCount > 0; EntryExitCount-- )
       
   616         {
       
   617           OTV_OPTIONAL_OFFSET( EntryAnchor );
       
   618           OTV_OPTIONAL_OFFSET( ExitAnchor  );
       
   619 
       
   620           OTV_SIZE_CHECK( EntryAnchor );
       
   621           if ( EntryAnchor )
       
   622             otv_Anchor_validate( table + EntryAnchor, valid );
       
   623 
       
   624           OTV_SIZE_CHECK( ExitAnchor );
       
   625           if ( ExitAnchor )
       
   626             otv_Anchor_validate( table + ExitAnchor, valid );
       
   627         }
       
   628       }
       
   629       break;
       
   630 
       
   631     default:
       
   632       FT_INVALID_FORMAT;
       
   633     }
       
   634 
       
   635     OTV_EXIT;
       
   636   }
       
   637 
       
   638 
       
   639   /*************************************************************************/
       
   640   /*************************************************************************/
       
   641   /*****                                                               *****/
       
   642   /*****                     GPOS LOOKUP TYPE 4                        *****/
       
   643   /*****                                                               *****/
       
   644   /*************************************************************************/
       
   645   /*************************************************************************/
       
   646 
       
   647   /* UNDOCUMENTED (in OpenType 1.5):              */
       
   648   /* BaseRecord tables can contain NULL pointers. */
       
   649 
       
   650   /* sets valid->extra2 (1) */
       
   651 
       
   652   static void
       
   653   otv_MarkBasePos_validate( FT_Bytes       table,
       
   654                             OTV_Validator  valid )
       
   655   {
       
   656     FT_Bytes  p = table;
       
   657     FT_UInt   PosFormat;
       
   658 
       
   659 
       
   660     OTV_NAME_ENTER( "MarkBasePos" );
       
   661 
       
   662     OTV_LIMIT_CHECK( 2 );
       
   663     PosFormat = FT_NEXT_USHORT( p );
       
   664 
       
   665     OTV_TRACE(( " (format %d)\n", PosFormat ));
       
   666 
       
   667     switch ( PosFormat )
       
   668     {
       
   669     case 1:
       
   670       valid->extra2 = 1;
       
   671       OTV_NEST2( MarkBasePosFormat1, BaseArray );
       
   672       OTV_RUN( table, valid );
       
   673       break;
       
   674 
       
   675     default:
       
   676       FT_INVALID_FORMAT;
       
   677     }
       
   678 
       
   679     OTV_EXIT;
       
   680   }
       
   681 
       
   682 
       
   683   /*************************************************************************/
       
   684   /*************************************************************************/
       
   685   /*****                                                               *****/
       
   686   /*****                     GPOS LOOKUP TYPE 5                        *****/
       
   687   /*****                                                               *****/
       
   688   /*************************************************************************/
       
   689   /*************************************************************************/
       
   690 
       
   691   /* sets valid->extra2 (1) */
       
   692 
       
   693   static void
       
   694   otv_MarkLigPos_validate( FT_Bytes       table,
       
   695                            OTV_Validator  valid )
       
   696   {
       
   697     FT_Bytes  p = table;
       
   698     FT_UInt   PosFormat;
       
   699 
       
   700 
       
   701     OTV_NAME_ENTER( "MarkLigPos" );
       
   702 
       
   703     OTV_LIMIT_CHECK( 2 );
       
   704     PosFormat = FT_NEXT_USHORT( p );
       
   705 
       
   706     OTV_TRACE(( " (format %d)\n", PosFormat ));
       
   707 
       
   708     switch ( PosFormat )
       
   709     {
       
   710     case 1:
       
   711       valid->extra2 = 1;
       
   712       OTV_NEST3( MarkLigPosFormat1, LigatureArray, LigatureAttach );
       
   713       OTV_RUN( table, valid );
       
   714       break;
       
   715 
       
   716     default:
       
   717       FT_INVALID_FORMAT;
       
   718     }
       
   719 
       
   720     OTV_EXIT;
       
   721   }
       
   722 
       
   723 
       
   724   /*************************************************************************/
       
   725   /*************************************************************************/
       
   726   /*****                                                               *****/
       
   727   /*****                     GPOS LOOKUP TYPE 6                        *****/
       
   728   /*****                                                               *****/
       
   729   /*************************************************************************/
       
   730   /*************************************************************************/
       
   731 
       
   732   /* sets valid->extra2 (0) */
       
   733 
       
   734   static void
       
   735   otv_MarkMarkPos_validate( FT_Bytes       table,
       
   736                             OTV_Validator  valid )
       
   737   {
       
   738     FT_Bytes  p = table;
       
   739     FT_UInt   PosFormat;
       
   740 
       
   741 
       
   742     OTV_NAME_ENTER( "MarkMarkPos" );
       
   743 
       
   744     OTV_LIMIT_CHECK( 2 );
       
   745     PosFormat = FT_NEXT_USHORT( p );
       
   746 
       
   747     OTV_TRACE(( " (format %d)\n", PosFormat ));
       
   748 
       
   749     switch ( PosFormat )
       
   750     {
       
   751     case 1:
       
   752       valid->extra2 = 0;
       
   753       OTV_NEST2( MarkMarkPosFormat1, Mark2Array );
       
   754       OTV_RUN( table, valid );
       
   755       break;
       
   756 
       
   757     default:
       
   758       FT_INVALID_FORMAT;
       
   759     }
       
   760 
       
   761     OTV_EXIT;
       
   762   }
       
   763 
       
   764 
       
   765   /*************************************************************************/
       
   766   /*************************************************************************/
       
   767   /*****                                                               *****/
       
   768   /*****                     GPOS LOOKUP TYPE 7                        *****/
       
   769   /*****                                                               *****/
       
   770   /*************************************************************************/
       
   771   /*************************************************************************/
       
   772 
       
   773   /* sets valid->extra1 (lookup count) */
       
   774 
       
   775   static void
       
   776   otv_ContextPos_validate( FT_Bytes       table,
       
   777                            OTV_Validator  valid )
       
   778   {
       
   779     FT_Bytes  p = table;
       
   780     FT_UInt   PosFormat;
       
   781 
       
   782 
       
   783     OTV_NAME_ENTER( "ContextPos" );
       
   784 
       
   785     OTV_LIMIT_CHECK( 2 );
       
   786     PosFormat = FT_NEXT_USHORT( p );
       
   787 
       
   788     OTV_TRACE(( " (format %d)\n", PosFormat ));
       
   789 
       
   790     switch ( PosFormat )
       
   791     {
       
   792     case 1:
       
   793       /* no need to check glyph indices/classes used as input for these */
       
   794       /* context rules since even invalid glyph indices/classes return  */
       
   795       /* meaningful results                                             */
       
   796 
       
   797       valid->extra1 = valid->lookup_count;
       
   798       OTV_NEST3( ContextPosFormat1, PosRuleSet, PosRule );
       
   799       OTV_RUN( table, valid );
       
   800       break;
       
   801 
       
   802     case 2:
       
   803       /* no need to check glyph indices/classes used as input for these */
       
   804       /* context rules since even invalid glyph indices/classes return  */
       
   805       /* meaningful results                                             */
       
   806 
       
   807       OTV_NEST3( ContextPosFormat2, PosClassSet, PosClassRule );
       
   808       OTV_RUN( table, valid );
       
   809       break;
       
   810 
       
   811     case 3:
       
   812       OTV_NEST1( ContextPosFormat3 );
       
   813       OTV_RUN( table, valid );
       
   814       break;
       
   815 
       
   816     default:
       
   817       FT_INVALID_FORMAT;
       
   818     }
       
   819 
       
   820     OTV_EXIT;
       
   821   }
       
   822 
       
   823 
       
   824   /*************************************************************************/
       
   825   /*************************************************************************/
       
   826   /*****                                                               *****/
       
   827   /*****                     GPOS LOOKUP TYPE 8                        *****/
       
   828   /*****                                                               *****/
       
   829   /*************************************************************************/
       
   830   /*************************************************************************/
       
   831 
       
   832   /* sets valid->extra1 (lookup count) */
       
   833 
       
   834   static void
       
   835   otv_ChainContextPos_validate( FT_Bytes       table,
       
   836                                 OTV_Validator  valid )
       
   837   {
       
   838     FT_Bytes  p = table;
       
   839     FT_UInt   PosFormat;
       
   840 
       
   841 
       
   842     OTV_NAME_ENTER( "ChainContextPos" );
       
   843 
       
   844     OTV_LIMIT_CHECK( 2 );
       
   845     PosFormat = FT_NEXT_USHORT( p );
       
   846 
       
   847     OTV_TRACE(( " (format %d)\n", PosFormat ));
       
   848 
       
   849     switch ( PosFormat )
       
   850     {
       
   851     case 1:
       
   852       /* no need to check glyph indices/classes used as input for these */
       
   853       /* context rules since even invalid glyph indices/classes return  */
       
   854       /* meaningful results                                             */
       
   855 
       
   856       valid->extra1 = valid->lookup_count;
       
   857       OTV_NEST3( ChainContextPosFormat1,
       
   858                  ChainPosRuleSet, ChainPosRule );
       
   859       OTV_RUN( table, valid );
       
   860       break;
       
   861 
       
   862     case 2:
       
   863       /* no need to check glyph indices/classes used as input for these */
       
   864       /* context rules since even invalid glyph indices/classes return  */
       
   865       /* meaningful results                                             */
       
   866 
       
   867       OTV_NEST3( ChainContextPosFormat2,
       
   868                  ChainPosClassSet, ChainPosClassRule );
       
   869       OTV_RUN( table, valid );
       
   870       break;
       
   871 
       
   872     case 3:
       
   873       OTV_NEST1( ChainContextPosFormat3 );
       
   874       OTV_RUN( table, valid );
       
   875       break;
       
   876 
       
   877     default:
       
   878       FT_INVALID_FORMAT;
       
   879     }
       
   880 
       
   881     OTV_EXIT;
       
   882   }
       
   883 
       
   884 
       
   885   /*************************************************************************/
       
   886   /*************************************************************************/
       
   887   /*****                                                               *****/
       
   888   /*****                     GPOS LOOKUP TYPE 9                        *****/
       
   889   /*****                                                               *****/
       
   890   /*************************************************************************/
       
   891   /*************************************************************************/
       
   892 
       
   893   /* uses valid->type_funcs */
       
   894 
       
   895   static void
       
   896   otv_ExtensionPos_validate( FT_Bytes       table,
       
   897                              OTV_Validator  valid )
       
   898   {
       
   899     FT_Bytes  p = table;
       
   900     FT_UInt   PosFormat;
       
   901 
       
   902 
       
   903     OTV_NAME_ENTER( "ExtensionPos" );
       
   904 
       
   905     OTV_LIMIT_CHECK( 2 );
       
   906     PosFormat = FT_NEXT_USHORT( p );
       
   907 
       
   908     OTV_TRACE(( " (format %d)\n", PosFormat ));
       
   909 
       
   910     switch ( PosFormat )
       
   911     {
       
   912     case 1:     /* ExtensionPosFormat1 */
       
   913       {
       
   914         FT_UInt            ExtensionLookupType;
       
   915         FT_ULong           ExtensionOffset;
       
   916         OTV_Validate_Func  validate;
       
   917 
       
   918 
       
   919         OTV_LIMIT_CHECK( 6 );
       
   920         ExtensionLookupType = FT_NEXT_USHORT( p );
       
   921         ExtensionOffset     = FT_NEXT_ULONG( p );
       
   922 
       
   923         if ( ExtensionLookupType == 0 || ExtensionLookupType >= 9 )
       
   924           FT_INVALID_DATA;
       
   925 
       
   926         validate = valid->type_funcs[ExtensionLookupType - 1];
       
   927         validate( table + ExtensionOffset, valid );
       
   928       }
       
   929       break;
       
   930 
       
   931     default:
       
   932       FT_INVALID_FORMAT;
       
   933     }
       
   934 
       
   935     OTV_EXIT;
       
   936   }
       
   937 
       
   938 
       
   939   static const OTV_Validate_Func  otv_gpos_validate_funcs[9] =
       
   940   {
       
   941     otv_SinglePos_validate,
       
   942     otv_PairPos_validate,
       
   943     otv_CursivePos_validate,
       
   944     otv_MarkBasePos_validate,
       
   945     otv_MarkLigPos_validate,
       
   946     otv_MarkMarkPos_validate,
       
   947     otv_ContextPos_validate,
       
   948     otv_ChainContextPos_validate,
       
   949     otv_ExtensionPos_validate
       
   950   };
       
   951 
       
   952 
       
   953   /* sets valid->type_count */
       
   954   /* sets valid->type_funcs */
       
   955 
       
   956   FT_LOCAL_DEF( void )
       
   957   otv_GPOS_subtable_validate( FT_Bytes       table,
       
   958                               OTV_Validator  valid )
       
   959   {
       
   960     valid->type_count = 9;
       
   961     valid->type_funcs = (OTV_Validate_Func*)otv_gpos_validate_funcs;
       
   962 
       
   963     otv_Lookup_validate( table, valid );
       
   964   }
       
   965 
       
   966 
       
   967   /*************************************************************************/
       
   968   /*************************************************************************/
       
   969   /*****                                                               *****/
       
   970   /*****                          GPOS TABLE                           *****/
       
   971   /*****                                                               *****/
       
   972   /*************************************************************************/
       
   973   /*************************************************************************/
       
   974 
       
   975   /* sets valid->glyph_count */
       
   976 
       
   977   FT_LOCAL_DEF( void )
       
   978   otv_GPOS_validate( FT_Bytes      table,
       
   979                      FT_UInt       glyph_count,
       
   980                      FT_Validator  ftvalid )
       
   981   {
       
   982     OTV_ValidatorRec  validrec;
       
   983     OTV_Validator     valid = &validrec;
       
   984     FT_Bytes          p     = table;
       
   985     FT_UInt           ScriptList, FeatureList, LookupList;
       
   986 
       
   987 
       
   988     valid->root = ftvalid;
       
   989 
       
   990     FT_TRACE3(( "validating GPOS table\n" ));
       
   991     OTV_INIT;
       
   992 
       
   993     OTV_LIMIT_CHECK( 10 );
       
   994 
       
   995     if ( FT_NEXT_ULONG( p ) != 0x10000UL )      /* Version */
       
   996       FT_INVALID_FORMAT;
       
   997 
       
   998     ScriptList  = FT_NEXT_USHORT( p );
       
   999     FeatureList = FT_NEXT_USHORT( p );
       
  1000     LookupList  = FT_NEXT_USHORT( p );
       
  1001 
       
  1002     valid->type_count  = 9;
       
  1003     valid->type_funcs  = (OTV_Validate_Func*)otv_gpos_validate_funcs;
       
  1004     valid->glyph_count = glyph_count;
       
  1005 
       
  1006     otv_LookupList_validate( table + LookupList,
       
  1007                              valid );
       
  1008     otv_FeatureList_validate( table + FeatureList, table + LookupList,
       
  1009                               valid );
       
  1010     otv_ScriptList_validate( table + ScriptList, table + FeatureList,
       
  1011                              valid );
       
  1012 
       
  1013     FT_TRACE4(( "\n" ));
       
  1014   }
       
  1015 
       
  1016 
       
  1017 /* END */