1/***************************************************************************/
2/*                                                                         */
3/*  ttpload.c                                                              */
4/*                                                                         */
5/*    TrueType-specific tables loader (body).                              */
6/*                                                                         */
7/*  Copyright 1996-2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009 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 FT_INTERNAL_DEBUG_H
21#include FT_INTERNAL_OBJECTS_H
22#include FT_INTERNAL_STREAM_H
23#include FT_TRUETYPE_TAGS_H
24
25#include "ttpload.h"
26
27#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
28#include "ttgxvar.h"
29#endif
30
31#include "tterrors.h"
32
33
34  /*************************************************************************/
35  /*                                                                       */
36  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
37  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
38  /* messages during execution.                                            */
39  /*                                                                       */
40#undef  FT_COMPONENT
41#define FT_COMPONENT  trace_ttpload
42
43
44  /*************************************************************************/
45  /*                                                                       */
46  /* <Function>                                                            */
47  /*    tt_face_load_loca                                                  */
48  /*                                                                       */
49  /* <Description>                                                         */
50  /*    Load the locations table.                                          */
51  /*                                                                       */
52  /* <InOut>                                                               */
53  /*    face   :: A handle to the target face object.                      */
54  /*                                                                       */
55  /* <Input>                                                               */
56  /*    stream :: The input stream.                                        */
57  /*                                                                       */
58  /* <Return>                                                              */
59  /*    FreeType error code.  0 means success.                             */
60  /*                                                                       */
61  FT_LOCAL_DEF( FT_Error )
62  tt_face_load_loca( TT_Face    face,
63                     FT_Stream  stream )
64  {
65    FT_Error  error;
66    FT_ULong  table_len;
67    FT_Int    shift;
68
69
70    /* we need the size of the `glyf' table for malformed `loca' tables */
71    error = face->goto_table( face, TTAG_glyf, stream, &face->glyf_len );
72
73    /* it is possible that a font doesn't have a glyf table at all */
74    /* or its size is zero                                         */
75    if ( error == TT_Err_Table_Missing )
76      face->glyf_len = 0;
77    else if ( error )
78      goto Exit;
79
80    FT_TRACE2(( "Locations " ));
81    error = face->goto_table( face, TTAG_loca, stream, &table_len );
82    if ( error )
83    {
84      error = TT_Err_Locations_Missing;
85      goto Exit;
86    }
87
88    if ( face->header.Index_To_Loc_Format != 0 )
89    {
90      shift = 2;
91
92      if ( table_len >= 0x40000L )
93      {
94        FT_TRACE2(( "table too large\n" ));
95        error = TT_Err_Invalid_Table;
96        goto Exit;
97      }
98      face->num_locations = table_len >> shift;
99    }
100    else
101    {
102      shift = 1;
103
104      if ( table_len >= 0x20000L )
105      {
106        FT_TRACE2(( "table too large\n" ));
107        error = TT_Err_Invalid_Table;
108        goto Exit;
109      }
110      face->num_locations = table_len >> shift;
111    }
112
113    if ( face->num_locations != (FT_ULong)face->root.num_glyphs )
114    {
115      FT_TRACE2(( "glyph count mismatch!  loca: %d, maxp: %d\n",
116                  face->num_locations, face->root.num_glyphs ));
117
118      /* we only handle the case where `maxp' gives a larger value */
119      if ( face->num_locations < (FT_ULong)face->root.num_glyphs )
120      {
121        FT_Long   new_loca_len = (FT_Long)face->root.num_glyphs << shift;
122
123        TT_Table  entry = face->dir_tables;
124        TT_Table  limit = entry + face->num_tables;
125
126        FT_Long   pos  = FT_Stream_Pos( stream );
127        FT_Long   dist = 0x7FFFFFFFL;
128
129
130        /* compute the distance to next table in font file */
131        for ( ; entry < limit; entry++ )
132        {
133          FT_Long  diff = entry->Offset - pos;
134
135
136          if ( diff > 0 && diff < dist )
137            dist = diff;
138        }
139
140        if ( new_loca_len <= dist )
141        {
142          face->num_locations = face->root.num_glyphs;
143          table_len           = new_loca_len;
144
145          FT_TRACE2(( "adjusting num_locations to %d\n",
146                      face->num_locations ));
147        }
148      }
149    }
150
151    /*
152     * Extract the frame.  We don't need to decompress it since
153     * we are able to parse it directly.
154     */
155    if ( FT_FRAME_EXTRACT( table_len, face->glyph_locations ) )
156      goto Exit;
157
158    FT_TRACE2(( "loaded\n" ));
159
160  Exit:
161    return error;
162  }
163
164
165  FT_LOCAL_DEF( FT_ULong )
166  tt_face_get_location( TT_Face   face,
167                        FT_UInt   gindex,
168                        FT_UInt  *asize )
169  {
170    FT_ULong  pos1, pos2;
171    FT_Byte*  p;
172    FT_Byte*  p_limit;
173
174
175    pos1 = pos2 = 0;
176
177    if ( gindex < face->num_locations )
178    {
179      if ( face->header.Index_To_Loc_Format != 0 )
180      {
181        p       = face->glyph_locations + gindex * 4;
182        p_limit = face->glyph_locations + face->num_locations * 4;
183
184        pos1 = FT_NEXT_ULONG( p );
185        pos2 = pos1;
186
187        if ( p + 4 <= p_limit )
188          pos2 = FT_NEXT_ULONG( p );
189      }
190      else
191      {
192        p       = face->glyph_locations + gindex * 2;
193        p_limit = face->glyph_locations + face->num_locations * 2;
194
195        pos1 = FT_NEXT_USHORT( p );
196        pos2 = pos1;
197
198        if ( p + 2 <= p_limit )
199          pos2 = FT_NEXT_USHORT( p );
200
201        pos1 <<= 1;
202        pos2 <<= 1;
203      }
204    }
205
206    /* The `loca' table must be ordered; it refers to the length of */
207    /* an entry as the difference between the current and the next  */
208    /* position.  However, there do exist (malformed) fonts which   */
209    /* don't obey this rule, so we are only able to provide an      */
210    /* upper bound for the size.                                    */
211    /*                                                              */
212    /* We get (intentionally) a wrong, non-zero result in case the  */
213    /* `glyf' table is missing.                                     */
214    if ( pos2 >= pos1 )
215      *asize = (FT_UInt)( pos2 - pos1 );
216    else
217      *asize = (FT_UInt)( face->glyf_len - pos1 );
218
219    return pos1;
220  }
221
222
223  FT_LOCAL_DEF( void )
224  tt_face_done_loca( TT_Face  face )
225  {
226    FT_Stream  stream = face->root.stream;
227
228
229    FT_FRAME_RELEASE( face->glyph_locations );
230    face->num_locations = 0;
231  }
232
233
234
235  /*************************************************************************/
236  /*                                                                       */
237  /* <Function>                                                            */
238  /*    tt_face_load_cvt                                                   */
239  /*                                                                       */
240  /* <Description>                                                         */
241  /*    Load the control value table into a face object.                   */
242  /*                                                                       */
243  /* <InOut>                                                               */
244  /*    face   :: A handle to the target face object.                      */
245  /*                                                                       */
246  /* <Input>                                                               */
247  /*    stream :: A handle to the input stream.                            */
248  /*                                                                       */
249  /* <Return>                                                              */
250  /*    FreeType error code.  0 means success.                             */
251  /*                                                                       */
252  FT_LOCAL_DEF( FT_Error )
253  tt_face_load_cvt( TT_Face    face,
254                    FT_Stream  stream )
255  {
256#ifdef TT_USE_BYTECODE_INTERPRETER
257
258    FT_Error   error;
259    FT_Memory  memory = stream->memory;
260    FT_ULong   table_len;
261
262
263    FT_TRACE2(( "CVT " ));
264
265    error = face->goto_table( face, TTAG_cvt, stream, &table_len );
266    if ( error )
267    {
268      FT_TRACE2(( "is missing\n" ));
269
270      face->cvt_size = 0;
271      face->cvt      = NULL;
272      error          = TT_Err_Ok;
273
274      goto Exit;
275    }
276
277    face->cvt_size = table_len / 2;
278
279    if ( FT_NEW_ARRAY( face->cvt, face->cvt_size ) )
280      goto Exit;
281
282    if ( FT_FRAME_ENTER( face->cvt_size * 2L ) )
283      goto Exit;
284
285    {
286      FT_Short*  cur   = face->cvt;
287      FT_Short*  limit = cur + face->cvt_size;
288
289
290      for ( ; cur <  limit; cur++ )
291        *cur = FT_GET_SHORT();
292    }
293
294    FT_FRAME_EXIT();
295    FT_TRACE2(( "loaded\n" ));
296
297#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
298    if ( face->doblend )
299      error = tt_face_vary_cvt( face, stream );
300#endif
301
302  Exit:
303    return error;
304
305#else /* !TT_USE_BYTECODE_INTERPRETER */
306
307    FT_UNUSED( face   );
308    FT_UNUSED( stream );
309
310    return TT_Err_Ok;
311
312#endif
313  }
314
315
316  /*************************************************************************/
317  /*                                                                       */
318  /* <Function>                                                            */
319  /*    tt_face_load_fpgm                                                  */
320  /*                                                                       */
321  /* <Description>                                                         */
322  /*    Load the font program.                                             */
323  /*                                                                       */
324  /* <InOut>                                                               */
325  /*    face   :: A handle to the target face object.                      */
326  /*                                                                       */
327  /* <Input>                                                               */
328  /*    stream :: A handle to the input stream.                            */
329  /*                                                                       */
330  /* <Return>                                                              */
331  /*    FreeType error code.  0 means success.                             */
332  /*                                                                       */
333  FT_LOCAL_DEF( FT_Error )
334  tt_face_load_fpgm( TT_Face    face,
335                     FT_Stream  stream )
336  {
337#ifdef TT_USE_BYTECODE_INTERPRETER
338
339    FT_Error  error;
340    FT_ULong  table_len;
341
342
343    FT_TRACE2(( "Font program " ));
344
345    /* The font program is optional */
346    error = face->goto_table( face, TTAG_fpgm, stream, &table_len );
347    if ( error )
348    {
349      face->font_program      = NULL;
350      face->font_program_size = 0;
351      error                   = TT_Err_Ok;
352
353      FT_TRACE2(( "is missing\n" ));
354    }
355    else
356    {
357      face->font_program_size = table_len;
358      if ( FT_FRAME_EXTRACT( table_len, face->font_program ) )
359        goto Exit;
360
361      FT_TRACE2(( "loaded, %12d bytes\n", face->font_program_size ));
362    }
363
364  Exit:
365    return error;
366
367#else /* !TT_USE_BYTECODE_INTERPRETER */
368
369    FT_UNUSED( face   );
370    FT_UNUSED( stream );
371
372    return TT_Err_Ok;
373
374#endif
375  }
376
377
378  /*************************************************************************/
379  /*                                                                       */
380  /* <Function>                                                            */
381  /*    tt_face_load_prep                                                  */
382  /*                                                                       */
383  /* <Description>                                                         */
384  /*    Load the cvt program.                                              */
385  /*                                                                       */
386  /* <InOut>                                                               */
387  /*    face   :: A handle to the target face object.                      */
388  /*                                                                       */
389  /* <Input>                                                               */
390  /*    stream :: A handle to the input stream.                            */
391  /*                                                                       */
392  /* <Return>                                                              */
393  /*    FreeType error code.  0 means success.                             */
394  /*                                                                       */
395  FT_LOCAL_DEF( FT_Error )
396  tt_face_load_prep( TT_Face    face,
397                     FT_Stream  stream )
398  {
399#ifdef TT_USE_BYTECODE_INTERPRETER
400
401    FT_Error  error;
402    FT_ULong  table_len;
403
404
405    FT_TRACE2(( "Prep program " ));
406
407    error = face->goto_table( face, TTAG_prep, stream, &table_len );
408    if ( error )
409    {
410      face->cvt_program      = NULL;
411      face->cvt_program_size = 0;
412      error                  = TT_Err_Ok;
413
414      FT_TRACE2(( "is missing\n" ));
415    }
416    else
417    {
418      face->cvt_program_size = table_len;
419      if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) )
420        goto Exit;
421
422      FT_TRACE2(( "loaded, %12d bytes\n", face->cvt_program_size ));
423    }
424
425  Exit:
426    return error;
427
428#else /* !TT_USE_BYTECODE_INTERPRETER */
429
430    FT_UNUSED( face   );
431    FT_UNUSED( stream );
432
433    return TT_Err_Ok;
434
435#endif
436  }
437
438
439  /*************************************************************************/
440  /*                                                                       */
441  /* <Function>                                                            */
442  /*    tt_face_load_hdmx                                                  */
443  /*                                                                       */
444  /* <Description>                                                         */
445  /*    Load the `hdmx' table into the face object.                        */
446  /*                                                                       */
447  /* <Input>                                                               */
448  /*    face   :: A handle to the target face object.                      */
449  /*                                                                       */
450  /*    stream :: A handle to the input stream.                            */
451  /*                                                                       */
452  /* <Return>                                                              */
453  /*    FreeType error code.  0 means success.                             */
454  /*                                                                       */
455
456  FT_LOCAL_DEF( FT_Error )
457  tt_face_load_hdmx( TT_Face    face,
458                     FT_Stream  stream )
459  {
460    FT_Error   error;
461    FT_Memory  memory = stream->memory;
462    FT_UInt    version, nn, num_records;
463    FT_ULong   table_size, record_size;
464    FT_Byte*   p;
465    FT_Byte*   limit;
466
467
468    /* this table is optional */
469    error = face->goto_table( face, TTAG_hdmx, stream, &table_size );
470    if ( error || table_size < 8 )
471      return TT_Err_Ok;
472
473    if ( FT_FRAME_EXTRACT( table_size, face->hdmx_table ) )
474      goto Exit;
475
476    p     = face->hdmx_table;
477    limit = p + table_size;
478
479    version     = FT_NEXT_USHORT( p );
480    num_records = FT_NEXT_USHORT( p );
481    record_size = FT_NEXT_ULONG( p );
482
483    /* The maximum number of bytes in an hdmx device record is the */
484    /* maximum number of glyphs + 2; this is 0xFFFF + 2; this is   */
485    /* the reason why `record_size' is a long (which we read as    */
486    /* unsigned long for convenience).  In practice, two bytes     */
487    /* sufficient to hold the size value.                          */
488    /*                                                             */
489    /* There are at least two fonts, HANNOM-A and HANNOM-B version */
490    /* 2.0 (2005), which get this wrong: The upper two bytes of    */
491    /* the size value are set to 0xFF instead of 0x00.  We catch   */
492    /* and fix this.                                               */
493
494    if ( record_size >= 0xFFFF0000UL )
495      record_size &= 0xFFFFU;
496
497    /* The limit for `num_records' is a heuristic value. */
498
499    if ( version != 0 || num_records > 255 || record_size > 0x10001L )
500    {
501      error = TT_Err_Invalid_File_Format;
502      goto Fail;
503    }
504
505    if ( FT_NEW_ARRAY( face->hdmx_record_sizes, num_records ) )
506      goto Fail;
507
508    for ( nn = 0; nn < num_records; nn++ )
509    {
510      if ( p + record_size > limit )
511        break;
512
513      face->hdmx_record_sizes[nn] = p[0];
514      p                          += record_size;
515    }
516
517    face->hdmx_record_count = nn;
518    face->hdmx_table_size   = table_size;
519    face->hdmx_record_size  = record_size;
520
521  Exit:
522    return error;
523
524  Fail:
525    FT_FRAME_RELEASE( face->hdmx_table );
526    face->hdmx_table_size = 0;
527    goto Exit;
528  }
529
530
531  FT_LOCAL_DEF( void )
532  tt_face_free_hdmx( TT_Face  face )
533  {
534    FT_Stream  stream = face->root.stream;
535    FT_Memory  memory = stream->memory;
536
537
538    FT_FREE( face->hdmx_record_sizes );
539    FT_FRAME_RELEASE( face->hdmx_table );
540  }
541
542
543  /*************************************************************************/
544  /*                                                                       */
545  /* Return the advance width table for a given pixel size if it is found  */
546  /* in the font's `hdmx' table (if any).                                  */
547  /*                                                                       */
548  FT_LOCAL_DEF( FT_Byte* )
549  tt_face_get_device_metrics( TT_Face  face,
550                              FT_UInt  ppem,
551                              FT_UInt  gindex )
552  {
553    FT_UInt   nn;
554    FT_Byte*  result      = NULL;
555    FT_ULong  record_size = face->hdmx_record_size;
556    FT_Byte*  record      = face->hdmx_table + 8;
557
558
559    for ( nn = 0; nn < face->hdmx_record_count; nn++ )
560      if ( face->hdmx_record_sizes[nn] == ppem )
561      {
562        gindex += 2;
563        if ( gindex < record_size )
564          result = record + nn * record_size + gindex;
565        break;
566      }
567
568    return result;
569  }
570
571
572/* END */
573