shithub: freetype+ttf2subf

ref: 35eee3f3078bd06431f54813870a2417f686b252
dir: /src/otlayout/oltypes.c/

View raw version
#include <oltypes.h>

  LOCAL_FUNC
  TT_Error  OTL_Table_Init( OTL_Table*  table,
                            FT_Memory   memory )
  {
    MEM_Set( table, 0, sizeof(*table) );
    table->memory = memory;
  }

 /* read a script list table */
 /* use with any table       */
  LOCAL_FUNC
  TT_Error  OTL_Table_Set_Scripts( OTL_Table*  table,
                                   TT_Byte*    bytes,
                                   TT_Long     len,
                                   OTL_Type    otl_type )
  {
    TT_Byte*  p;
    TT_Byte*  start = bytes;
    TT_UInt   count, max_langs;
    TT_Error  error;

    /* skip version of the JSTF table */    
    if (otl_type == otl_jstf)
      start += 4;
      
    p = start;
      
    /* we must allocate the script_tags and language_tags arrays     */
    /* this requires that we compute the maximum number of languages */
    /* per script..                                                  */
    
    count     = table->num_scripts = OTL_UShort(p);
    max_langs = 0;
    for ( ; count > 0; count++ )
    {
      TT_Byte*  script;
      TT_UInt   num_langs;
      
      p += 4; /* skip tag */
      script = bytes + OTL_UShort(p);

      /* skip the baseValues or extenders field of the BASE and JSTF table */
      if (otl_type == otl_type_base || otl_type == otl_type_jstf)
        script += 2;

      /* test if there is a default language system */
      if ( OTL_UShort(script) )
        num_langs++;
      
      /* test other language systems */
      num_langs += OTL_UShort(script); /* add other lang sys */
      
      if (num_langs > max_langs)
        max_langs = num_langs;
    }

    /* good, now allocate the tag arrays */
    if ( !ALLOC_ARRAY( table->script_tags,
                      table->num_scripts + max_langs,
                      TT_ULong ) )
    {
      table->language_tags = table->script_tags + table->num_scripts;
      table->max_languages = max_langs;
      table->num_languages = 0;
      table->otl_type      = otl_type;
  
      table->scripts_table = bytes;
      table->scripts_len   = len;
      
      /* fill the script_tags array */
      {
        TT_UInt  n;
        TT_Byte* p = start + 2; /* skip count */
        
        for ( n = 0; n < table->num_scripts; n++ )
        {
          table->script_tags[n] = OTL_ULong(p);
          p += 2; /* skip offset */
        }
      }
    }
    return error;
  }



 /* add a features list to the table   */
 /* use only with a GSUB or GPOS table */
  LOCAL_FUNC
  TT_Error  OTL_Table_Set_Features( OTL_Table*  table,
                                    TT_Byte*    bytes,
                                    TT_Long     len )
  {
    TT_Error  error;
    TT_Byte*  p = bytes;
    TT_UInt   count;
    
    table->max_features = count = OTL_UShort(p);
    if ( !ALLOC_ARRAY( table->feature_tags, count, TT_ULong ) &&
         !ALLOC_ARRAY( table->features,     count, TT_Bool  ) )
    {
      table->features_table = bytes;
      table->features_len   = len;
    }
    return error;     
  }


 /* add a lookup list to the table     */
 /* use only with a GSUB or GPOS table */
  LOCAL_FUNC
  TT_Error  OTL_Table_Set_Lookups( OTL_Table*  table,
                                   TT_Byte*    bytes,
                                   TT_Long     len )
  {
    TT_Error  error;
    TT_Byte*  p = bytes;
    TT_UInt   count;
    
    table->max_lookups = count = OTL_UShort(p);
    if ( !ALLOC_ARRAY( table->lookups, count, TT_Bool ) )
    {
      table->lookups_table = bytes;
      table->lookups_len   = len;
    }
    return error;     
  }

 /* discard table arrays */
  LOCAL_FUNC
  void      OTL_Table_Done( OTL_Table*  table )
  {
    FREE( table->scrip_tags );
    FREE( table->language_tags );
    FREE( table->feature_tags );
    FREE( table->lookups );
  }


 /* return the list of available languages for a given script */
 /* use with any table..                                      */
  LOCAL_FUNC
  void  OTL_Get_Languages_List( OTL_Table*  table,
                                TT_ULong    script_tag )
  {
    TT_UInt  n;
    TT_Byte* p;
    TT_Byte* script = 0;
    TT_Byte* start = table->scripts_table;
    
    if ( table->otl_type == otl_type_jstf )  /* skip version for JSTF */
      start += 4;
      
    p = start + 6; /* skip count+first tag */
    
    for ( n = 0; n < table->num_scripts; n++, p += 6 )
    {
      if ( table->script_tags[n] == script_tag )
      {
        script = table->scripts_table + OTL_UShort(p);
        break;
      }
    }
    
    table->cur_script = script;
    if (!script)
      table->num_languages = 0;
    else
    {
      /* now fill the language_tags array with the appropriate values    */
      /* not that we put a '0' tag in front of the list to indicate that */
      /* there is a default language for this script..                   */
      TT_ULong* tags = table->language_tags;
      
      switch (table->otl_type)
      {
        case otl_type_base:
        case otl_type_jstf:
          script += 2;    /* skip basevalue or extenders */
          /* fall-through */
          
        default:
          if ( OTL_UShort(script) )
            *tags++ = 0;
      }
      
      count = OTL_UShort(script);
      for ( ; count > 0; count-- )
      {
        *tags++ = OTL_ULong(script);
        script += 2; /* skip offset */
      }
      
      table->num_langs = tags - table->language_tags;
    }
  }

  
 /* return the list of available features for the current script/language */
 /* use with a GPOS or GSUB script table                                  */
  LOCAL_FUNC
  void OTL_Get_Features_List( OTL_Table*  table,
                              TT_ULong    language_tag )
  {
    TT_UInt   n;
    TT_Byte*  script   = table->cur_script;
    TT_Byte*  language = 0;
    TT_UShort offset;

    /* clear feature selection table */
    for ( n = 0; n < table->max_features; n++ )
      table->features[n] = 0;

    /* now, look for the current language */
    if ( language_tag == 0 )
    {
      offset = OTL_UShort(script);
      if (!offset) return; /* if there is no default language, exit */
        
      language = script - 2 + offset;
    }
    else
    {
      TT_Byte*  p = script + 8; /* skip default+count+1st tag */
      TT_UShort index;
      
      for ( n = 0; n < table->num_languages; n++, p+=6 )
      {
        if ( table->language_tags[n] == language_tag )
        {
          language = script + OTL_UShort(p);
          break;
        }
      }

      table->cur_language = language; 
      if (!language) return;
      
      p     = language + 2;   /* skip lookup order */
      index = OTL_UShort(p);  /* required feature index */
      if (index != 0xFFFF)
      {
        if (index < table->max_features)
          table->features[index] = 1;
      }
      
      count = OTL_UShort(p);
      for ( ; count > 0; count-- )
      {
        index = OTL_UShort(p);
        if (index < table->max_features)
          table->features[index] = 1;
      }
    }
  }


 /* return the list of lookups for the current features list */
 /* use only with a GSUB or GPOS table                       */
  LOCAL_FUNC
  void  OTL_Get_Lookups_List( OTL_Table*  table )
  {
    TT_UInt  n;
    TT_Byte* features = table->features_table;
    TT_Byte* p        = features + 6; /* skip count+1st tag */
    
    /* clear lookup list */
    for ( n = 0; n < table->max_lookups; n++ )
      table->lookups[n] = 0;
      
    /* now, parse the features list */
    for ( n = 0; n < table->features; n++ )
    {
      if (table->features[n])
      {
        TT_UInt   count;
        TT_UShort index;
        TT_Byte*  feature;
        
        feature = features + OTL_UShort(p);
        p      += 4;  /* skip tag */
        
        /* now, select all lookups from this feature */
        count = OTL_UShort(feature);
        for ( ; count > 0; count-- )
        {
          index = OTL_UShort(feature);
          if (index < table->max_lookups)
            table->lookups[index] = 1;
        }
      }
    }
  }
  

 /* find the basevalues and minmax for the current script/language */  
 /* only use it with a BASE table..                                */
  LOCAL_FUNC
  void OTL_Get_Baseline_Values( OTL_Table*  table,
                                TT_ULong    language_tag )
  {
    TT_Byte*  script   = table->cur_script;
    TT_Byte*  p        = script;
    TT_UShort offset, count;

    table->cur_basevalues = 0;
    table->cur_minmax     = 0;
    
    /* read basevalues */    
    offset = OTL_UShort(p);
    if (offset)
      table->cur_basevalues = script + offset;
      
    offset = OTL_UShort(p);
    if (offset)
      table->cur_minmax = script + offset;

    count = OTL_UShort(p);
    for ( ; count > 0; count-- )
    {
      TT_ULong  tag;
      
      tag = OTL_ULong(p);
      if ( language_tag == tag )
      {
        table->cur_minmax = script + OTL_UShort(p);
        break;
      }
      p += 2; /* skip offset */
    }
  }


 /* compute the coverage value of a given glyph id */
  LOCAL_FUNC
  TT_Long  OTL_Get_Coverage_Index( TT_Byte*  coverage,
                                   TT_UInt   glyph_id )
  {
    TT_Long    result = -1;
    TT_UInt    count, index, start, end;
    TT_Byte*   p = coverage;
    
    switch ( OTL_UShort(p) )
    {
      case 1:  /* coverage format 1 - array of glyph indices */
        {
          count = OTL_UShort(p);
          for ( index = 0; index < count; index++ )
          {
            if ( OTL_UShort(p) == glyph_id )
            {
              result = index;
              break;
            }
          }
        }
        break;
        
      case 2:
        {
          count = OTL_UShort(p);
          for ( ; count > 0; count-- )
          {
            start = OTL_UShort(p);
            end   = OTL_UShort(p);
            index = OTL_UShort(p);
            if (start <= glyph_id && glyph_id <= end)
            {
              result = glyph_id - start + index;
              break;
            }
          }
        }
        break;
    }
    return result;
  }


 /* compute the class value of a given glyph_id */
  LOCAL_FUNC
  TT_UInt  OTL_Get_Glyph_Class( TT_Byte*  class_def,
                                TT_UInt   glyph_id )
  {
    TT_Byte*  p = class_def;
    TT_UInt   result = 0;
    TT_UInt   start, end, count, index;
    
    switch ( OTL_UShort(p) )
    {
      case 1:
        {
          start = OTL_UShort(p);
          count = OTL_UShort(p);
          
          glyph_id -= start;
          if (glyph_id < count)
          {
            p += 2*glyph_id;
            result = OTL_UShort(p);
          }
        }
        break;
      
      case 2:
        {
          count = OTL_UShort(p);
          for ( ; count > 0; count-- )
          {
            start = OTL_UShort(p);
            end   = OTL_UShort(p);
            index = OTL_UShort(p);
            if ( start <= glyph_id && glyph_id <= end )
            {
              result = index;
              break;
            }
          }
        }
        break;
    }
    return result;
  }


 /* compute the adjustement necessary for a given device size */
  LOCAL_FUNC
  TT_Int  OTL_Get_Device_Adjustment( TT_Byte* device,
                                     TT_UInt  size )
  {
    TT_Byte*  p = device;
    TT_Int    result = 0;
    TT_UInt   start, end;
    TT_Short  value;
    
    start = OTL_UShort(p);
    end   = OTL_UShort(p);
    if (size >= start && size <= end)
    {
      /* I know we could do all of this without a switch, with */
      /* clever shifts and everything, but it makes the code   */
      /* really difficult to understand..                      */
      
      size -= start;
      switch ( OTL_UShort(p) )
      {
        case 1: /* 2-bits per value */
          {
            p     += 2*(size >> 3);
            size   = (size & 7) << 1;
            value  = (TT_Short)((TT_Short)OTL_UShort(p) << size);
            result = value >> 14;
          }
          break;
          
        case 2: /* 4-bits per value */
          {
            p     += 2*(size >> 2);
            size   = (size & 3) << 2;
            value  = (TT_Short)((TT_Short)OTL_UShort(p) << size);
            result = value >> 12;
          }
          break;
          
        case 3: /* 8-bits per value */
          {
            p     += 2*(size >> 1);
            size   = (size & 1) << 3;
            value  = (TT_Short)((TT_Short)OTL_UShort(p) << size);
            result = value >> 8;
          }
          break;
      }
    }
    return result;
  }
  
 /* compute a BaseCoord value */
  LOCAL_FUNC
  TT_Int  OTL_Get_Base_Coordinate( TT_Byte*   base_coord,
                                   TT_UShort *format
                                   TT_UShort *ref_glyph_id,
                                   TT_Byte*  *device )
  {
    TT_Byte*  p =base_coord;
    TT_Int    result = 0;
    
    *format = OTL_UShort(p);
    
    switch (*format)
    {
      case
    }
  }