Edit

kc3-lang/freetype/src/gxvalid/gxvjust.c

Branch :

  • Show log

    Commit

  • Author : David Turner
    Date : 2020-06-08 13:31:55
    Hash : e1339133
    Message : Make macros for header file names optional. We no longer have to take care of the 8.3 file name limit; this allows us (a) to introduce longer, meaningful file names, and (b) to avoid macro names in `#include' lines altogether since some compilers (most notably Visual C++) doesn't support this properly. */*: Replace #include FOO_H with #include <freetype/foo.h> or something similar. Also update the documentation.

  • src/gxvalid/gxvjust.c
  • /****************************************************************************
     *
     * gxvjust.c
     *
     *   TrueTypeGX/AAT just table validation (body).
     *
     * Copyright (C) 2005-2020 by
     * suzuki toshiya, Masatake YAMATO, Red Hat K.K.,
     * David Turner, Robert Wilhelm, and Werner Lemberg.
     *
     * This file is part of the FreeType project, and may only be used,
     * modified, and distributed under the terms of the FreeType project
     * license, LICENSE.TXT.  By continuing to use, modify, or distribute
     * this file you indicate that you have read the license and
     * understand and accept it fully.
     *
     */
    
    /****************************************************************************
     *
     * gxvalid is derived from both gxlayout module and otvalid module.
     * Development of gxlayout is supported by the Information-technology
     * Promotion Agency(IPA), Japan.
     *
     */
    
    
    #include "gxvalid.h"
    #include "gxvcommn.h"
    
    #include <freetype/ftsnames.h>
    
    
      /**************************************************************************
       *
       * The macro FT_COMPONENT is used in trace mode.  It is an implicit
       * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
       * messages during execution.
       */
    #undef  FT_COMPONENT
    #define FT_COMPONENT  gxvjust
    
      /*
       * referred `just' table format specification:
       * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6just.html
       * last updated 2000.
       * ----------------------------------------------
       * [JUST HEADER]: GXV_JUST_HEADER_SIZE
       * version     (fixed:  32bit) = 0x00010000
       * format      (uint16: 16bit) = 0 is only defined (2000)
       * horizOffset (uint16: 16bit)
       * vertOffset  (uint16: 16bit)
       * ----------------------------------------------
       */
    
      typedef struct  GXV_just_DataRec_
      {
        FT_UShort  wdc_offset_max;
        FT_UShort  wdc_offset_min;
        FT_UShort  pc_offset_max;
        FT_UShort  pc_offset_min;
    
      } GXV_just_DataRec, *GXV_just_Data;
    
    
    #define  GXV_JUST_DATA( a )  GXV_TABLE_DATA( just, a )
    
    
      /* GX just table does not define their subset of GID */
      static void
      gxv_just_check_max_gid( FT_UShort         gid,
                              const FT_String*  msg_tag,
                              GXV_Validator     gxvalid )
      {
        FT_UNUSED( msg_tag );
    
        if ( gid < gxvalid->face->num_glyphs )
          return;
    
        GXV_TRACE(( "just table includes too large %s"
                    " GID=%d > %d (in maxp)\n",
                    msg_tag, gid, gxvalid->face->num_glyphs ));
        GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID );
      }
    
    
      static void
      gxv_just_wdp_entry_validate( FT_Bytes       table,
                                   FT_Bytes       limit,
                                   GXV_Validator  gxvalid )
      {
        FT_Bytes   p = table;
        FT_ULong   justClass;
    #ifdef GXV_LOAD_UNUSED_VARS
        FT_Fixed   beforeGrowLimit;
        FT_Fixed   beforeShrinkGrowLimit;
        FT_Fixed   afterGrowLimit;
        FT_Fixed   afterShrinkGrowLimit;
        FT_UShort  growFlags;
        FT_UShort  shrinkFlags;
    #endif
    
    
        GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 + 4 + 2 + 2 );
        justClass             = FT_NEXT_ULONG( p );
    #ifndef GXV_LOAD_UNUSED_VARS
        p += 4 + 4 + 4 + 4 + 2 + 2;
    #else
        beforeGrowLimit       = FT_NEXT_ULONG( p );
        beforeShrinkGrowLimit = FT_NEXT_ULONG( p );
        afterGrowLimit        = FT_NEXT_ULONG( p );
        afterShrinkGrowLimit  = FT_NEXT_ULONG( p );
        growFlags             = FT_NEXT_USHORT( p );
        shrinkFlags           = FT_NEXT_USHORT( p );
    #endif
    
        /* According to Apple spec, only 7bits in justClass is used */
        if ( ( justClass & 0xFFFFFF80UL ) != 0 )
        {
          GXV_TRACE(( "just table includes non-zero value"
                      " in unused justClass higher bits"
                      " of WidthDeltaPair" ));
          GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA );
        }
    
        gxvalid->subtable_length = (FT_ULong)( p - table );
      }
    
    
      static void
      gxv_just_wdc_entry_validate( FT_Bytes       table,
                                   FT_Bytes       limit,
                                   GXV_Validator  gxvalid )
      {
        FT_Bytes  p = table;
        FT_ULong  count, i;
    
    
        GXV_LIMIT_CHECK( 4 );
        count = FT_NEXT_ULONG( p );
        for ( i = 0; i < count; i++ )
        {
          GXV_TRACE(( "validating wdc pair %d/%d\n", i + 1, count ));
          gxv_just_wdp_entry_validate( p, limit, gxvalid );
          p += gxvalid->subtable_length;
        }
    
        gxvalid->subtable_length = (FT_ULong)( p - table );
      }
    
    
      static void
      gxv_just_widthDeltaClusters_validate( FT_Bytes       table,
                                            FT_Bytes       limit,
                                            GXV_Validator  gxvalid )
      {
        FT_Bytes  p         = table;
        FT_Bytes  wdc_end   = table + GXV_JUST_DATA( wdc_offset_max );
        FT_UInt   i;
    
    
        GXV_NAME_ENTER( "just justDeltaClusters" );
    
        if ( limit <= wdc_end )
          FT_INVALID_OFFSET;
    
        for ( i = 0; p <= wdc_end; i++ )
        {
          gxv_just_wdc_entry_validate( p, limit, gxvalid );
          p += gxvalid->subtable_length;
        }
    
        gxvalid->subtable_length = (FT_ULong)( p - table );
    
        GXV_EXIT;
      }
    
    
      static void
      gxv_just_actSubrecord_type0_validate( FT_Bytes       table,
                                            FT_Bytes       limit,
                                            GXV_Validator  gxvalid )
      {
        FT_Bytes   p = table;
    
        FT_Fixed   lowerLimit;
        FT_Fixed   upperLimit;
    #ifdef GXV_LOAD_UNUSED_VARS
        FT_UShort  order;
    #endif
        FT_UShort  decomposedCount;
    
        FT_UInt    i;
    
    
        GXV_LIMIT_CHECK( 4 + 4 + 2 + 2 );
        lowerLimit      = FT_NEXT_LONG( p );
        upperLimit      = FT_NEXT_LONG( p );
    #ifdef GXV_LOAD_UNUSED_VARS
        order           = FT_NEXT_USHORT( p );
    #else
        p += 2;
    #endif
        decomposedCount = FT_NEXT_USHORT( p );
    
        if ( lowerLimit >= upperLimit )
        {
          GXV_TRACE(( "just table includes invalid range spec:"
                      " lowerLimit(%d) > upperLimit(%d)\n"     ));
          GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA );
        }
    
        for ( i = 0; i < decomposedCount; i++ )
        {
          FT_UShort glyphs;
    
    
          GXV_LIMIT_CHECK( 2 );
          glyphs = FT_NEXT_USHORT( p );
          gxv_just_check_max_gid( glyphs, "type0:glyphs", gxvalid );
        }
    
        gxvalid->subtable_length = (FT_ULong)( p - table );
      }
    
    
      static void
      gxv_just_actSubrecord_type1_validate( FT_Bytes       table,
                                            FT_Bytes       limit,
                                            GXV_Validator  gxvalid )
      {
        FT_Bytes   p = table;
        FT_UShort  addGlyph;
    
    
        GXV_LIMIT_CHECK( 2 );
        addGlyph = FT_NEXT_USHORT( p );
    
        gxv_just_check_max_gid( addGlyph, "type1:addGlyph", gxvalid );
    
        gxvalid->subtable_length = (FT_ULong)( p - table );
      }
    
    
      static void
      gxv_just_actSubrecord_type2_validate( FT_Bytes       table,
                                            FT_Bytes       limit,
                                            GXV_Validator  gxvalid )
      {
        FT_Bytes   p = table;
    #ifdef GXV_LOAD_UNUSED_VARS
        FT_Fixed      substThreshhold; /* Apple misspelled "Threshhold" */
    #endif
        FT_UShort  addGlyph;
        FT_UShort  substGlyph;
    
    
        GXV_LIMIT_CHECK( 4 + 2 + 2 );
    #ifdef GXV_LOAD_UNUSED_VARS
        substThreshhold = FT_NEXT_ULONG( p );
    #else
        p += 4;
    #endif
        addGlyph        = FT_NEXT_USHORT( p );
        substGlyph      = FT_NEXT_USHORT( p );
    
        if ( addGlyph != 0xFFFF )
          gxv_just_check_max_gid( addGlyph, "type2:addGlyph", gxvalid );
    
        gxv_just_check_max_gid( substGlyph, "type2:substGlyph", gxvalid );
    
        gxvalid->subtable_length = (FT_ULong)( p - table );
      }
    
    
      static void
      gxv_just_actSubrecord_type4_validate( FT_Bytes       table,
                                            FT_Bytes       limit,
                                            GXV_Validator  gxvalid )
      {
        FT_Bytes  p = table;
        FT_ULong  variantsAxis;
        FT_Fixed  minimumLimit;
        FT_Fixed  noStretchValue;
        FT_Fixed  maximumLimit;
    
    
        GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 );
        variantsAxis   = FT_NEXT_ULONG( p );
        minimumLimit   = FT_NEXT_LONG( p );
        noStretchValue = FT_NEXT_LONG( p );
        maximumLimit   = FT_NEXT_LONG( p );
    
        gxvalid->subtable_length = (FT_ULong)( p - table );
    
        if ( variantsAxis != 0x64756374L ) /* 'duct' */
          GXV_TRACE(( "variantsAxis 0x%08x is non default value",
                       variantsAxis ));
    
        if ( minimumLimit > noStretchValue )
          GXV_TRACE(( "type4:minimumLimit 0x%08x > noStretchValue 0x%08x\n",
                      minimumLimit, noStretchValue ));
        else if ( noStretchValue > maximumLimit )
          GXV_TRACE(( "type4:noStretchValue 0x%08x > maximumLimit 0x%08x\n",
                      noStretchValue, maximumLimit ));
        else if ( !IS_PARANOID_VALIDATION )
          return;
    
        FT_INVALID_DATA;
      }
    
    
      static void
      gxv_just_actSubrecord_type5_validate( FT_Bytes       table,
                                            FT_Bytes       limit,
                                            GXV_Validator  gxvalid )
      {
        FT_Bytes   p = table;
        FT_UShort  flags;
        FT_UShort  glyph;
    
    
        GXV_LIMIT_CHECK( 2 + 2 );
        flags = FT_NEXT_USHORT( p );
        glyph = FT_NEXT_USHORT( p );
    
        if ( flags )
          GXV_TRACE(( "type5: nonzero value 0x%04x in unused flags\n",
                       flags ));
        gxv_just_check_max_gid( glyph, "type5:glyph", gxvalid );
    
        gxvalid->subtable_length = (FT_ULong)( p - table );
      }
    
    
      /* parse single actSubrecord */
      static void
      gxv_just_actSubrecord_validate( FT_Bytes       table,
                                      FT_Bytes       limit,
                                      GXV_Validator  gxvalid )
      {
        FT_Bytes   p = table;
        FT_UShort  actionClass;
        FT_UShort  actionType;
        FT_ULong   actionLength;
    
    
        GXV_NAME_ENTER( "just actSubrecord" );
    
        GXV_LIMIT_CHECK( 2 + 2 + 4 );
        actionClass  = FT_NEXT_USHORT( p );
        actionType   = FT_NEXT_USHORT( p );
        actionLength = FT_NEXT_ULONG( p );
    
        /* actionClass is related with justClass using 7bit only */
        if ( ( actionClass & 0xFF80 ) != 0 )
          GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA );
    
        if ( actionType == 0 )
          gxv_just_actSubrecord_type0_validate( p, limit, gxvalid );
        else if ( actionType == 1 )
          gxv_just_actSubrecord_type1_validate( p, limit, gxvalid );
        else if ( actionType == 2 )
          gxv_just_actSubrecord_type2_validate( p, limit, gxvalid );
        else if ( actionType == 3 )
          ;                         /* Stretch glyph action: no actionData */
        else if ( actionType == 4 )
          gxv_just_actSubrecord_type4_validate( p, limit, gxvalid );
        else if ( actionType == 5 )
          gxv_just_actSubrecord_type5_validate( p, limit, gxvalid );
        else
          FT_INVALID_DATA;
    
        gxvalid->subtable_length = actionLength;
    
        GXV_EXIT;
      }
    
    
      static void
      gxv_just_pcActionRecord_validate( FT_Bytes       table,
                                        FT_Bytes       limit,
                                        GXV_Validator  gxvalid )
      {
        FT_Bytes  p = table;
        FT_ULong  actionCount;
        FT_ULong  i;
    
    
        GXV_LIMIT_CHECK( 4 );
        actionCount = FT_NEXT_ULONG( p );
        GXV_TRACE(( "actionCount = %d\n", actionCount ));
    
        for ( i = 0; i < actionCount; i++ )
        {
          gxv_just_actSubrecord_validate( p, limit, gxvalid );
          p += gxvalid->subtable_length;
        }
    
        gxvalid->subtable_length = (FT_ULong)( p - table );
    
        GXV_EXIT;
      }
    
    
      static void
      gxv_just_pcTable_LookupValue_entry_validate( FT_UShort            glyph,
                                                   GXV_LookupValueCPtr  value_p,
                                                   GXV_Validator        gxvalid )
      {
        FT_UNUSED( glyph );
    
        if ( value_p->u > GXV_JUST_DATA( pc_offset_max ) )
          GXV_JUST_DATA( pc_offset_max ) = value_p->u;
        if ( value_p->u < GXV_JUST_DATA( pc_offset_max ) )
          GXV_JUST_DATA( pc_offset_min ) = value_p->u;
      }
    
    
      static void
      gxv_just_pcLookupTable_validate( FT_Bytes       table,
                                       FT_Bytes       limit,
                                       GXV_Validator  gxvalid )
      {
        FT_Bytes  p = table;
    
    
        GXV_NAME_ENTER( "just pcLookupTable" );
        GXV_JUST_DATA( pc_offset_max ) = 0x0000;
        GXV_JUST_DATA( pc_offset_min ) = 0xFFFFU;
    
        gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED;
        gxvalid->lookupval_func = gxv_just_pcTable_LookupValue_entry_validate;
    
        gxv_LookupTable_validate( p, limit, gxvalid );
    
        /* subtable_length is set by gxv_LookupTable_validate() */
    
        GXV_EXIT;
      }
    
    
      static void
      gxv_just_postcompTable_validate( FT_Bytes       table,
                                       FT_Bytes       limit,
                                       GXV_Validator  gxvalid )
      {
        FT_Bytes  p = table;
    
    
        GXV_NAME_ENTER( "just postcompTable" );
    
        gxv_just_pcLookupTable_validate( p, limit, gxvalid );
        p += gxvalid->subtable_length;
    
        gxv_just_pcActionRecord_validate( p, limit, gxvalid );
        p += gxvalid->subtable_length;
    
        gxvalid->subtable_length = (FT_ULong)( p - table );
    
        GXV_EXIT;
      }
    
    
      static void
      gxv_just_classTable_entry_validate(
        FT_Byte                         state,
        FT_UShort                       flags,
        GXV_StateTable_GlyphOffsetCPtr  glyphOffset_p,
        FT_Bytes                        table,
        FT_Bytes                        limit,
        GXV_Validator                   gxvalid )
      {
    #ifdef GXV_LOAD_UNUSED_VARS
        /* TODO: validate markClass & currentClass */
        FT_UShort  setMark;
        FT_UShort  dontAdvance;
        FT_UShort  markClass;
        FT_UShort  currentClass;
    #endif
    
        FT_UNUSED( state );
        FT_UNUSED( glyphOffset_p );
        FT_UNUSED( table );
        FT_UNUSED( limit );
        FT_UNUSED( gxvalid );
    
    #ifndef GXV_LOAD_UNUSED_VARS
        FT_UNUSED( flags );
    #else
        setMark      = (FT_UShort)( ( flags >> 15 ) & 1    );
        dontAdvance  = (FT_UShort)( ( flags >> 14 ) & 1    );
        markClass    = (FT_UShort)( ( flags >> 7  ) & 0x7F );
        currentClass = (FT_UShort)(   flags         & 0x7F );
    #endif
      }
    
    
      static void
      gxv_just_justClassTable_validate ( FT_Bytes       table,
                                         FT_Bytes       limit,
                                         GXV_Validator  gxvalid )
      {
        FT_Bytes   p = table;
        FT_UShort  length;
        FT_UShort  coverage;
        FT_ULong   subFeatureFlags;
    
    
        GXV_NAME_ENTER( "just justClassTable" );
    
        GXV_LIMIT_CHECK( 2 + 2 + 4 );
        length          = FT_NEXT_USHORT( p );
        coverage        = FT_NEXT_USHORT( p );
        subFeatureFlags = FT_NEXT_ULONG( p );
    
        GXV_TRACE(( "  justClassTable: coverage = 0x%04x (%s) ", coverage ));
        if ( ( coverage & 0x4000 ) == 0  )
          GXV_TRACE(( "ascending\n" ));
        else
          GXV_TRACE(( "descending\n" ));
    
        if ( subFeatureFlags )
          GXV_TRACE(( "  justClassTable: nonzero value (0x%08x)"
                      " in unused subFeatureFlags\n", subFeatureFlags ));
    
        gxvalid->statetable.optdata               = NULL;
        gxvalid->statetable.optdata_load_func     = NULL;
        gxvalid->statetable.subtable_setup_func   = NULL;
        gxvalid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE;
        gxvalid->statetable.entry_validate_func   =
          gxv_just_classTable_entry_validate;
    
        gxv_StateTable_validate( p, table + length, gxvalid );
    
        /* subtable_length is set by gxv_LookupTable_validate() */
    
        GXV_EXIT;
      }
    
    
      static void
      gxv_just_wdcTable_LookupValue_validate( FT_UShort            glyph,
                                              GXV_LookupValueCPtr  value_p,
                                              GXV_Validator        gxvalid )
      {
        FT_UNUSED( glyph );
    
        if ( value_p->u > GXV_JUST_DATA( wdc_offset_max ) )
          GXV_JUST_DATA( wdc_offset_max ) = value_p->u;
        if ( value_p->u < GXV_JUST_DATA( wdc_offset_min ) )
          GXV_JUST_DATA( wdc_offset_min ) = value_p->u;
      }
    
    
      static void
      gxv_just_justData_lookuptable_validate( FT_Bytes       table,
                                              FT_Bytes       limit,
                                              GXV_Validator  gxvalid )
      {
        FT_Bytes  p = table;
    
    
        GXV_JUST_DATA( wdc_offset_max ) = 0x0000;
        GXV_JUST_DATA( wdc_offset_min ) = 0xFFFFU;
    
        gxvalid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED;
        gxvalid->lookupval_func = gxv_just_wdcTable_LookupValue_validate;
    
        gxv_LookupTable_validate( p, limit, gxvalid );
    
        /* subtable_length is set by gxv_LookupTable_validate() */
    
        GXV_EXIT;
      }
    
    
      /*
       * gxv_just_justData_validate() parses and validates horizData, vertData.
       */
      static void
      gxv_just_justData_validate( FT_Bytes       table,
                                  FT_Bytes       limit,
                                  GXV_Validator  gxvalid )
      {
        /*
         * following 3 offsets are measured from the start of `just'
         * (which table points to), not justData
         */
        FT_UShort  justClassTableOffset;
        FT_UShort  wdcTableOffset;
        FT_UShort  pcTableOffset;
        FT_Bytes   p = table;
    
        GXV_ODTECT( 4, odtect );
    
    
        GXV_NAME_ENTER( "just justData" );
    
        GXV_ODTECT_INIT( odtect );
        GXV_LIMIT_CHECK( 2 + 2 + 2 );
        justClassTableOffset = FT_NEXT_USHORT( p );
        wdcTableOffset       = FT_NEXT_USHORT( p );
        pcTableOffset        = FT_NEXT_USHORT( p );
    
        GXV_TRACE(( " (justClassTableOffset = 0x%04x)\n", justClassTableOffset ));
        GXV_TRACE(( " (wdcTableOffset = 0x%04x)\n", wdcTableOffset ));
        GXV_TRACE(( " (pcTableOffset = 0x%04x)\n", pcTableOffset ));
    
        gxv_just_justData_lookuptable_validate( p, limit, gxvalid );
        gxv_odtect_add_range( p, gxvalid->subtable_length,
                              "just_LookupTable", odtect );
    
        if ( wdcTableOffset )
        {
          gxv_just_widthDeltaClusters_validate(
            gxvalid->root->base + wdcTableOffset, limit, gxvalid );
          gxv_odtect_add_range( gxvalid->root->base + wdcTableOffset,
                                gxvalid->subtable_length, "just_wdcTable", odtect );
        }
    
        if ( pcTableOffset )
        {
          gxv_just_postcompTable_validate( gxvalid->root->base + pcTableOffset,
                                           limit, gxvalid );
          gxv_odtect_add_range( gxvalid->root->base + pcTableOffset,
                                gxvalid->subtable_length, "just_pcTable", odtect );
        }
    
        if ( justClassTableOffset )
        {
          gxv_just_justClassTable_validate(
            gxvalid->root->base + justClassTableOffset, limit, gxvalid );
          gxv_odtect_add_range( gxvalid->root->base + justClassTableOffset,
                                gxvalid->subtable_length, "just_justClassTable",
                                odtect );
        }
    
        gxv_odtect_validate( odtect, gxvalid );
    
        GXV_EXIT;
      }
    
    
      FT_LOCAL_DEF( void )
      gxv_just_validate( FT_Bytes      table,
                         FT_Face       face,
                         FT_Validator  ftvalid )
      {
        FT_Bytes           p     = table;
        FT_Bytes           limit = 0;
    
        GXV_ValidatorRec   gxvalidrec;
        GXV_Validator      gxvalid = &gxvalidrec;
        GXV_just_DataRec   justrec;
        GXV_just_Data      just = &justrec;
    
        FT_ULong           version;
        FT_UShort          format;
        FT_UShort          horizOffset;
        FT_UShort          vertOffset;
    
        GXV_ODTECT( 3, odtect );
    
    
        GXV_ODTECT_INIT( odtect );
    
        gxvalid->root       = ftvalid;
        gxvalid->table_data = just;
        gxvalid->face       = face;
    
        FT_TRACE3(( "validating `just' table\n" ));
        GXV_INIT;
    
        limit      = gxvalid->root->limit;
    
        GXV_LIMIT_CHECK( 4 + 2 + 2 + 2 );
        version     = FT_NEXT_ULONG( p );
        format      = FT_NEXT_USHORT( p );
        horizOffset = FT_NEXT_USHORT( p );
        vertOffset  = FT_NEXT_USHORT( p );
        gxv_odtect_add_range( table, (FT_ULong)( p - table ),
                              "just header", odtect );
    
    
        /* Version 1.0 (always:2000) */
        GXV_TRACE(( " (version = 0x%08x)\n", version ));
        if ( version != 0x00010000UL )
          FT_INVALID_FORMAT;
    
        /* format 0 (always:2000) */
        GXV_TRACE(( " (format = 0x%04x)\n", format ));
        if ( format != 0x0000 )
            FT_INVALID_FORMAT;
    
        GXV_TRACE(( " (horizOffset = %d)\n", horizOffset  ));
        GXV_TRACE(( " (vertOffset = %d)\n", vertOffset  ));
    
    
        /* validate justData */
        if ( 0 < horizOffset )
        {
          gxv_just_justData_validate( table + horizOffset, limit, gxvalid );
          gxv_odtect_add_range( table + horizOffset, gxvalid->subtable_length,
                                "horizJustData", odtect );
        }
    
        if ( 0 < vertOffset )
        {
          gxv_just_justData_validate( table + vertOffset, limit, gxvalid );
          gxv_odtect_add_range( table + vertOffset, gxvalid->subtable_length,
                                "vertJustData", odtect );
        }
    
        gxv_odtect_validate( odtect, gxvalid );
    
        FT_TRACE4(( "\n" ));
      }
    
    
    /* END */