1e5680279b21106173e342eab28552ae0e027196aDavid Turner/***************************************************************************/
2e5680279b21106173e342eab28552ae0e027196aDavid Turner/*                                                                         */
3e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg/*  ttkern.c                                                               */
4e5680279b21106173e342eab28552ae0e027196aDavid Turner/*                                                                         */
5e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg/*    Load the basic TrueType kerning table.  This doesn't handle          */
6e5680279b21106173e342eab28552ae0e027196aDavid Turner/*    kerning data within the GPOS table at the moment.                    */
7e5680279b21106173e342eab28552ae0e027196aDavid Turner/*                                                                         */
80a0c22569deab933df21127e75db5c81f724f292Werner Lemberg/*  Copyright 1996-2018 by                                                 */
9e5680279b21106173e342eab28552ae0e027196aDavid Turner/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
10e5680279b21106173e342eab28552ae0e027196aDavid Turner/*                                                                         */
11e5680279b21106173e342eab28552ae0e027196aDavid Turner/*  This file is part of the FreeType project, and may only be used,       */
12e5680279b21106173e342eab28552ae0e027196aDavid Turner/*  modified, and distributed under the terms of the FreeType project      */
13e5680279b21106173e342eab28552ae0e027196aDavid Turner/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
14e5680279b21106173e342eab28552ae0e027196aDavid Turner/*  this file you indicate that you have read the license and              */
15e5680279b21106173e342eab28552ae0e027196aDavid Turner/*  understand and accept it fully.                                        */
16e5680279b21106173e342eab28552ae0e027196aDavid Turner/*                                                                         */
17e5680279b21106173e342eab28552ae0e027196aDavid Turner/***************************************************************************/
18e5680279b21106173e342eab28552ae0e027196aDavid Turner
19e5680279b21106173e342eab28552ae0e027196aDavid Turner
20e5680279b21106173e342eab28552ae0e027196aDavid Turner#include <ft2build.h>
21e5680279b21106173e342eab28552ae0e027196aDavid Turner#include FT_INTERNAL_DEBUG_H
22e5680279b21106173e342eab28552ae0e027196aDavid Turner#include FT_INTERNAL_STREAM_H
23e5680279b21106173e342eab28552ae0e027196aDavid Turner#include FT_TRUETYPE_TAGS_H
24e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg#include "ttkern.h"
25e5680279b21106173e342eab28552ae0e027196aDavid Turner
26e5680279b21106173e342eab28552ae0e027196aDavid Turner#include "sferrors.h"
27e5680279b21106173e342eab28552ae0e027196aDavid Turner
28e5680279b21106173e342eab28552ae0e027196aDavid Turner
29e5680279b21106173e342eab28552ae0e027196aDavid Turner  /*************************************************************************/
30e5680279b21106173e342eab28552ae0e027196aDavid Turner  /*                                                                       */
31e5680279b21106173e342eab28552ae0e027196aDavid Turner  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
32e5680279b21106173e342eab28552ae0e027196aDavid Turner  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
33e5680279b21106173e342eab28552ae0e027196aDavid Turner  /* messages during execution.                                            */
34e5680279b21106173e342eab28552ae0e027196aDavid Turner  /*                                                                       */
35e5680279b21106173e342eab28552ae0e027196aDavid Turner#undef  FT_COMPONENT
36e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg#define FT_COMPONENT  trace_ttkern
37e5680279b21106173e342eab28552ae0e027196aDavid Turner
38e5680279b21106173e342eab28552ae0e027196aDavid Turner
39e5680279b21106173e342eab28552ae0e027196aDavid Turner#undef  TT_KERN_INDEX
40e5680279b21106173e342eab28552ae0e027196aDavid Turner#define TT_KERN_INDEX( g1, g2 )  ( ( (FT_ULong)(g1) << 16 ) | (g2) )
41e5680279b21106173e342eab28552ae0e027196aDavid Turner
42e5680279b21106173e342eab28552ae0e027196aDavid Turner
43e5680279b21106173e342eab28552ae0e027196aDavid Turner  FT_LOCAL_DEF( FT_Error )
44e5680279b21106173e342eab28552ae0e027196aDavid Turner  tt_face_load_kern( TT_Face    face,
45e5680279b21106173e342eab28552ae0e027196aDavid Turner                     FT_Stream  stream )
46e5680279b21106173e342eab28552ae0e027196aDavid Turner  {
47e5680279b21106173e342eab28552ae0e027196aDavid Turner    FT_Error   error;
48e5680279b21106173e342eab28552ae0e027196aDavid Turner    FT_ULong   table_size;
49e5680279b21106173e342eab28552ae0e027196aDavid Turner    FT_Byte*   p;
50e5680279b21106173e342eab28552ae0e027196aDavid Turner    FT_Byte*   p_limit;
51e5680279b21106173e342eab28552ae0e027196aDavid Turner    FT_UInt    nn, num_tables;
52e5680279b21106173e342eab28552ae0e027196aDavid Turner    FT_UInt32  avail = 0, ordered = 0;
53e5680279b21106173e342eab28552ae0e027196aDavid Turner
54e5680279b21106173e342eab28552ae0e027196aDavid Turner
55e5680279b21106173e342eab28552ae0e027196aDavid Turner    /* the kern table is optional; exit silently if it is missing */
56e5680279b21106173e342eab28552ae0e027196aDavid Turner    error = face->goto_table( face, TTAG_kern, stream, &table_size );
57e5680279b21106173e342eab28552ae0e027196aDavid Turner    if ( error )
58e5680279b21106173e342eab28552ae0e027196aDavid Turner      goto Exit;
59e5680279b21106173e342eab28552ae0e027196aDavid Turner
60e5680279b21106173e342eab28552ae0e027196aDavid Turner    if ( table_size < 4 )  /* the case of a malformed table */
61e5680279b21106173e342eab28552ae0e027196aDavid Turner    {
62858abbedc0c156965aba830bfc2072a3c21144cfWerner Lemberg      FT_ERROR(( "tt_face_load_kern:"
63858abbedc0c156965aba830bfc2072a3c21144cfWerner Lemberg                 " kerning table is too small - ignored\n" ));
64059bc335ce42220b222763379e89d0cbf2b949ebWerner Lemberg      error = FT_THROW( Table_Missing );
65e5680279b21106173e342eab28552ae0e027196aDavid Turner      goto Exit;
66e5680279b21106173e342eab28552ae0e027196aDavid Turner    }
67e5680279b21106173e342eab28552ae0e027196aDavid Turner
68e5680279b21106173e342eab28552ae0e027196aDavid Turner    if ( FT_FRAME_EXTRACT( table_size, face->kern_table ) )
69e5680279b21106173e342eab28552ae0e027196aDavid Turner    {
70858abbedc0c156965aba830bfc2072a3c21144cfWerner Lemberg      FT_ERROR(( "tt_face_load_kern:"
71858abbedc0c156965aba830bfc2072a3c21144cfWerner Lemberg                 " could not extract kerning table\n" ));
72e5680279b21106173e342eab28552ae0e027196aDavid Turner      goto Exit;
73e5680279b21106173e342eab28552ae0e027196aDavid Turner    }
74e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
75e5680279b21106173e342eab28552ae0e027196aDavid Turner    face->kern_table_size = table_size;
76e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
77e5680279b21106173e342eab28552ae0e027196aDavid Turner    p       = face->kern_table;
78e5680279b21106173e342eab28552ae0e027196aDavid Turner    p_limit = p + table_size;
79e5680279b21106173e342eab28552ae0e027196aDavid Turner
80e5680279b21106173e342eab28552ae0e027196aDavid Turner    p         += 2; /* skip version */
81e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg    num_tables = FT_NEXT_USHORT( p );
82e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
83e5680279b21106173e342eab28552ae0e027196aDavid Turner    if ( num_tables > 32 ) /* we only support up to 32 sub-tables */
84e5680279b21106173e342eab28552ae0e027196aDavid Turner      num_tables = 32;
85e5680279b21106173e342eab28552ae0e027196aDavid Turner
86e5680279b21106173e342eab28552ae0e027196aDavid Turner    for ( nn = 0; nn < num_tables; nn++ )
87e5680279b21106173e342eab28552ae0e027196aDavid Turner    {
883e4b79970e0681bd2481392420a0eb4dc7820b70Werner Lemberg      FT_UInt    num_pairs, length, coverage, format;
89e5680279b21106173e342eab28552ae0e027196aDavid Turner      FT_Byte*   p_next;
90cad4f915555f1eb190753da9b4b8bd58130e4739Suzuki, Toshiya (鈴木俊哉)      FT_UInt32  mask = (FT_UInt32)1UL << nn;
91e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
92e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
93e5680279b21106173e342eab28552ae0e027196aDavid Turner      if ( p + 6 > p_limit )
94e5680279b21106173e342eab28552ae0e027196aDavid Turner        break;
95e5680279b21106173e342eab28552ae0e027196aDavid Turner
96e5680279b21106173e342eab28552ae0e027196aDavid Turner      p_next = p;
97e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
98607dec79bb6ad524a9d2e7f93b836b795fe234cfWerner Lemberg      p += 2; /* skip version */
99e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg      length   = FT_NEXT_USHORT( p );
100e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg      coverage = FT_NEXT_USHORT( p );
101e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
102f70d9342e65cd2cb44e9f26b6d7edeedf191fc6cWerner Lemberg      if ( length <= 6 + 8 )
103e5680279b21106173e342eab28552ae0e027196aDavid Turner        break;
104e5680279b21106173e342eab28552ae0e027196aDavid Turner
105e5680279b21106173e342eab28552ae0e027196aDavid Turner      p_next += length;
106e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
10742f5c714c055d9d8cade2ede35c3abb5ae448a2cWerner Lemberg      if ( p_next > p_limit )  /* handle broken table */
10842f5c714c055d9d8cade2ede35c3abb5ae448a2cWerner Lemberg        p_next = p_limit;
109ab7e52b1c78b27d74e9555c6488c46bd62101804David Turner
1103e4b79970e0681bd2481392420a0eb4dc7820b70Werner Lemberg      format = coverage >> 8;
1113e4b79970e0681bd2481392420a0eb4dc7820b70Werner Lemberg
1123e4b79970e0681bd2481392420a0eb4dc7820b70Werner Lemberg      /* we currently only support format 0 kerning tables */
1133e4b79970e0681bd2481392420a0eb4dc7820b70Werner Lemberg      if ( format != 0 )
1143e4b79970e0681bd2481392420a0eb4dc7820b70Werner Lemberg        goto NextTable;
1153e4b79970e0681bd2481392420a0eb4dc7820b70Werner Lemberg
116e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg      /* only use horizontal kerning tables */
117565f5a7d19d23aa7b3d6f917e5ef6b297b89f384Wojciech Mamrak      if ( ( coverage & 3U ) != 0x0001 ||
118565f5a7d19d23aa7b3d6f917e5ef6b297b89f384Wojciech Mamrak           p + 8 > p_next              )
119e5680279b21106173e342eab28552ae0e027196aDavid Turner        goto NextTable;
120e5680279b21106173e342eab28552ae0e027196aDavid Turner
121e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg      num_pairs = FT_NEXT_USHORT( p );
122e5680279b21106173e342eab28552ae0e027196aDavid Turner      p        += 6;
123e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
1240ae6cf214ff1eec6499c347726a18b8a9809ab2cWerner Lemberg      if ( ( p_next - p ) < 6 * (int)num_pairs ) /* handle broken count */
12542f5c714c055d9d8cade2ede35c3abb5ae448a2cWerner Lemberg        num_pairs = (FT_UInt)( ( p_next - p ) / 6 );
126e5680279b21106173e342eab28552ae0e027196aDavid Turner
127e5680279b21106173e342eab28552ae0e027196aDavid Turner      avail |= mask;
128e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
129e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg      /*
130e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg       *  Now check whether the pairs in this table are ordered.
131e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg       *  We then can use binary search.
132e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg       */
133e5680279b21106173e342eab28552ae0e027196aDavid Turner      if ( num_pairs > 0 )
134e5680279b21106173e342eab28552ae0e027196aDavid Turner      {
1352a2beb47c4b7b61be75ca92c96976ef9f33c64f0Suzuki, Toshiya (鈴木俊哉)        FT_ULong  count;
1362a2beb47c4b7b61be75ca92c96976ef9f33c64f0Suzuki, Toshiya (鈴木俊哉)        FT_ULong  old_pair;
137e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
138e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
139e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg        old_pair = FT_NEXT_ULONG( p );
140e5680279b21106173e342eab28552ae0e027196aDavid Turner        p       += 2;
141e5680279b21106173e342eab28552ae0e027196aDavid Turner
142e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg        for ( count = num_pairs - 1; count > 0; count-- )
143e5680279b21106173e342eab28552ae0e027196aDavid Turner        {
144e5680279b21106173e342eab28552ae0e027196aDavid Turner          FT_UInt32  cur_pair;
145e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
146e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
147e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg          cur_pair = FT_NEXT_ULONG( p );
148e5680279b21106173e342eab28552ae0e027196aDavid Turner          if ( cur_pair <= old_pair )
149e5680279b21106173e342eab28552ae0e027196aDavid Turner            break;
150e5680279b21106173e342eab28552ae0e027196aDavid Turner
151e5680279b21106173e342eab28552ae0e027196aDavid Turner          p += 2;
152e5680279b21106173e342eab28552ae0e027196aDavid Turner          old_pair = cur_pair;
153e5680279b21106173e342eab28552ae0e027196aDavid Turner        }
154e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
155e5680279b21106173e342eab28552ae0e027196aDavid Turner        if ( count == 0 )
156e5680279b21106173e342eab28552ae0e027196aDavid Turner          ordered |= mask;
157e5680279b21106173e342eab28552ae0e027196aDavid Turner      }
158e5680279b21106173e342eab28552ae0e027196aDavid Turner
159e5680279b21106173e342eab28552ae0e027196aDavid Turner    NextTable:
160e5680279b21106173e342eab28552ae0e027196aDavid Turner      p = p_next;
161e5680279b21106173e342eab28552ae0e027196aDavid Turner    }
162e5680279b21106173e342eab28552ae0e027196aDavid Turner
163e5680279b21106173e342eab28552ae0e027196aDavid Turner    face->num_kern_tables = nn;
164e5680279b21106173e342eab28552ae0e027196aDavid Turner    face->kern_avail_bits = avail;
165e5680279b21106173e342eab28552ae0e027196aDavid Turner    face->kern_order_bits = ordered;
166e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
167e5680279b21106173e342eab28552ae0e027196aDavid Turner  Exit:
168e5680279b21106173e342eab28552ae0e027196aDavid Turner    return error;
169e5680279b21106173e342eab28552ae0e027196aDavid Turner  }
170e5680279b21106173e342eab28552ae0e027196aDavid Turner
171e5680279b21106173e342eab28552ae0e027196aDavid Turner
172e5680279b21106173e342eab28552ae0e027196aDavid Turner  FT_LOCAL_DEF( void )
173e5680279b21106173e342eab28552ae0e027196aDavid Turner  tt_face_done_kern( TT_Face  face )
174e5680279b21106173e342eab28552ae0e027196aDavid Turner  {
175e5680279b21106173e342eab28552ae0e027196aDavid Turner    FT_Stream  stream = face->root.stream;
176e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
177e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
178e5680279b21106173e342eab28552ae0e027196aDavid Turner    FT_FRAME_RELEASE( face->kern_table );
179e5680279b21106173e342eab28552ae0e027196aDavid Turner    face->kern_table_size = 0;
180e5680279b21106173e342eab28552ae0e027196aDavid Turner    face->num_kern_tables = 0;
181e5680279b21106173e342eab28552ae0e027196aDavid Turner    face->kern_avail_bits = 0;
182e5680279b21106173e342eab28552ae0e027196aDavid Turner    face->kern_order_bits = 0;
183e5680279b21106173e342eab28552ae0e027196aDavid Turner  }
184e5680279b21106173e342eab28552ae0e027196aDavid Turner
185e5680279b21106173e342eab28552ae0e027196aDavid Turner
186e5680279b21106173e342eab28552ae0e027196aDavid Turner  FT_LOCAL_DEF( FT_Int )
187e5680279b21106173e342eab28552ae0e027196aDavid Turner  tt_face_get_kerning( TT_Face  face,
188e5680279b21106173e342eab28552ae0e027196aDavid Turner                       FT_UInt  left_glyph,
189e5680279b21106173e342eab28552ae0e027196aDavid Turner                       FT_UInt  right_glyph )
190e5680279b21106173e342eab28552ae0e027196aDavid Turner  {
191e5680279b21106173e342eab28552ae0e027196aDavid Turner    FT_Int    result = 0;
192e8ed2d621e4182956488ce15c5611472345e63beWerner Lemberg    FT_UInt   count, mask;
193e5680279b21106173e342eab28552ae0e027196aDavid Turner    FT_Byte*  p       = face->kern_table;
194ab7e52b1c78b27d74e9555c6488c46bd62101804David Turner    FT_Byte*  p_limit = p + face->kern_table_size;
195e5680279b21106173e342eab28552ae0e027196aDavid Turner
196e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
197e5680279b21106173e342eab28552ae0e027196aDavid Turner    p   += 4;
198e5680279b21106173e342eab28552ae0e027196aDavid Turner    mask = 0x0001;
199e5680279b21106173e342eab28552ae0e027196aDavid Turner
200ab7e52b1c78b27d74e9555c6488c46bd62101804David Turner    for ( count = face->num_kern_tables;
201ab7e52b1c78b27d74e9555c6488c46bd62101804David Turner          count > 0 && p + 6 <= p_limit;
202ab7e52b1c78b27d74e9555c6488c46bd62101804David Turner          count--, mask <<= 1 )
203e5680279b21106173e342eab28552ae0e027196aDavid Turner    {
204e5680279b21106173e342eab28552ae0e027196aDavid Turner      FT_Byte* base     = p;
205e8ed2d621e4182956488ce15c5611472345e63beWerner Lemberg      FT_Byte* next;
206e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg      FT_UInt  version  = FT_NEXT_USHORT( p );
207e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg      FT_UInt  length   = FT_NEXT_USHORT( p );
208e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg      FT_UInt  coverage = FT_NEXT_USHORT( p );
209ab7e52b1c78b27d74e9555c6488c46bd62101804David Turner      FT_UInt  num_pairs;
210fa0eb0c95fa954a3097d62c440303c403f466942David Turner      FT_Int   value    = 0;
211e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
212b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg      FT_UNUSED( version );
213b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
214e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
215e5680279b21106173e342eab28552ae0e027196aDavid Turner      next = base + length;
216e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
21742f5c714c055d9d8cade2ede35c3abb5ae448a2cWerner Lemberg      if ( next > p_limit )  /* handle broken table */
218ab7e52b1c78b27d74e9555c6488c46bd62101804David Turner        next = p_limit;
219ab7e52b1c78b27d74e9555c6488c46bd62101804David Turner
220e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg      if ( ( face->kern_avail_bits & mask ) == 0 )
221e5680279b21106173e342eab28552ae0e027196aDavid Turner        goto NextTable;
222e5680279b21106173e342eab28552ae0e027196aDavid Turner
223565f5a7d19d23aa7b3d6f917e5ef6b297b89f384Wojciech Mamrak      FT_ASSERT( p + 8 <= next ); /* tested in tt_face_load_kern */
224e5680279b21106173e342eab28552ae0e027196aDavid Turner
225ab7e52b1c78b27d74e9555c6488c46bd62101804David Turner      num_pairs = FT_NEXT_USHORT( p );
226ab7e52b1c78b27d74e9555c6488c46bd62101804David Turner      p        += 6;
227ab7e52b1c78b27d74e9555c6488c46bd62101804David Turner
2280ae6cf214ff1eec6499c347726a18b8a9809ab2cWerner Lemberg      if ( ( next - p ) < 6 * (int)num_pairs )  /* handle broken count  */
22942f5c714c055d9d8cade2ede35c3abb5ae448a2cWerner Lemberg        num_pairs = (FT_UInt)( ( next - p ) / 6 );
230ab7e52b1c78b27d74e9555c6488c46bd62101804David Turner
231e5680279b21106173e342eab28552ae0e027196aDavid Turner      switch ( coverage >> 8 )
232e5680279b21106173e342eab28552ae0e027196aDavid Turner      {
233e5680279b21106173e342eab28552ae0e027196aDavid Turner      case 0:
234e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg        {
235ab7e52b1c78b27d74e9555c6488c46bd62101804David Turner          FT_ULong  key0 = TT_KERN_INDEX( left_glyph, right_glyph );
236e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
237e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
238e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg          if ( face->kern_order_bits & mask )   /* binary search */
239e5680279b21106173e342eab28552ae0e027196aDavid Turner          {
240e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg            FT_UInt   min = 0;
241e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg            FT_UInt   max = num_pairs;
242fa0eb0c95fa954a3097d62c440303c403f466942David Turner
243e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
244e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg            while ( min < max )
245e5680279b21106173e342eab28552ae0e027196aDavid Turner            {
246e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg              FT_UInt   mid = ( min + max ) >> 1;
247e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg              FT_Byte*  q   = p + 6 * mid;
248e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg              FT_ULong  key;
249e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
250e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
251e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg              key = FT_NEXT_ULONG( q );
252e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
253e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg              if ( key == key0 )
254e5680279b21106173e342eab28552ae0e027196aDavid Turner              {
255e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg                value = FT_PEEK_SHORT( q );
256e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg                goto Found;
257e5680279b21106173e342eab28552ae0e027196aDavid Turner              }
258e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg              if ( key < key0 )
259e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg                min = mid + 1;
260e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg              else
261e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg                max = mid;
262e5680279b21106173e342eab28552ae0e027196aDavid Turner            }
263e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg          }
264e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg          else /* linear search */
265e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg          {
26642137bc6145c426702b90d0cec5c5acd332739aeDavid Turner            FT_UInt  count2;
26742137bc6145c426702b90d0cec5c5acd332739aeDavid Turner
268fa3651e7d8af95b080db00d25a5ada0a5f77ef3dWerner Lemberg
26942137bc6145c426702b90d0cec5c5acd332739aeDavid Turner            for ( count2 = num_pairs; count2 > 0; count2-- )
270e5680279b21106173e342eab28552ae0e027196aDavid Turner            {
271e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg              FT_ULong  key = FT_NEXT_ULONG( p );
272e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
273e5680279b21106173e342eab28552ae0e027196aDavid Turner
274e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg              if ( key == key0 )
275e5680279b21106173e342eab28552ae0e027196aDavid Turner              {
276e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg                value = FT_PEEK_SHORT( p );
277e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg                goto Found;
278e5680279b21106173e342eab28552ae0e027196aDavid Turner              }
279e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg              p += 2;
280e5680279b21106173e342eab28552ae0e027196aDavid Turner            }
281e5680279b21106173e342eab28552ae0e027196aDavid Turner          }
282e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg        }
283e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg        break;
284e5680279b21106173e342eab28552ae0e027196aDavid Turner
285e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg       /*
286fa3651e7d8af95b080db00d25a5ada0a5f77ef3dWerner Lemberg        *  We don't support format 2 because we haven't seen a single font
287e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg        *  using it in real life...
288e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg        */
289e5680279b21106173e342eab28552ae0e027196aDavid Turner
290e5680279b21106173e342eab28552ae0e027196aDavid Turner      default:
291e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg        ;
292e5680279b21106173e342eab28552ae0e027196aDavid Turner      }
293e5680279b21106173e342eab28552ae0e027196aDavid Turner
294fa0eb0c95fa954a3097d62c440303c403f466942David Turner      goto NextTable;
295e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
296fa0eb0c95fa954a3097d62c440303c403f466942David Turner    Found:
2976e87ed9f04f7914e15f9284b0b762b730222c399Werner Lemberg      if ( coverage & 8 ) /* override or add */
298e5680279b21106173e342eab28552ae0e027196aDavid Turner        result = value;
299e5680279b21106173e342eab28552ae0e027196aDavid Turner      else
300e5680279b21106173e342eab28552ae0e027196aDavid Turner        result += value;
301e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
302e5680279b21106173e342eab28552ae0e027196aDavid Turner    NextTable:
303e5680279b21106173e342eab28552ae0e027196aDavid Turner      p = next;
304e5680279b21106173e342eab28552ae0e027196aDavid Turner    }
305e5680279b21106173e342eab28552ae0e027196aDavid Turner
306e5680279b21106173e342eab28552ae0e027196aDavid Turner    return result;
307e5680279b21106173e342eab28552ae0e027196aDavid Turner  }
308e5680279b21106173e342eab28552ae0e027196aDavid Turner
309e5680279b21106173e342eab28552ae0e027196aDavid Turner#undef TT_KERN_INDEX
310e793092d0a9f4d4d383315bcefd485dcbe4804b3Werner Lemberg
311e5680279b21106173e342eab28552ae0e027196aDavid Turner/* END */
312