shithub: freetype+ttf2subf

ref: 0f6467a016e9a13dedb944b239b6eddb2af33ca3
dir: /src/cff/t2load.c/

View raw version
/***************************************************************************/
/*                                                                         */
/*  t2load.h                                                               */
/*                                                                         */
/*    TrueType glyph data/program tables loader (body).                    */
/*                                                                         */
/*  Copyright 1996-1999 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 <freetype/internal/ftdebug.h>
#include <freetype/internal/ftobjs.h>
#include <freetype/internal/ftstream.h>
#include <freetype/internal/psnames.h>

#include <freetype/fterrors.h>
#include <freetype/tttags.h>
#include <t2load.h>
#include <t2parse.h>
#include <t2errors.h>

#undef  FT_COMPONENT
#define FT_COMPONENT  trace_ttload

 /* read a CFF offset from memory */
  static
  FT_ULong  t2_get_offset( FT_Byte*  p,
                           FT_Byte   off_size )
  {
    FT_ULong  result;
    for ( result = 0; off_size > 0; off_size-- )
      result = (result <<= 8) | *p++;
    return result;
  }



  static
  FT_Error  t2_new_cff_index( CFF_Index*  index,
                              FT_Stream   stream,
                              FT_Bool     load )
  {
    FT_Error  error;
    FT_Memory memory = stream->memory;
    FT_UShort count;

    MEM_Set( index, 0, sizeof(*index) );
    index->stream = stream;
    if ( !READ_UShort( count ) &&
          count > 0            )
    {
      FT_Byte*  p;
      FT_Byte   offsize;
      FT_ULong  data_size;
      FT_ULong* poff;

      /* there is at least one element, read the offset size            */
      /* then access the offset table to compute the index's total size */
      if ( READ_Byte( offsize ) )
        goto Exit;

      index->stream   = stream;
      index->count    = count;
      index->off_size = offsize;
      data_size       = (FT_ULong)(count+1) * offsize;

      if ( ALLOC_ARRAY( index->offsets, count+1, FT_ULong ) ||
           ACCESS_Frame( data_size ))
        goto Exit;

      poff = index->offsets;
      p    = (FT_Byte*)stream->cursor;
      for ( ; (FT_Short)count >= 0; count-- )
      {
        poff[0] = t2_get_offset( p, offsize );
        poff++;
        p += offsize;
      }

      FORGET_Frame();

      index->data_offset = FILE_Pos();
      data_size          = poff[-1]-1;

      if (load)
      {
        /* load the data */
        if ( EXTRACT_Frame( data_size, index->bytes ) )
          goto Exit;
      }
      else
      {
        /* skip the data */
        (void)FILE_Skip( data_size );
      }
    }
  Exit:
    if (error)
      FREE( index->offsets );

    return error;
  }


  static
  void  t2_done_cff_index( CFF_Index*  index )
  {
    if ( index->stream )
    {
      FT_Stream  stream = index->stream;
      FT_Memory  memory = stream->memory;
    
      if (index->bytes)
        RELEASE_Frame( index->bytes );

      FREE( index->offsets );
      MEM_Set( index, 0, sizeof(*index) );
    }
  }


  static
  FT_Error  t2_explicit_cff_index( CFF_Index*  index,
                                   FT_Byte**  *table )
  {
    FT_Error  error  = 0;
    FT_Memory memory = index->stream->memory;
    FT_UInt   n, offset, old_offset;
    FT_Byte** t;

    *table  = 0;
    if ( index->count > 0 && !ALLOC_ARRAY( t, index->count+1, FT_Byte* ) )
    {
      old_offset = 1;
      for ( n = 0; n <= index->count; n++ )
      {
        offset = index->offsets[n];
        if (!offset)
          offset = old_offset;
        
        t[n] = index->bytes + offset - 1;
        
        old_offset = offset;
      }
      *table = t;
    }
    return error;    
  }


  LOCAL_FUNC
  FT_Error  T2_Access_Element( CFF_Index*   index,
                               FT_UInt      element,
                               FT_Byte*    *pbytes,
                               FT_ULong    *pbyte_len )
  {
    FT_Error  error = 0;

    if ( index && index->count > element )
    {
      /* compute start and end offsets */
      FT_ULong  off1, off2;
      
      off1 = index->offsets[element];
      if (off1)
      {
        do
        {
          element++;
          off2 = index->offsets[element];
        }
        while (off2 == 0 && element < index->count);
        if (!off2)
          off1 = 0;
      }
    
      /* access element */
      if (off1)
      {
        *pbyte_len = off2 - off1;
        
        if (index->bytes)
        {
          /* this index was completely loaded in memory, that's easy */
          *pbytes   = index->bytes + off1 - 1;
        }
        else
        {
          /* this index is still on disk/file, access it through a frame */
          FT_Stream  stream = index->stream;
          
          if ( FILE_Seek( index->data_offset + off1 - 1 ) ||
               EXTRACT_Frame( off2-off1, *pbytes )        )
            goto Exit;
        }
      }
      else
      {
        /* empty index element */
        *pbytes    = 0;
        *pbyte_len = 0;
      }
    }
    else
      error = FT_Err_Invalid_Argument;
      
  Exit:
    return error;
  }


  LOCAL_FUNC
  void  T2_Forget_Element( CFF_Index*  index,
                           FT_Byte*   *pbytes )
  {
    if (index->bytes == 0)
    {
      FT_Stream  stream = index->stream;
      RELEASE_Frame( *pbytes );
    }
  }                           


  LOCAL_FUNC
  FT_String*  T2_Get_Name( CFF_Index*  index,
                           FT_UInt     element )
  {
    FT_Memory  memory = index->stream->memory;
    FT_Byte*   bytes;
    FT_ULong   byte_len;
    FT_Error   error;
    FT_String* name = 0;
    
    error = T2_Access_Element( index, element, &bytes, &byte_len );
    if (error) goto Exit;
    
    if ( !ALLOC( name, byte_len+1 ) )
    {
      MEM_Copy( name, bytes, byte_len );
      name[byte_len] = 0;
    }
    T2_Forget_Element( index, &bytes );

  Exit:
    return name;
  }                           


