misc/libfreetype/src/gxvalid/gxvjust.c
changeset 9372 915436ff64ab
parent 9371 f3840de881bd
child 9373 b769a8e38cbd
equal deleted inserted replaced
9371:f3840de881bd 9372:915436ff64ab
     1 /***************************************************************************/
       
     2 /*                                                                         */
       
     3 /*  gxvjust.c                                                              */
       
     4 /*                                                                         */
       
     5 /*    TrueTypeGX/AAT just table validation (body).                         */
       
     6 /*                                                                         */
       
     7 /*  Copyright 2005 by suzuki toshiya, Masatake YAMATO, Red Hat K.K.,       */
       
     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 /*                                                                         */
       
    20 /* gxvalid is derived from both gxlayout module and otvalid module.        */
       
    21 /* Development of gxlayout is supported by the Information-technology      */
       
    22 /* Promotion Agency(IPA), Japan.                                           */
       
    23 /*                                                                         */
       
    24 /***************************************************************************/
       
    25 
       
    26 
       
    27 #include "gxvalid.h"
       
    28 #include "gxvcommn.h"
       
    29 
       
    30 #include FT_SFNT_NAMES_H
       
    31 
       
    32 
       
    33   /*************************************************************************/
       
    34   /*                                                                       */
       
    35   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
       
    36   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
       
    37   /* messages during execution.                                            */
       
    38   /*                                                                       */
       
    39 #undef  FT_COMPONENT
       
    40 #define FT_COMPONENT  trace_gxvjust
       
    41 
       
    42   /*
       
    43    * referred `just' table format specification:
       
    44    * http://developer.apple.com/fonts/TTRefMan/RM06/Chap6just.html
       
    45    * last updated 2000.
       
    46    * ----------------------------------------------
       
    47    * [JUST HEADER]: GXV_JUST_HEADER_SIZE
       
    48    * version     (fixed:  32bit) = 0x00010000
       
    49    * format      (uint16: 16bit) = 0 is only defined (2000)
       
    50    * horizOffset (uint16: 16bit)
       
    51    * vertOffset  (uint16: 16bit)
       
    52    * ----------------------------------------------
       
    53    */
       
    54 
       
    55   typedef struct  GXV_just_DataRec_
       
    56   {
       
    57     FT_UShort  wdc_offset_max;
       
    58     FT_UShort  wdc_offset_min;
       
    59     FT_UShort  pc_offset_max;
       
    60     FT_UShort  pc_offset_min;
       
    61 
       
    62   } GXV_just_DataRec, *GXV_just_Data;
       
    63 
       
    64 
       
    65 #define  GXV_JUST_DATA( a )  GXV_TABLE_DATA( just, a )
       
    66 
       
    67 
       
    68   static void
       
    69   gxv_just_wdp_entry_validate( FT_Bytes       table,
       
    70                                FT_Bytes       limit,
       
    71                                GXV_Validator  valid )
       
    72   {
       
    73     FT_Bytes   p = table;
       
    74     FT_ULong   justClass;
       
    75     FT_Fixed   beforeGrowLimit;
       
    76     FT_Fixed   beforeShrinkGrowLimit;
       
    77     FT_Fixed   afterGrowLimit;
       
    78     FT_Fixed   afterShrinkGrowLimit;
       
    79     FT_UShort  growFlags;
       
    80     FT_UShort  shrinkFlags;
       
    81 
       
    82 
       
    83     GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 + 4 + 2 + 2 );
       
    84     justClass             = FT_NEXT_ULONG( p );
       
    85     beforeGrowLimit       = FT_NEXT_ULONG( p );
       
    86     beforeShrinkGrowLimit = FT_NEXT_ULONG( p );
       
    87     afterGrowLimit        = FT_NEXT_ULONG( p );
       
    88     afterShrinkGrowLimit  = FT_NEXT_ULONG( p );
       
    89     growFlags             = FT_NEXT_USHORT( p );
       
    90     shrinkFlags           = FT_NEXT_USHORT( p );
       
    91 
       
    92     /* TODO: decode flags for human readability */
       
    93 
       
    94     valid->subtable_length = p - table;
       
    95   }
       
    96 
       
    97 
       
    98   static void
       
    99   gxv_just_wdc_entry_validate( FT_Bytes       table,
       
   100                                FT_Bytes       limit,
       
   101                                GXV_Validator  valid )
       
   102   {
       
   103     FT_Bytes  p = table;
       
   104     FT_ULong  count, i;
       
   105 
       
   106 
       
   107     GXV_LIMIT_CHECK( 4 );
       
   108     count = FT_NEXT_ULONG( p );
       
   109     for ( i = 0; i < count; i++ )
       
   110     {
       
   111       GXV_TRACE(( "validating wdc pair %d/%d\n", i + 1, count ));
       
   112       gxv_just_wdp_entry_validate( p, limit, valid );
       
   113       p += valid->subtable_length;
       
   114     }
       
   115 
       
   116     valid->subtable_length = p - table;
       
   117   }
       
   118 
       
   119 
       
   120   static void
       
   121   gxv_just_widthDeltaClusters_validate( FT_Bytes       table,
       
   122                                         FT_Bytes       limit,
       
   123                                         GXV_Validator  valid )
       
   124   {
       
   125     FT_Bytes  p         = table ;
       
   126     FT_Bytes  wdc_end   = table + GXV_JUST_DATA( wdc_offset_max );
       
   127     FT_UInt   i;
       
   128 
       
   129 
       
   130     GXV_NAME_ENTER( "just justDeltaClusters" );
       
   131 
       
   132     if ( limit <= wdc_end )
       
   133       FT_INVALID_OFFSET;
       
   134 
       
   135     for ( i = 0; p <= wdc_end; i++ )
       
   136     {
       
   137       gxv_just_wdc_entry_validate( p, limit, valid );
       
   138       p += valid->subtable_length;
       
   139     }
       
   140 
       
   141     valid->subtable_length = p - table;
       
   142 
       
   143     GXV_EXIT;
       
   144   }
       
   145 
       
   146 
       
   147   static void
       
   148   gxv_just_actSubrecord_type0_validate( FT_Bytes       table,
       
   149                                         FT_Bytes       limit,
       
   150                                         GXV_Validator  valid )
       
   151   {
       
   152     FT_Bytes   p = table;
       
   153 
       
   154     FT_Fixed   lowerLimit;
       
   155     FT_Fixed   upperLimit;
       
   156 
       
   157     FT_UShort  order;
       
   158     FT_UShort  decomposedCount;
       
   159 
       
   160     FT_UInt    i;
       
   161 
       
   162 
       
   163     GXV_LIMIT_CHECK( 4 + 4 + 2 + 2 );
       
   164     lowerLimit      = FT_NEXT_ULONG( p );
       
   165     upperLimit      = FT_NEXT_ULONG( p );
       
   166     order           = FT_NEXT_USHORT( p );
       
   167     decomposedCount = FT_NEXT_USHORT( p );
       
   168 
       
   169     for ( i = 0; i < decomposedCount; i++ )
       
   170     {
       
   171       FT_UShort glyphs;
       
   172 
       
   173 
       
   174       GXV_LIMIT_CHECK( 2 );
       
   175       glyphs = FT_NEXT_USHORT( p );
       
   176     }
       
   177 
       
   178     valid->subtable_length = p - table;
       
   179   }
       
   180 
       
   181 
       
   182   static void
       
   183   gxv_just_actSubrecord_type1_validate( FT_Bytes       table,
       
   184                                         FT_Bytes       limit,
       
   185                                         GXV_Validator  valid )
       
   186   {
       
   187     FT_Bytes   p = table;
       
   188     FT_UShort  addGlyph;
       
   189 
       
   190 
       
   191     GXV_LIMIT_CHECK( 2 );
       
   192     addGlyph = FT_NEXT_USHORT( p );
       
   193 
       
   194     valid->subtable_length = p - table;
       
   195   }
       
   196 
       
   197 
       
   198   static void
       
   199   gxv_just_actSubrecord_type2_validate( FT_Bytes       table,
       
   200                                         FT_Bytes       limit,
       
   201                                         GXV_Validator  valid )
       
   202   {
       
   203     FT_Bytes   p = table;
       
   204     FT_Fixed   substThreshhold; /* Apple misspelled "Threshhold" */
       
   205     FT_UShort  addGlyph;
       
   206     FT_UShort  substGlyph;
       
   207 
       
   208 
       
   209     GXV_LIMIT_CHECK( 4 + 2 + 2 );
       
   210     substThreshhold = FT_NEXT_ULONG( p );
       
   211     addGlyph        = FT_NEXT_USHORT( p );
       
   212     substGlyph      = FT_NEXT_USHORT( p );
       
   213 
       
   214     valid->subtable_length = p - table;
       
   215   }
       
   216 
       
   217 
       
   218   static void
       
   219   gxv_just_actSubrecord_type4_validate( FT_Bytes       table,
       
   220                                         FT_Bytes       limit,
       
   221                                         GXV_Validator  valid )
       
   222   {
       
   223     FT_Bytes  p = table;
       
   224     FT_ULong  variantsAxis;
       
   225     FT_Fixed  minimumLimit;
       
   226     FT_Fixed  noStretchValue;
       
   227     FT_Fixed  maximumLimit;
       
   228 
       
   229 
       
   230     GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 );
       
   231     variantsAxis   = FT_NEXT_ULONG( p );
       
   232     minimumLimit   = FT_NEXT_ULONG( p );
       
   233     noStretchValue = FT_NEXT_ULONG( p );
       
   234     maximumLimit   = FT_NEXT_ULONG( p );
       
   235 
       
   236     valid->subtable_length = p - table;
       
   237   }
       
   238 
       
   239 
       
   240   static void
       
   241   gxv_just_actSubrecord_type5_validate( FT_Bytes       table,
       
   242                                         FT_Bytes       limit,
       
   243                                         GXV_Validator  valid )
       
   244   {
       
   245     FT_Bytes   p = table;
       
   246     FT_UShort  flags;
       
   247     FT_UShort  glyph;
       
   248 
       
   249 
       
   250     GXV_LIMIT_CHECK( 2 + 2 );
       
   251     flags = FT_NEXT_USHORT( p );
       
   252     glyph = FT_NEXT_USHORT( p );
       
   253 
       
   254     valid->subtable_length = p - table;
       
   255   }
       
   256 
       
   257 
       
   258   /* parse single actSubrecord */
       
   259   static void
       
   260   gxv_just_actSubrecord_validate( FT_Bytes       table,
       
   261                                   FT_Bytes       limit,
       
   262                                   GXV_Validator  valid )
       
   263   {
       
   264     FT_Bytes   p = table;
       
   265     FT_UShort  actionClass;
       
   266     FT_UShort  actionType;
       
   267     FT_ULong   actionLength;
       
   268 
       
   269 
       
   270     GXV_NAME_ENTER( "just actSubrecord" );
       
   271 
       
   272     GXV_LIMIT_CHECK( 2 + 2 + 4 );
       
   273     actionClass  = FT_NEXT_USHORT( p );
       
   274     actionType   = FT_NEXT_USHORT( p );
       
   275     actionLength = FT_NEXT_ULONG( p );
       
   276 
       
   277     if ( actionType == 0 )
       
   278       gxv_just_actSubrecord_type0_validate( p, limit, valid );
       
   279     else if ( actionType == 1 )
       
   280       gxv_just_actSubrecord_type1_validate( p, limit, valid );
       
   281     else if ( actionType == 2 )
       
   282       gxv_just_actSubrecord_type2_validate( p, limit, valid );
       
   283     else if ( actionType == 3 )
       
   284       ;                         /* Stretch glyph action: no actionData */
       
   285     else if ( actionType == 4 )
       
   286       gxv_just_actSubrecord_type4_validate( p, limit, valid );
       
   287     else if ( actionType == 5 )
       
   288       gxv_just_actSubrecord_type5_validate( p, limit, valid );
       
   289     else
       
   290       FT_INVALID_DATA;
       
   291 
       
   292     valid->subtable_length = actionLength;
       
   293 
       
   294     GXV_EXIT;
       
   295   }
       
   296 
       
   297 
       
   298   static void
       
   299   gxv_just_pcActionRecord_validate( FT_Bytes       table,
       
   300                                     FT_Bytes       limit,
       
   301                                     GXV_Validator  valid )
       
   302   {
       
   303     FT_Bytes  p = table;
       
   304     FT_ULong  actionCount;
       
   305     FT_ULong  i;
       
   306 
       
   307 
       
   308     GXV_LIMIT_CHECK( 4 );
       
   309     actionCount = FT_NEXT_ULONG( p );
       
   310     GXV_TRACE(( "actionCount = %d\n", actionCount ));
       
   311 
       
   312     for ( i = 0; i < actionCount; i++ )
       
   313     {
       
   314       gxv_just_actSubrecord_validate( p, limit, valid );
       
   315       p += valid->subtable_length;
       
   316     }
       
   317 
       
   318     valid->subtable_length = p - table;
       
   319 
       
   320     GXV_EXIT;
       
   321   }
       
   322 
       
   323 
       
   324   static void
       
   325   gxv_just_pcTable_LookupValue_entry_validate( FT_UShort            glyph,
       
   326                                                GXV_LookupValueCPtr  value_p,
       
   327                                                GXV_Validator        valid )
       
   328   {
       
   329     FT_UNUSED( glyph );
       
   330 
       
   331     if ( value_p->u > GXV_JUST_DATA( pc_offset_max ) )
       
   332       GXV_JUST_DATA( pc_offset_max ) = value_p->u;
       
   333     if ( value_p->u < GXV_JUST_DATA( pc_offset_max ) )
       
   334       GXV_JUST_DATA( pc_offset_min ) = value_p->u;
       
   335   }
       
   336 
       
   337 
       
   338   static void
       
   339   gxv_just_pcLookupTable_validate( FT_Bytes       table,
       
   340                                    FT_Bytes       limit,
       
   341                                    GXV_Validator  valid )
       
   342   {
       
   343     FT_Bytes p = table;
       
   344 
       
   345 
       
   346     GXV_NAME_ENTER( "just pcLookupTable" );
       
   347     GXV_JUST_DATA( pc_offset_max ) = 0x0000;
       
   348     GXV_JUST_DATA( pc_offset_min ) = 0xFFFFU;
       
   349 
       
   350     valid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED;
       
   351     valid->lookupval_func = gxv_just_pcTable_LookupValue_entry_validate;
       
   352 
       
   353     gxv_LookupTable_validate( p, limit, valid );
       
   354 
       
   355     /* subtable_length is set by gxv_LookupTable_validate() */
       
   356 
       
   357     GXV_EXIT;
       
   358   }
       
   359 
       
   360 
       
   361   static void
       
   362   gxv_just_postcompTable_validate( FT_Bytes       table,
       
   363                                    FT_Bytes       limit,
       
   364                                    GXV_Validator  valid )
       
   365   {
       
   366     FT_Bytes  p = table;
       
   367 
       
   368 
       
   369     GXV_NAME_ENTER( "just postcompTable" );
       
   370 
       
   371     gxv_just_pcLookupTable_validate( p, limit, valid );
       
   372     p += valid->subtable_length;
       
   373 
       
   374     gxv_just_pcActionRecord_validate( p, limit, valid );
       
   375     p += valid->subtable_length;
       
   376 
       
   377     valid->subtable_length = p - table;
       
   378 
       
   379     GXV_EXIT;
       
   380   }
       
   381 
       
   382 
       
   383   static void
       
   384   gxv_just_classTable_entry_validate(
       
   385     FT_Byte                         state,
       
   386     FT_UShort                       flags,
       
   387     GXV_StateTable_GlyphOffsetCPtr  glyphOffset_p,
       
   388     FT_Bytes                        table,
       
   389     FT_Bytes                        limit,
       
   390     GXV_Validator                   valid )
       
   391   {
       
   392     FT_UShort  setMark;
       
   393     FT_UShort  dontAdvance;
       
   394     FT_UShort  markClass;
       
   395     FT_UShort  currentClass;
       
   396 
       
   397     FT_UNUSED( state );
       
   398     FT_UNUSED( glyphOffset_p );
       
   399     FT_UNUSED( table );
       
   400     FT_UNUSED( limit );
       
   401     FT_UNUSED( valid );
       
   402 
       
   403 
       
   404     setMark      = (FT_UShort)( ( flags >> 15 ) & 1    );
       
   405     dontAdvance  = (FT_UShort)( ( flags >> 14 ) & 1    );
       
   406     markClass    = (FT_UShort)( ( flags >> 7  ) & 0x7F );
       
   407     currentClass = (FT_UShort)(   flags         & 0x7F );
       
   408 
       
   409     /* TODO: validate markClass & currentClass */
       
   410   }
       
   411 
       
   412 
       
   413   static void
       
   414   gxv_just_justClassTable_validate ( FT_Bytes       table,
       
   415                                      FT_Bytes       limit,
       
   416                                      GXV_Validator  valid )
       
   417   {
       
   418     FT_Bytes   p = table;
       
   419     FT_UShort  length;
       
   420     FT_UShort  coverage;
       
   421     FT_ULong   subFeatureFlags;
       
   422 
       
   423 
       
   424     GXV_NAME_ENTER( "just justClassTable" );
       
   425 
       
   426     GXV_LIMIT_CHECK( 2 + 2 + 4 );
       
   427     length          = FT_NEXT_USHORT( p );
       
   428     coverage        = FT_NEXT_USHORT( p );
       
   429     subFeatureFlags = FT_NEXT_ULONG( p );
       
   430 
       
   431     GXV_TRACE(( "  justClassTable: coverage = 0x%04x (%s)",
       
   432                 coverage,
       
   433                 ( 0x4000 & coverage ) == 0 ? "ascending" : "descending" ));
       
   434 
       
   435     valid->statetable.optdata               = NULL;
       
   436     valid->statetable.optdata_load_func     = NULL;
       
   437     valid->statetable.subtable_setup_func   = NULL;
       
   438     valid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE;
       
   439     valid->statetable.entry_validate_func   =
       
   440       gxv_just_classTable_entry_validate;
       
   441 
       
   442     gxv_StateTable_validate( p, table + length, valid );
       
   443 
       
   444     /* subtable_length is set by gxv_LookupTable_validate() */
       
   445 
       
   446     GXV_EXIT;
       
   447   }
       
   448 
       
   449 
       
   450   static void
       
   451   gxv_just_wdcTable_LookupValue_validate( FT_UShort            glyph,
       
   452                                           GXV_LookupValueCPtr  value_p,
       
   453                                           GXV_Validator        valid )
       
   454   {
       
   455     FT_UNUSED( glyph );
       
   456 
       
   457     if ( value_p->u > GXV_JUST_DATA( wdc_offset_max ) )
       
   458       GXV_JUST_DATA( wdc_offset_max ) = value_p->u;
       
   459     if ( value_p->u < GXV_JUST_DATA( wdc_offset_min ) )
       
   460       GXV_JUST_DATA( wdc_offset_min ) = value_p->u;
       
   461   }
       
   462 
       
   463 
       
   464   static void
       
   465   gxv_just_justData_lookuptable_validate( FT_Bytes       table,
       
   466                                           FT_Bytes       limit,
       
   467                                           GXV_Validator  valid )
       
   468   {
       
   469     FT_Bytes  p = table;
       
   470 
       
   471 
       
   472     GXV_JUST_DATA( wdc_offset_max ) = 0x0000;
       
   473     GXV_JUST_DATA( wdc_offset_min ) = 0xFFFFU;
       
   474 
       
   475     valid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED;
       
   476     valid->lookupval_func = gxv_just_wdcTable_LookupValue_validate;
       
   477 
       
   478     gxv_LookupTable_validate( p, limit, valid );
       
   479 
       
   480     /* subtable_length is set by gxv_LookupTable_validate() */
       
   481 
       
   482     GXV_EXIT;
       
   483   }
       
   484 
       
   485 
       
   486   /*
       
   487    * gxv_just_justData_validate() parses and validates horizData, vertData.
       
   488    */
       
   489   static void
       
   490   gxv_just_justData_validate( FT_Bytes       table,
       
   491                               FT_Bytes       limit,
       
   492                               GXV_Validator  valid )
       
   493   {
       
   494     /*
       
   495      * following 3 offsets are measured from the start of `just'
       
   496      * (which table points to), not justData
       
   497      */
       
   498     FT_UShort  justClassTableOffset;
       
   499     FT_UShort  wdcTableOffset;
       
   500     FT_UShort  pcTableOffset;
       
   501     FT_Bytes   p = table;
       
   502 
       
   503     GXV_ODTECT( 4, odtect );
       
   504 
       
   505 
       
   506     GXV_NAME_ENTER( "just justData" );
       
   507 
       
   508     GXV_ODTECT_INIT( odtect );
       
   509     GXV_LIMIT_CHECK( 2 + 2 + 2 );
       
   510     justClassTableOffset = FT_NEXT_USHORT( p );
       
   511     wdcTableOffset       = FT_NEXT_USHORT( p );
       
   512     pcTableOffset        = FT_NEXT_USHORT( p );
       
   513 
       
   514     GXV_TRACE(( " (justClassTableOffset = 0x%04x)\n", justClassTableOffset ));
       
   515     GXV_TRACE(( " (wdcTableOffset = 0x%04x)\n", wdcTableOffset ));
       
   516     GXV_TRACE(( " (pcTableOffset = 0x%04x)\n", pcTableOffset ));
       
   517 
       
   518     gxv_just_justData_lookuptable_validate( p, limit, valid );
       
   519     gxv_odtect_add_range( p, valid->subtable_length,
       
   520                           "just_LookupTable", odtect );
       
   521 
       
   522     if ( wdcTableOffset )
       
   523     {
       
   524       gxv_just_widthDeltaClusters_validate(
       
   525         valid->root->base + wdcTableOffset, limit, valid );
       
   526       gxv_odtect_add_range( valid->root->base + wdcTableOffset,
       
   527                             valid->subtable_length, "just_wdcTable", odtect );
       
   528     }
       
   529 
       
   530     if ( pcTableOffset )
       
   531     {
       
   532       gxv_just_postcompTable_validate( valid->root->base + pcTableOffset,
       
   533                                        limit, valid );
       
   534       gxv_odtect_add_range( valid->root->base + pcTableOffset,
       
   535                             valid->subtable_length, "just_pcTable", odtect );
       
   536     }
       
   537 
       
   538     if ( justClassTableOffset )
       
   539     {
       
   540       gxv_just_justClassTable_validate(
       
   541         valid->root->base + justClassTableOffset, limit, valid );
       
   542       gxv_odtect_add_range( valid->root->base + justClassTableOffset,
       
   543                             valid->subtable_length, "just_justClassTable",
       
   544                             odtect );
       
   545     }
       
   546 
       
   547     gxv_odtect_validate( odtect, valid );
       
   548 
       
   549     GXV_EXIT;
       
   550   }
       
   551 
       
   552 
       
   553   FT_LOCAL_DEF( void )
       
   554   gxv_just_validate( FT_Bytes      table,
       
   555                      FT_Face       face,
       
   556                      FT_Validator  ftvalid )
       
   557   {
       
   558     FT_Bytes           p     = table;
       
   559     FT_Bytes           limit = 0;
       
   560     FT_Offset          table_size;
       
   561 
       
   562     GXV_ValidatorRec   validrec;
       
   563     GXV_Validator      valid = &validrec;
       
   564     GXV_just_DataRec   justrec;
       
   565     GXV_just_Data      just = &justrec;
       
   566 
       
   567     FT_ULong           version;
       
   568     FT_UShort          format;
       
   569     FT_UShort          horizOffset;
       
   570     FT_UShort          vertOffset;
       
   571 
       
   572     GXV_ODTECT( 3, odtect );
       
   573 
       
   574 
       
   575     GXV_ODTECT_INIT( odtect );
       
   576 
       
   577     valid->root       = ftvalid;
       
   578     valid->table_data = just;
       
   579     valid->face       = face;
       
   580 
       
   581     FT_TRACE3(( "validating `just' table\n" ));
       
   582     GXV_INIT;
       
   583 
       
   584     limit      = valid->root->limit;
       
   585     table_size = limit - table;
       
   586 
       
   587     GXV_LIMIT_CHECK( 4 + 2 + 2 + 2 );
       
   588     version     = FT_NEXT_ULONG( p );
       
   589     format      = FT_NEXT_USHORT( p );
       
   590     horizOffset = FT_NEXT_USHORT( p );
       
   591     vertOffset  = FT_NEXT_USHORT( p );
       
   592     gxv_odtect_add_range( table, p - table, "just header", odtect );
       
   593 
       
   594 
       
   595     /* Version 1.0 (always:2000) */
       
   596     GXV_TRACE(( " (version = 0x%08x)\n", version ));
       
   597     if ( version != 0x00010000UL )
       
   598       FT_INVALID_FORMAT;
       
   599 
       
   600     /* format 0 (always:2000) */
       
   601     GXV_TRACE(( " (format = 0x%04x)\n", format ));
       
   602     if ( format != 0x0000 )
       
   603         FT_INVALID_FORMAT;
       
   604 
       
   605     GXV_TRACE(( " (horizOffset = %d)\n", horizOffset  ));
       
   606     GXV_TRACE(( " (vertOffset = %d)\n", vertOffset  ));
       
   607 
       
   608 
       
   609     /* validate justData */
       
   610     if ( 0 < horizOffset )
       
   611     {
       
   612       gxv_just_justData_validate( table + horizOffset, limit, valid );
       
   613       gxv_odtect_add_range( table + horizOffset, valid->subtable_length,
       
   614                             "horizJustData", odtect );
       
   615     }
       
   616 
       
   617     if ( 0 < vertOffset )
       
   618     {
       
   619       gxv_just_justData_validate( table + vertOffset, limit, valid );
       
   620       gxv_odtect_add_range( table + vertOffset, valid->subtable_length,
       
   621                             "vertJustData", odtect );
       
   622     }
       
   623 
       
   624     gxv_odtect_validate( odtect, valid );
       
   625 
       
   626     FT_TRACE4(( "\n" ));
       
   627   }
       
   628 
       
   629 
       
   630 /* END */