< prev index next >

src/java.desktop/share/native/libfreetype/src/type1/t1gload.c

Print this page


   1 /***************************************************************************/
   2 /*                                                                         */
   3 /*  t1gload.c                                                              */
   4 /*                                                                         */
   5 /*    Type 1 Glyph Loader (body).                                          */
   6 /*                                                                         */
   7 /*  Copyright 1996-2018 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 <ft2build.h>
  20 #include "t1gload.h"
  21 #include FT_INTERNAL_CALC_H
  22 #include FT_INTERNAL_DEBUG_H
  23 #include FT_INTERNAL_STREAM_H
  24 #include FT_OUTLINE_H
  25 #include FT_INTERNAL_POSTSCRIPT_AUX_H
  26 #include FT_INTERNAL_CFF_TYPES_H
  27 #include FT_DRIVER_H
  28 
  29 #include "t1errors.h"
  30 
  31 
  32   /*************************************************************************/
  33   /*                                                                       */
  34   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  35   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
  36   /* messages during execution.                                            */
  37   /*                                                                       */
  38 #undef  FT_COMPONENT
  39 #define FT_COMPONENT  trace_t1gload
  40 
  41 
  42   static FT_Error
  43   T1_Parse_Glyph_And_Get_Char_String( T1_Decoder  decoder,
  44                                       FT_UInt     glyph_index,
  45                                       FT_Data*    char_string,
  46                                       FT_Bool*    force_scaling )
  47   {
  48     T1_Face   face  = (T1_Face)decoder->builder.face;
  49     T1_Font   type1 = &face->type1;
  50     FT_Error  error = FT_Err_Ok;
  51 
  52     PSAux_Service           psaux         = (PSAux_Service)face->psaux;
  53     const T1_Decoder_Funcs  decoder_funcs = psaux->t1_decoder_funcs;
  54     PS_Decoder              psdecoder;
  55 
  56 #ifdef FT_CONFIG_OPTION_INCREMENTAL
  57     FT_Incremental_InterfaceRec *inc =
  58                       face->root.internal->incremental_interface;
  59 #endif
  60 
  61 #ifdef T1_CONFIG_OPTION_OLD_ENGINE
  62     PS_Driver  driver = (PS_Driver)FT_FACE_DRIVER( face );
  63 #endif
  64 

  65     decoder->font_matrix = type1->font_matrix;
  66     decoder->font_offset = type1->font_offset;
  67 
  68 #ifdef FT_CONFIG_OPTION_INCREMENTAL
  69 
  70     /* For incremental fonts get the character data using the */
  71     /* callback function.                                     */
  72     if ( inc )
  73       error = inc->funcs->get_glyph_data( inc->object,
  74                                           glyph_index, char_string );
  75     else
  76 
  77 #endif /* FT_CONFIG_OPTION_INCREMENTAL */
  78 
  79     /* For ordinary fonts get the character data stored in the face record. */
  80     {
  81       char_string->pointer = type1->charstrings[glyph_index];
  82       char_string->length  = (FT_Int)type1->charstrings_len[glyph_index];
  83     }
  84 


 232                                            face->blend,
 233                                            0,
 234                                            FT_RENDER_MODE_NORMAL,
 235                                            T1_Parse_Glyph );
 236     if ( error )
 237       return error;
 238 
 239     decoder.builder.metrics_only = 1;
 240     decoder.builder.load_points  = 0;
 241 
 242     decoder.num_subrs     = type1->num_subrs;
 243     decoder.subrs         = type1->subrs;
 244     decoder.subrs_len     = type1->subrs_len;
 245     decoder.subrs_hash    = type1->subrs_hash;
 246 
 247     decoder.buildchar     = face->buildchar;
 248     decoder.len_buildchar = face->len_buildchar;
 249 
 250     *max_advance = 0;
 251 


 252     /* for each glyph, parse the glyph charstring and extract */
 253     /* the advance width                                      */
 254     for ( glyph_index = 0; glyph_index < type1->num_glyphs; glyph_index++ )
 255     {
 256       /* now get load the unscaled outline */
 257       (void)T1_Parse_Glyph( &decoder, (FT_UInt)glyph_index );
 258       if ( glyph_index == 0 || decoder.builder.advance.x > *max_advance )
 259         *max_advance = decoder.builder.advance.x;
 260 
 261       /* ignore the error if one occurred - skip to next glyph */
 262     }
 263 



 264     psaux->t1_decoder_funcs->done( &decoder );
 265 
 266     return FT_Err_Ok;
 267   }
 268 
 269 
 270   FT_LOCAL_DEF( FT_Error )
 271   T1_Get_Advances( FT_Face    t1face,        /* T1_Face */
 272                    FT_UInt    first,
 273                    FT_UInt    count,
 274                    FT_Int32   load_flags,
 275                    FT_Fixed*  advances )
 276   {
 277     T1_Face        face  = (T1_Face)t1face;
 278     T1_DecoderRec  decoder;
 279     T1_Font        type1 = &face->type1;
 280     PSAux_Service  psaux = (PSAux_Service)face->psaux;
 281     FT_UInt        nn;
 282     FT_Error       error;
 283 
 284 


 285     if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
 286     {
 287       for ( nn = 0; nn < count; nn++ )

 288         advances[nn] = 0;
 289 




 290       return FT_Err_Ok;
 291     }
 292 
 293     error = psaux->t1_decoder_funcs->init( &decoder,
 294                                            (FT_Face)face,
 295                                            0, /* size       */
 296                                            0, /* glyph slot */
 297                                            (FT_Byte**)type1->glyph_names,
 298                                            face->blend,
 299                                            0,
 300                                            FT_RENDER_MODE_NORMAL,
 301                                            T1_Parse_Glyph );
 302     if ( error )
 303       return error;
 304 
 305     decoder.builder.metrics_only = 1;
 306     decoder.builder.load_points  = 0;
 307 
 308     decoder.num_subrs  = type1->num_subrs;
 309     decoder.subrs      = type1->subrs;
 310     decoder.subrs_len  = type1->subrs_len;
 311     decoder.subrs_hash = type1->subrs_hash;
 312 
 313     decoder.buildchar     = face->buildchar;
 314     decoder.len_buildchar = face->len_buildchar;
 315 
 316     for ( nn = 0; nn < count; nn++ )
 317     {
 318       error = T1_Parse_Glyph( &decoder, first + nn );
 319       if ( !error )
 320         advances[nn] = FIXED_TO_INT( decoder.builder.advance.x );
 321       else
 322         advances[nn] = 0;





 323     }
 324 
 325     return FT_Err_Ok;
 326   }
 327 
 328 
 329   FT_LOCAL_DEF( FT_Error )
 330   T1_Load_Glyph( FT_GlyphSlot  t1glyph,          /* T1_GlyphSlot */
 331                  FT_Size       t1size,           /* T1_Size      */
 332                  FT_UInt       glyph_index,
 333                  FT_Int32      load_flags )
 334   {
 335     T1_GlyphSlot            glyph = (T1_GlyphSlot)t1glyph;
 336     FT_Error                error;
 337     T1_DecoderRec           decoder;
 338     T1_Face                 face = (T1_Face)t1glyph->face;
 339     FT_Bool                 hinting;
 340     FT_Bool                 scaled;
 341     FT_Bool                 force_scaling = FALSE;
 342     T1_Font                 type1         = &face->type1;


 367 
 368     FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) );
 369 
 370     if ( load_flags & FT_LOAD_NO_RECURSE )
 371       load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
 372 
 373     if ( t1size )
 374     {
 375       glyph->x_scale = t1size->metrics.x_scale;
 376       glyph->y_scale = t1size->metrics.y_scale;
 377     }
 378     else
 379     {
 380       glyph->x_scale = 0x10000L;
 381       glyph->y_scale = 0x10000L;
 382     }
 383 
 384     t1glyph->outline.n_points   = 0;
 385     t1glyph->outline.n_contours = 0;
 386 
 387     hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE   ) == 0 &&
 388                        ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
 389     scaled  = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE   ) == 0 );
 390 
 391     glyph->hint     = hinting;
 392     glyph->scaled   = scaled;
 393     t1glyph->format = FT_GLYPH_FORMAT_OUTLINE;
 394 
 395     error = decoder_funcs->init( &decoder,
 396                                  t1glyph->face,
 397                                  t1size,
 398                                  t1glyph,
 399                                  (FT_Byte**)type1->glyph_names,
 400                                  face->blend,
 401                                  FT_BOOL( hinting ),
 402                                  FT_LOAD_TARGET_MODE( load_flags ),
 403                                  T1_Parse_Glyph );
 404     if ( error )
 405       goto Exit;
 406 
 407     must_finish_decoder = TRUE;
 408 
 409     decoder.builder.no_recurse = FT_BOOL(
 410                                    ( load_flags & FT_LOAD_NO_RECURSE ) != 0 );
 411 
 412     decoder.num_subrs     = type1->num_subrs;
 413     decoder.subrs         = type1->subrs;
 414     decoder.subrs_len     = type1->subrs_len;
 415     decoder.subrs_hash    = type1->subrs_hash;
 416 
 417     decoder.buildchar     = face->buildchar;
 418     decoder.len_buildchar = face->len_buildchar;
 419 
 420     /* now load the unscaled outline */
 421     error = T1_Parse_Glyph_And_Get_Char_String( &decoder, glyph_index,
 422                                                 &glyph_data,
 423                                                 &force_scaling );
 424     if ( error )
 425       goto Exit;
 426 #ifdef FT_CONFIG_OPTION_INCREMENTAL
 427     glyph_data_loaded = 1;
 428 #endif
 429 
 430     hinting     = glyph->hint;


 511           FT_Outline_Translate( &t1glyph->outline,
 512                                 font_offset.x,
 513                                 font_offset.y );
 514 
 515           metrics->horiAdvance += font_offset.x;
 516           metrics->vertAdvance += font_offset.y;
 517         }
 518 #endif
 519 
 520         if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || force_scaling )
 521         {
 522           /* scale the outline and the metrics */
 523           FT_Int       n;
 524           FT_Outline*  cur = decoder.builder.base;
 525           FT_Vector*   vec = cur->points;
 526           FT_Fixed     x_scale = glyph->x_scale;
 527           FT_Fixed     y_scale = glyph->y_scale;
 528 
 529 
 530           /* First of all, scale the points, if we are not hinting */
 531           if ( !hinting || ! decoder.builder.hints_funcs )
 532             for ( n = cur->n_points; n > 0; n--, vec++ )
 533             {
 534               vec->x = FT_MulFix( vec->x, x_scale );
 535               vec->y = FT_MulFix( vec->y, y_scale );
 536             }
 537 
 538           /* Then scale the metrics */
 539           metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
 540           metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
 541         }
 542 
 543         /* compute the other metrics */
 544         FT_Outline_Get_CBox( &t1glyph->outline, &cbox );
 545 
 546         metrics->width  = cbox.xMax - cbox.xMin;
 547         metrics->height = cbox.yMax - cbox.yMin;
 548 
 549         metrics->horiBearingX = cbox.xMin;
 550         metrics->horiBearingY = cbox.yMax;
 551 


   1 /****************************************************************************
   2  *
   3  * t1gload.c
   4  *
   5  *   Type 1 Glyph Loader (body).
   6  *
   7  * Copyright (C) 1996-2019 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 <ft2build.h>
  20 #include "t1gload.h"
  21 #include FT_INTERNAL_CALC_H
  22 #include FT_INTERNAL_DEBUG_H
  23 #include FT_INTERNAL_STREAM_H
  24 #include FT_OUTLINE_H
  25 #include FT_INTERNAL_POSTSCRIPT_AUX_H
  26 #include FT_INTERNAL_CFF_TYPES_H
  27 #include FT_DRIVER_H
  28 
  29 #include "t1errors.h"
  30 
  31 
  32   /**************************************************************************
  33    *
  34    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
  35    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
  36    * messages during execution.
  37    */
  38 #undef  FT_COMPONENT
  39 #define FT_COMPONENT  t1gload
  40 
  41 
  42   static FT_Error
  43   T1_Parse_Glyph_And_Get_Char_String( T1_Decoder  decoder,
  44                                       FT_UInt     glyph_index,
  45                                       FT_Data*    char_string,
  46                                       FT_Bool*    force_scaling )
  47   {
  48     T1_Face   face  = (T1_Face)decoder->builder.face;
  49     T1_Font   type1 = &face->type1;
  50     FT_Error  error = FT_Err_Ok;
  51 
  52     PSAux_Service           psaux         = (PSAux_Service)face->psaux;
  53     const T1_Decoder_Funcs  decoder_funcs = psaux->t1_decoder_funcs;
  54     PS_Decoder              psdecoder;
  55 
  56 #ifdef FT_CONFIG_OPTION_INCREMENTAL
  57     FT_Incremental_InterfaceRec *inc =
  58                       face->root.internal->incremental_interface;
  59 #endif
  60 
  61 #ifdef T1_CONFIG_OPTION_OLD_ENGINE
  62     PS_Driver  driver = (PS_Driver)FT_FACE_DRIVER( face );
  63 #endif
  64 
  65 
  66     decoder->font_matrix = type1->font_matrix;
  67     decoder->font_offset = type1->font_offset;
  68 
  69 #ifdef FT_CONFIG_OPTION_INCREMENTAL
  70 
  71     /* For incremental fonts get the character data using the */
  72     /* callback function.                                     */
  73     if ( inc )
  74       error = inc->funcs->get_glyph_data( inc->object,
  75                                           glyph_index, char_string );
  76     else
  77 
  78 #endif /* FT_CONFIG_OPTION_INCREMENTAL */
  79 
  80     /* For ordinary fonts get the character data stored in the face record. */
  81     {
  82       char_string->pointer = type1->charstrings[glyph_index];
  83       char_string->length  = (FT_Int)type1->charstrings_len[glyph_index];
  84     }
  85 


 233                                            face->blend,
 234                                            0,
 235                                            FT_RENDER_MODE_NORMAL,
 236                                            T1_Parse_Glyph );
 237     if ( error )
 238       return error;
 239 
 240     decoder.builder.metrics_only = 1;
 241     decoder.builder.load_points  = 0;
 242 
 243     decoder.num_subrs     = type1->num_subrs;
 244     decoder.subrs         = type1->subrs;
 245     decoder.subrs_len     = type1->subrs_len;
 246     decoder.subrs_hash    = type1->subrs_hash;
 247 
 248     decoder.buildchar     = face->buildchar;
 249     decoder.len_buildchar = face->len_buildchar;
 250 
 251     *max_advance = 0;
 252 
 253     FT_TRACE6(( "T1_Compute_Max_Advance:\n" ));
 254 
 255     /* for each glyph, parse the glyph charstring and extract */
 256     /* the advance width                                      */
 257     for ( glyph_index = 0; glyph_index < type1->num_glyphs; glyph_index++ )
 258     {
 259       /* now get load the unscaled outline */
 260       (void)T1_Parse_Glyph( &decoder, (FT_UInt)glyph_index );
 261       if ( glyph_index == 0 || decoder.builder.advance.x > *max_advance )
 262         *max_advance = decoder.builder.advance.x;
 263 
 264       /* ignore the error if one occurred - skip to next glyph */
 265     }
 266 
 267     FT_TRACE6(( "T1_Compute_Max_Advance: max advance: %f\n",
 268                 *max_advance / 65536.0 ));
 269 
 270     psaux->t1_decoder_funcs->done( &decoder );
 271 
 272     return FT_Err_Ok;
 273   }
 274 
 275 
 276   FT_LOCAL_DEF( FT_Error )
 277   T1_Get_Advances( FT_Face    t1face,        /* T1_Face */
 278                    FT_UInt    first,
 279                    FT_UInt    count,
 280                    FT_Int32   load_flags,
 281                    FT_Fixed*  advances )
 282   {
 283     T1_Face        face  = (T1_Face)t1face;
 284     T1_DecoderRec  decoder;
 285     T1_Font        type1 = &face->type1;
 286     PSAux_Service  psaux = (PSAux_Service)face->psaux;
 287     FT_UInt        nn;
 288     FT_Error       error;
 289 
 290 
 291     FT_TRACE5(( "T1_Get_Advances:\n" ));
 292 
 293     if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
 294     {
 295       for ( nn = 0; nn < count; nn++ )
 296       {
 297         advances[nn] = 0;
 298 
 299         FT_TRACE5(( "  idx %d: advance height 0 font units\n",
 300                     first + nn ));
 301       }
 302 
 303       return FT_Err_Ok;
 304     }
 305 
 306     error = psaux->t1_decoder_funcs->init( &decoder,
 307                                            (FT_Face)face,
 308                                            0, /* size       */
 309                                            0, /* glyph slot */
 310                                            (FT_Byte**)type1->glyph_names,
 311                                            face->blend,
 312                                            0,
 313                                            FT_RENDER_MODE_NORMAL,
 314                                            T1_Parse_Glyph );
 315     if ( error )
 316       return error;
 317 
 318     decoder.builder.metrics_only = 1;
 319     decoder.builder.load_points  = 0;
 320 
 321     decoder.num_subrs  = type1->num_subrs;
 322     decoder.subrs      = type1->subrs;
 323     decoder.subrs_len  = type1->subrs_len;
 324     decoder.subrs_hash = type1->subrs_hash;
 325 
 326     decoder.buildchar     = face->buildchar;
 327     decoder.len_buildchar = face->len_buildchar;
 328 
 329     for ( nn = 0; nn < count; nn++ )
 330     {
 331       error = T1_Parse_Glyph( &decoder, first + nn );
 332       if ( !error )
 333         advances[nn] = FIXED_TO_INT( decoder.builder.advance.x );
 334       else
 335         advances[nn] = 0;
 336 
 337       FT_TRACE5(( "  idx %d: advance width %d font unit%s\n",
 338                   first + nn,
 339                   advances[nn],
 340                   advances[nn] == 1 ? "" : "s" ));
 341     }
 342 
 343     return FT_Err_Ok;
 344   }
 345 
 346 
 347   FT_LOCAL_DEF( FT_Error )
 348   T1_Load_Glyph( FT_GlyphSlot  t1glyph,          /* T1_GlyphSlot */
 349                  FT_Size       t1size,           /* T1_Size      */
 350                  FT_UInt       glyph_index,
 351                  FT_Int32      load_flags )
 352   {
 353     T1_GlyphSlot            glyph = (T1_GlyphSlot)t1glyph;
 354     FT_Error                error;
 355     T1_DecoderRec           decoder;
 356     T1_Face                 face = (T1_Face)t1glyph->face;
 357     FT_Bool                 hinting;
 358     FT_Bool                 scaled;
 359     FT_Bool                 force_scaling = FALSE;
 360     T1_Font                 type1         = &face->type1;


 385 
 386     FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) );
 387 
 388     if ( load_flags & FT_LOAD_NO_RECURSE )
 389       load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
 390 
 391     if ( t1size )
 392     {
 393       glyph->x_scale = t1size->metrics.x_scale;
 394       glyph->y_scale = t1size->metrics.y_scale;
 395     }
 396     else
 397     {
 398       glyph->x_scale = 0x10000L;
 399       glyph->y_scale = 0x10000L;
 400     }
 401 
 402     t1glyph->outline.n_points   = 0;
 403     t1glyph->outline.n_contours = 0;
 404 
 405     hinting = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE   ) &&
 406                        !( load_flags & FT_LOAD_NO_HINTING ) );
 407     scaled  = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE   ) );
 408 
 409     glyph->hint     = hinting;
 410     glyph->scaled   = scaled;
 411     t1glyph->format = FT_GLYPH_FORMAT_OUTLINE;
 412 
 413     error = decoder_funcs->init( &decoder,
 414                                  t1glyph->face,
 415                                  t1size,
 416                                  t1glyph,
 417                                  (FT_Byte**)type1->glyph_names,
 418                                  face->blend,
 419                                  hinting,
 420                                  FT_LOAD_TARGET_MODE( load_flags ),
 421                                  T1_Parse_Glyph );
 422     if ( error )
 423       goto Exit;
 424 
 425     must_finish_decoder = TRUE;
 426 
 427     decoder.builder.no_recurse = FT_BOOL( load_flags & FT_LOAD_NO_RECURSE );

 428 
 429     decoder.num_subrs     = type1->num_subrs;
 430     decoder.subrs         = type1->subrs;
 431     decoder.subrs_len     = type1->subrs_len;
 432     decoder.subrs_hash    = type1->subrs_hash;
 433 
 434     decoder.buildchar     = face->buildchar;
 435     decoder.len_buildchar = face->len_buildchar;
 436 
 437     /* now load the unscaled outline */
 438     error = T1_Parse_Glyph_And_Get_Char_String( &decoder, glyph_index,
 439                                                 &glyph_data,
 440                                                 &force_scaling );
 441     if ( error )
 442       goto Exit;
 443 #ifdef FT_CONFIG_OPTION_INCREMENTAL
 444     glyph_data_loaded = 1;
 445 #endif
 446 
 447     hinting     = glyph->hint;


 528           FT_Outline_Translate( &t1glyph->outline,
 529                                 font_offset.x,
 530                                 font_offset.y );
 531 
 532           metrics->horiAdvance += font_offset.x;
 533           metrics->vertAdvance += font_offset.y;
 534         }
 535 #endif
 536 
 537         if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || force_scaling )
 538         {
 539           /* scale the outline and the metrics */
 540           FT_Int       n;
 541           FT_Outline*  cur = decoder.builder.base;
 542           FT_Vector*   vec = cur->points;
 543           FT_Fixed     x_scale = glyph->x_scale;
 544           FT_Fixed     y_scale = glyph->y_scale;
 545 
 546 
 547           /* First of all, scale the points, if we are not hinting */
 548           if ( !hinting || !decoder.builder.hints_funcs )
 549             for ( n = cur->n_points; n > 0; n--, vec++ )
 550             {
 551               vec->x = FT_MulFix( vec->x, x_scale );
 552               vec->y = FT_MulFix( vec->y, y_scale );
 553             }
 554 
 555           /* Then scale the metrics */
 556           metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
 557           metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
 558         }
 559 
 560         /* compute the other metrics */
 561         FT_Outline_Get_CBox( &t1glyph->outline, &cbox );
 562 
 563         metrics->width  = cbox.xMax - cbox.xMin;
 564         metrics->height = cbox.yMax - cbox.yMin;
 565 
 566         metrics->horiBearingX = cbox.xMin;
 567         metrics->horiBearingY = cbox.yMax;
 568 


< prev index next >