/***************************************************************************/

/*                                                                         */

/*  otvjstf.c                                                              */

/*                                                                         */

/*    OpenType JSTF table validation (body).                               */

/*                                                                         */

/*  Copyright 2004, 2007 by                                                */

/*  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.                                        */

/*                                                                         */

/***************************************************************************/





#include "otvalid.h"

#include "otvcommn.h"

#include "otvgpos.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  trace_otvjstf





#define JstfPriorityFunc  otv_JstfPriority_validate

#define JstfLookupFunc    otv_GPOS_subtable_validate



  /* uses valid->extra1 (GSUB lookup count) */

  /* uses valid->extra2 (GPOS lookup count) */

  /* sets valid->extra1 (counter)           */



  static void

  otv_JstfPriority_validate( FT_Bytes       table,

                             OTV_Validator  valid )

  {

    FT_Bytes  p = table;

    FT_UInt   table_size;

    FT_UInt   gsub_lookup_count, gpos_lookup_count;



    OTV_OPTIONAL_TABLE( ShrinkageEnableGSUB  );

    OTV_OPTIONAL_TABLE( ShrinkageDisableGSUB );

    OTV_OPTIONAL_TABLE( ShrinkageEnableGPOS  );

    OTV_OPTIONAL_TABLE( ShrinkageDisableGPOS );

    OTV_OPTIONAL_TABLE( ExtensionEnableGSUB  );

    OTV_OPTIONAL_TABLE( ExtensionDisableGSUB );

    OTV_OPTIONAL_TABLE( ExtensionEnableGPOS  );

    OTV_OPTIONAL_TABLE( ExtensionDisableGPOS );

    OTV_OPTIONAL_TABLE( ShrinkageJstfMax );

    OTV_OPTIONAL_TABLE( ExtensionJstfMax );





    OTV_ENTER;

    OTV_TRACE(( "JstfPriority table\n" ));



    OTV_LIMIT_CHECK( 20 );



    gsub_lookup_count = valid->extra1;

    gpos_lookup_count = valid->extra2;



    table_size = 20;



    valid->extra1 = gsub_lookup_count;



    OTV_OPTIONAL_OFFSET( ShrinkageEnableGSUB );

    OTV_SIZE_CHECK( ShrinkageEnableGSUB );

    if ( ShrinkageEnableGSUB )

      otv_x_ux( table + ShrinkageEnableGSUB, valid );



    OTV_OPTIONAL_OFFSET( ShrinkageDisableGSUB );

    OTV_SIZE_CHECK( ShrinkageDisableGSUB );

    if ( ShrinkageDisableGSUB )

      otv_x_ux( table + ShrinkageDisableGSUB, valid );



    valid->extra1 = gpos_lookup_count;



    OTV_OPTIONAL_OFFSET( ShrinkageEnableGPOS );

    OTV_SIZE_CHECK( ShrinkageEnableGPOS );

    if ( ShrinkageEnableGPOS )

      otv_x_ux( table + ShrinkageEnableGPOS, valid );



    OTV_OPTIONAL_OFFSET( ShrinkageDisableGPOS );

    OTV_SIZE_CHECK( ShrinkageDisableGPOS );

    if ( ShrinkageDisableGPOS )

      otv_x_ux( table + ShrinkageDisableGPOS, valid );



    OTV_OPTIONAL_OFFSET( ShrinkageJstfMax );

    OTV_SIZE_CHECK( ShrinkageJstfMax );

    if ( ShrinkageJstfMax )

    {

      /* XXX: check lookup types? */

      OTV_NEST2( JstfMax, JstfLookup );

      OTV_RUN( table + ShrinkageJstfMax, valid );

    }



    valid->extra1 = gsub_lookup_count;



    OTV_OPTIONAL_OFFSET( ExtensionEnableGSUB );

    OTV_SIZE_CHECK( ExtensionEnableGSUB );

    if ( ExtensionEnableGSUB )

      otv_x_ux( table + ExtensionEnableGSUB, valid );



    OTV_OPTIONAL_OFFSET( ExtensionDisableGSUB );

    OTV_SIZE_CHECK( ExtensionDisableGSUB );

    if ( ExtensionDisableGSUB )

      otv_x_ux( table + ExtensionDisableGSUB, valid );



    valid->extra1 = gpos_lookup_count;



    OTV_OPTIONAL_OFFSET( ExtensionEnableGPOS );

    OTV_SIZE_CHECK( ExtensionEnableGPOS );

    if ( ExtensionEnableGPOS )

      otv_x_ux( table + ExtensionEnableGPOS, valid );



    OTV_OPTIONAL_OFFSET( ExtensionDisableGPOS );

    OTV_SIZE_CHECK( ExtensionDisableGPOS );

    if ( ExtensionDisableGPOS )

      otv_x_ux( table + ExtensionDisableGPOS, valid );



    OTV_OPTIONAL_OFFSET( ExtensionJstfMax );

    OTV_SIZE_CHECK( ExtensionJstfMax );

    if ( ExtensionJstfMax )

    {

      /* XXX: check lookup types? */

      OTV_NEST2( JstfMax, JstfLookup );

      OTV_RUN( table + ExtensionJstfMax, valid );

    }



    valid->extra1 = gsub_lookup_count;

    valid->extra2 = gpos_lookup_count;



    OTV_EXIT;

  }





  /* sets valid->extra (glyph count)               */

  /* sets valid->func1 (otv_JstfPriority_validate) */



  static void

  otv_JstfScript_validate( FT_Bytes       table,

                           OTV_Validator  valid )

  {

    FT_Bytes  p = table;

    FT_UInt   table_size;

    FT_UInt   JstfLangSysCount;



    OTV_OPTIONAL_TABLE( ExtGlyph );

    OTV_OPTIONAL_TABLE( DefJstfLangSys );





    OTV_NAME_ENTER( "JstfScript" );



    OTV_LIMIT_CHECK( 6 );

    OTV_OPTIONAL_OFFSET( ExtGlyph );

    OTV_OPTIONAL_OFFSET( DefJstfLangSys );

    JstfLangSysCount = FT_NEXT_USHORT( p );



    OTV_TRACE(( " (JstfLangSysCount = %d)\n", JstfLangSysCount ));



    table_size = JstfLangSysCount * 6 + 6;



    OTV_SIZE_CHECK( ExtGlyph );

    if ( ExtGlyph )

    {

      valid->extra1 = valid->glyph_count;

      OTV_NEST1( ExtenderGlyph );

      OTV_RUN( table + ExtGlyph, valid );

    }



    OTV_SIZE_CHECK( DefJstfLangSys );

    if ( DefJstfLangSys )

    {

      OTV_NEST2( JstfLangSys, JstfPriority );

      OTV_RUN( table + DefJstfLangSys, valid );

    }



    OTV_LIMIT_CHECK( 6 * JstfLangSysCount );



    /* JstfLangSysRecord */

    OTV_NEST2( JstfLangSys, JstfPriority );

    for ( ; JstfLangSysCount > 0; JstfLangSysCount-- )

    {

      p += 4;       /* skip JstfLangSysTag */



      OTV_RUN( table + FT_NEXT_USHORT( p ), valid );

    }



    OTV_EXIT;

  }





  /* sets valid->extra1 (GSUB lookup count) */

  /* sets valid->extra2 (GPOS lookup count) */

  /* sets valid->glyph_count                */



  FT_LOCAL_DEF( void )

  otv_JSTF_validate( FT_Bytes      table,

                     FT_Bytes      gsub,

                     FT_Bytes      gpos,

                     FT_UInt       glyph_count,

                     FT_Validator  ftvalid )

  {

    OTV_ValidatorRec  validrec;

    OTV_Validator     valid = &validrec;

    FT_Bytes          p     = table;

    FT_UInt           JstfScriptCount;





    valid->root = ftvalid;



    FT_TRACE3(( "validating JSTF table\n" ));

    OTV_INIT;



    OTV_LIMIT_CHECK( 6 );



    if ( FT_NEXT_ULONG( p ) != 0x10000UL )      /* Version */

      FT_INVALID_FORMAT;



    JstfScriptCount = FT_NEXT_USHORT( p );



    FT_TRACE3(( " (JstfScriptCount = %d)\n", JstfScriptCount ));



    OTV_LIMIT_CHECK( JstfScriptCount * 6 );



    if ( gsub )

      valid->extra1 = otv_GSUBGPOS_get_Lookup_count( gsub );

    else

      valid->extra1 = 0;



    if ( gpos )

      valid->extra2 = otv_GSUBGPOS_get_Lookup_count( gpos );

    else

      valid->extra2 = 0;



    valid->glyph_count = glyph_count;



    /* JstfScriptRecord */

    for ( ; JstfScriptCount > 0; JstfScriptCount-- )

    {

      p += 4;       /* skip JstfScriptTag */



      /* JstfScript */

      otv_JstfScript_validate( table + FT_NEXT_USHORT( p ), valid );

    }



    FT_TRACE4(( "\n" ));

  }





/* END */

