misc/libfreetype/src/sfnt/ttkern.c
branchwebgl
changeset 9521 8054d9d775fd
parent 9282 92af50454cf2
parent 9519 b8b5c82eb61b
child 9950 2759212a27de
equal deleted inserted replaced
9282:92af50454cf2 9521:8054d9d775fd
     1 /***************************************************************************/
       
     2 /*                                                                         */
       
     3 /*  ttkern.c                                                               */
       
     4 /*                                                                         */
       
     5 /*    Load the basic TrueType kerning table.  This doesn't handle          */
       
     6 /*    kerning data within the GPOS table at the moment.                    */
       
     7 /*                                                                         */
       
     8 /*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010 by */
       
     9 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
       
    10 /*                                                                         */
       
    11 /*  This file is part of the FreeType project, and may only be used,       */
       
    12 /*  modified, and distributed under the terms of the FreeType project      */
       
    13 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
       
    14 /*  this file you indicate that you have read the license and              */
       
    15 /*  understand and accept it fully.                                        */
       
    16 /*                                                                         */
       
    17 /***************************************************************************/
       
    18 
       
    19 
       
    20 #include <ft2build.h>
       
    21 #include FT_INTERNAL_DEBUG_H
       
    22 #include FT_INTERNAL_STREAM_H
       
    23 #include FT_TRUETYPE_TAGS_H
       
    24 #include "ttkern.h"
       
    25 
       
    26 #include "sferrors.h"
       
    27 
       
    28 
       
    29   /*************************************************************************/
       
    30   /*                                                                       */
       
    31   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
       
    32   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
       
    33   /* messages during execution.                                            */
       
    34   /*                                                                       */
       
    35 #undef  FT_COMPONENT
       
    36 #define FT_COMPONENT  trace_ttkern
       
    37 
       
    38 
       
    39 #undef  TT_KERN_INDEX
       
    40 #define TT_KERN_INDEX( g1, g2 )  ( ( (FT_ULong)(g1) << 16 ) | (g2) )
       
    41 
       
    42 
       
    43   FT_LOCAL_DEF( FT_Error )
       
    44   tt_face_load_kern( TT_Face    face,
       
    45                      FT_Stream  stream )
       
    46   {
       
    47     FT_Error   error;
       
    48     FT_ULong   table_size;
       
    49     FT_Byte*   p;
       
    50     FT_Byte*   p_limit;
       
    51     FT_UInt    nn, num_tables;
       
    52     FT_UInt32  avail = 0, ordered = 0;
       
    53 
       
    54 
       
    55     /* the kern table is optional; exit silently if it is missing */
       
    56     error = face->goto_table( face, TTAG_kern, stream, &table_size );
       
    57     if ( error )
       
    58       goto Exit;
       
    59 
       
    60     if ( table_size < 4 )  /* the case of a malformed table */
       
    61     {
       
    62       FT_ERROR(( "tt_face_load_kern:"
       
    63                  " kerning table is too small - ignored\n" ));
       
    64       error = SFNT_Err_Table_Missing;
       
    65       goto Exit;
       
    66     }
       
    67 
       
    68     if ( FT_FRAME_EXTRACT( table_size, face->kern_table ) )
       
    69     {
       
    70       FT_ERROR(( "tt_face_load_kern:"
       
    71                  " could not extract kerning table\n" ));
       
    72       goto Exit;
       
    73     }
       
    74 
       
    75     face->kern_table_size = table_size;
       
    76 
       
    77     p       = face->kern_table;
       
    78     p_limit = p + table_size;
       
    79 
       
    80     p         += 2; /* skip version */
       
    81     num_tables = FT_NEXT_USHORT( p );
       
    82 
       
    83     if ( num_tables > 32 ) /* we only support up to 32 sub-tables */
       
    84       num_tables = 32;
       
    85 
       
    86     for ( nn = 0; nn < num_tables; nn++ )
       
    87     {
       
    88       FT_UInt    num_pairs, length, coverage;
       
    89       FT_Byte*   p_next;
       
    90       FT_UInt32  mask = (FT_UInt32)1UL << nn;
       
    91 
       
    92 
       
    93       if ( p + 6 > p_limit )
       
    94         break;
       
    95 
       
    96       p_next = p;
       
    97 
       
    98       p += 2; /* skip version */
       
    99       length   = FT_NEXT_USHORT( p );
       
   100       coverage = FT_NEXT_USHORT( p );
       
   101 
       
   102       if ( length <= 6 )
       
   103         break;
       
   104 
       
   105       p_next += length;
       
   106 
       
   107       if ( p_next > p_limit )  /* handle broken table */
       
   108         p_next = p_limit;
       
   109 
       
   110       /* only use horizontal kerning tables */
       
   111       if ( ( coverage & ~8 ) != 0x0001 ||
       
   112            p + 8 > p_limit             )
       
   113         goto NextTable;
       
   114 
       
   115       num_pairs = FT_NEXT_USHORT( p );
       
   116       p        += 6;
       
   117 
       
   118       if ( ( p_next - p ) < 6 * (int)num_pairs ) /* handle broken count */
       
   119         num_pairs = (FT_UInt)( ( p_next - p ) / 6 );
       
   120 
       
   121       avail |= mask;
       
   122 
       
   123       /*
       
   124        *  Now check whether the pairs in this table are ordered.
       
   125        *  We then can use binary search.
       
   126        */
       
   127       if ( num_pairs > 0 )
       
   128       {
       
   129         FT_ULong  count;
       
   130         FT_ULong  old_pair;
       
   131 
       
   132 
       
   133         old_pair = FT_NEXT_ULONG( p );
       
   134         p       += 2;
       
   135 
       
   136         for ( count = num_pairs - 1; count > 0; count-- )
       
   137         {
       
   138           FT_UInt32  cur_pair;
       
   139 
       
   140 
       
   141           cur_pair = FT_NEXT_ULONG( p );
       
   142           if ( cur_pair <= old_pair )
       
   143             break;
       
   144 
       
   145           p += 2;
       
   146           old_pair = cur_pair;
       
   147         }
       
   148 
       
   149         if ( count == 0 )
       
   150           ordered |= mask;
       
   151       }
       
   152 
       
   153     NextTable:
       
   154       p = p_next;
       
   155     }
       
   156 
       
   157     face->num_kern_tables = nn;
       
   158     face->kern_avail_bits = avail;
       
   159     face->kern_order_bits = ordered;
       
   160 
       
   161   Exit:
       
   162     return error;
       
   163   }
       
   164 
       
   165 
       
   166   FT_LOCAL_DEF( void )
       
   167   tt_face_done_kern( TT_Face  face )
       
   168   {
       
   169     FT_Stream  stream = face->root.stream;
       
   170 
       
   171 
       
   172     FT_FRAME_RELEASE( face->kern_table );
       
   173     face->kern_table_size = 0;
       
   174     face->num_kern_tables = 0;
       
   175     face->kern_avail_bits = 0;
       
   176     face->kern_order_bits = 0;
       
   177   }
       
   178 
       
   179 
       
   180   FT_LOCAL_DEF( FT_Int )
       
   181   tt_face_get_kerning( TT_Face  face,
       
   182                        FT_UInt  left_glyph,
       
   183                        FT_UInt  right_glyph )
       
   184   {
       
   185     FT_Int    result = 0;
       
   186     FT_UInt   count, mask = 1;
       
   187     FT_Byte*  p       = face->kern_table;
       
   188     FT_Byte*  p_limit = p + face->kern_table_size;
       
   189 
       
   190 
       
   191     p   += 4;
       
   192     mask = 0x0001;
       
   193 
       
   194     for ( count = face->num_kern_tables;
       
   195           count > 0 && p + 6 <= p_limit;
       
   196           count--, mask <<= 1 )
       
   197     {
       
   198       FT_Byte* base     = p;
       
   199       FT_Byte* next     = base;
       
   200       FT_UInt  version  = FT_NEXT_USHORT( p );
       
   201       FT_UInt  length   = FT_NEXT_USHORT( p );
       
   202       FT_UInt  coverage = FT_NEXT_USHORT( p );
       
   203       FT_UInt  num_pairs;
       
   204       FT_Int   value    = 0;
       
   205 
       
   206       FT_UNUSED( version );
       
   207 
       
   208 
       
   209       next = base + length;
       
   210 
       
   211       if ( next > p_limit )  /* handle broken table */
       
   212         next = p_limit;
       
   213 
       
   214       if ( ( face->kern_avail_bits & mask ) == 0 )
       
   215         goto NextTable;
       
   216 
       
   217       if ( p + 8 > next )
       
   218         goto NextTable;
       
   219 
       
   220       num_pairs = FT_NEXT_USHORT( p );
       
   221       p        += 6;
       
   222 
       
   223       if ( ( next - p ) < 6 * (int)num_pairs )  /* handle broken count  */
       
   224         num_pairs = (FT_UInt)( ( next - p ) / 6 );
       
   225 
       
   226       switch ( coverage >> 8 )
       
   227       {
       
   228       case 0:
       
   229         {
       
   230           FT_ULong  key0 = TT_KERN_INDEX( left_glyph, right_glyph );
       
   231 
       
   232 
       
   233           if ( face->kern_order_bits & mask )   /* binary search */
       
   234           {
       
   235             FT_UInt   min = 0;
       
   236             FT_UInt   max = num_pairs;
       
   237 
       
   238 
       
   239             while ( min < max )
       
   240             {
       
   241               FT_UInt   mid = ( min + max ) >> 1;
       
   242               FT_Byte*  q   = p + 6 * mid;
       
   243               FT_ULong  key;
       
   244 
       
   245 
       
   246               key = FT_NEXT_ULONG( q );
       
   247 
       
   248               if ( key == key0 )
       
   249               {
       
   250                 value = FT_PEEK_SHORT( q );
       
   251                 goto Found;
       
   252               }
       
   253               if ( key < key0 )
       
   254                 min = mid + 1;
       
   255               else
       
   256                 max = mid;
       
   257             }
       
   258           }
       
   259           else /* linear search */
       
   260           {
       
   261             FT_UInt  count2;
       
   262 
       
   263 
       
   264             for ( count2 = num_pairs; count2 > 0; count2-- )
       
   265             {
       
   266               FT_ULong  key = FT_NEXT_ULONG( p );
       
   267 
       
   268 
       
   269               if ( key == key0 )
       
   270               {
       
   271                 value = FT_PEEK_SHORT( p );
       
   272                 goto Found;
       
   273               }
       
   274               p += 2;
       
   275             }
       
   276           }
       
   277         }
       
   278         break;
       
   279 
       
   280        /*
       
   281         *  We don't support format 2 because we haven't seen a single font
       
   282         *  using it in real life...
       
   283         */
       
   284 
       
   285       default:
       
   286         ;
       
   287       }
       
   288 
       
   289       goto NextTable;
       
   290 
       
   291     Found:
       
   292       if ( coverage & 8 ) /* override or add */
       
   293         result = value;
       
   294       else
       
   295         result += value;
       
   296 
       
   297     NextTable:
       
   298       p = next;
       
   299     }
       
   300 
       
   301     return result;
       
   302   }
       
   303 
       
   304 #undef TT_KERN_INDEX
       
   305 
       
   306 /* END */