#if 0 /* unused until we fully support pure-CFF fonts */
  LOCAL_FUNC
  FT_String*  T2_Get_String( CFF_Index*          index,
                             FT_UInt             sid,
                             PSNames_Interface*  interface )
  {
    /* if it's not a standard string, return it */
    if ( sid > 390 )
      return T2_Get_Name( index, sid - 390 );
      
    /* that's a standard string, fetch a copy from the psnamed module */
    {
      FT_String*   name       = 0;
      const char*  adobe_name = interface->adobe_std_strings( sid );
      FT_UInt      len;
      
      if (adobe_name)
      {
        FT_Memory memory = index->stream->memory;
        FT_Error  error;
        
        len = (FT_UInt)strlen(adobe_name);
        if ( !ALLOC( name, len+1 ) )
        {
          MEM_Copy( name, adobe_name, len );
          name[len] = 0;
        }
      }
      return name;
    }
  }                             
#endif

  LOCAL_FUNC
  FT_Error  T2_Load_CFF_Font( FT_Stream   stream,
                              FT_Int      face_index,
                              CFF_Font*   font )
  {
    static const FT_Frame_Field  cff_header_fields[] = {
                     FT_FRAME_START(4),
                       FT_FRAME_BYTE( CFF_Font,  version_major ),
                       FT_FRAME_BYTE( CFF_Font,  version_minor ),
                       FT_FRAME_BYTE( CFF_Font,  header_size   ),
                       FT_FRAME_BYTE( CFF_Font,  absolute_offsize ),
                     FT_FRAME_END };

    FT_Error  error;
    FT_Memory memory = stream->memory;
    FT_ULong  base_offset;

    MEM_Set( font, 0, sizeof(*font) );
    font->stream = stream;
    font->memory = memory;
    base_offset  = FILE_Pos();

    /* read CFF font header */
    if ( READ_Fields( cff_header_fields, font ) )
      goto Exit;

    /* check format */
    if ( font->version_major   != 1 ||
         font->header_size      < 4 ||
         font->absolute_offsize > 4 )
    {
      FT_ERROR(( "incorrect CFF font header !!\n" ));
      error = FT_Err_Unknown_File_Format;
      goto Exit;
    }

    /* skip the rest of the header */
    (void)FILE_Skip( font->header_size - 4 );

    /* read the name, top dict, string and global subrs index */
    error = t2_new_cff_index( &font->name_index, stream, 0 )       ||
            t2_new_cff_index( &font->top_dict_index, stream, 0 )   ||
            t2_new_cff_index( &font->string_index, stream, 0 )     ||
            t2_new_cff_index( &font->global_subrs_index, stream, 1 );
    if (error) goto Exit;

    /* well, we don't really forget the "disabled" fonts.. */
    font->num_faces = font->name_index.count;
    if (face_index >= font->num_faces)
    {
      FT_ERROR(( "T2.Load_Font: incorrect face index = %d\n", face_index ));
      error = FT_Err_Invalid_Argument;
    }

    /* in case of a font format check, simply exit now */
    if (face_index >= 0)
    {
      T2_Parser  parser;
      FT_Byte*   dict;
      FT_ULong   dict_len;
      CFF_Index* index = &font->top_dict_index;
      CFF_Top_Dict*  top = &font->top_dict;

      /* parse the top-level font dictionary */      
      T2_Parser_Init( &parser, T2CODE_TOPDICT, &font->top_dict );

      /* set defaults */
      memset( top, 0, sizeof(*top) );
      top->underline_position  = -100;
      top->underline_thickness = 50;
      top->charstring_type     = 2;
      top->font_matrix.xx      = 0x10000;
      top->font_matrix.yy      = 0x10000;
      top->cid_count           = 8720;
      
      error = T2_Access_Element( index, face_index, &dict, &dict_len ) ||
              T2_Parser_Run( &parser, dict, dict + dict_len );

      T2_Forget_Element( &font->top_dict_index, &dict );
      if (error) goto Exit;
      
      /* parse the private dictionary, if any */
      if (font->top_dict.private_offset && font->top_dict.private_size)
      {
        CFF_Private*  priv = &font->private_dict;
        
        /* set defaults */
        priv->blue_shift       = 7;
        priv->blue_fuzz        = 1;
        priv->lenIV            = -1;
        priv->expansion_factor = (FT_Fixed)0.06*0x10000;
        priv->blue_scale       = (FT_Fixed)0.039625*0x10000;

        T2_Parser_Init( &parser, T2CODE_PRIVATE, priv );
        
        if ( FILE_Seek( base_offset + font->top_dict.private_offset ) ||
             ACCESS_Frame( font->top_dict.private_size )               )
          goto Exit;

        error = T2_Parser_Run( &parser,
                               (FT_Byte*)stream->cursor,
                               (FT_Byte*)stream->limit );        
        FORGET_Frame();             
        if (error) goto Exit;
      }
      
      /* read the charstrings index now */
      if ( font->top_dict.charstrings_offset == 0 )
      {
        FT_ERROR(( "T2.New_CFF_Font: no charstrings offset !!\n" ));
        error = FT_Err_Unknown_File_Format;
        goto Exit;
      }
      
      if ( FILE_Seek( base_offset + font->top_dict.charstrings_offset ) )
        goto Exit;
        
      error = t2_new_cff_index( &font->charstrings_index, stream, 0 );
      if (error) goto Exit;

      /* read the local subrs */      
      if ( FILE_Seek( base_offset + font->top_dict.private_offset +
                      font->private_dict.local_subrs_offset ) )
        goto Exit;
        
      error = t2_new_cff_index( &font->local_subrs_index, stream, 1 );
      if (error) goto Exit;
      
      /* explicit the global and local subrs */
      font->num_local_subrs  = font->local_subrs_index.count;
      font->num_global_subrs = font->global_subrs_index.count;
      
      error = t2_explicit_cff_index( &font->global_subrs_index,
                                     &font->global_subrs ) ||
              t2_explicit_cff_index( &font->local_subrs_index,
                                     &font->local_subrs );
      if (error) goto Exit;
    }

    /* get the font name */      
    font->font_name = T2_Get_Name( &font->name_index, face_index );

  Exit:
    return error;
  }

  LOCAL_FUNC
  void  T2_Done_CFF_Font( CFF_Font*  font )
  {
    FT_Memory  memory = font->memory;
    
    t2_done_cff_index( &font->global_subrs_index );
    t2_done_cff_index( &font->string_index );
    t2_done_cff_index( &font->top_dict_index );
    t2_done_cff_index( &font->name_index );
    t2_done_cff_index( &font->charstrings_index );

    FREE( font->local_subrs );
    FREE( font->global_subrs );    
    FREE( font->font_name );
  }



 /***********************************************************************/
 /***********************************************************************/
 /***********************************************************************/
 /*****                                                             *****/
 /*****      TYPE 2 TABLES DECODING..                               *****/
 /*****                                                             *****/
 /***********************************************************************/
 /***********************************************************************/
 /***********************************************************************/

/* END */