1/***************************************************************************/
2/*                                                                         */
3/*  ttpload.c                                                              */
4/*                                                                         */
5/*    TrueType-specific tables loader (body).                              */
6/*                                                                         */
7/*  Copyright 1996-2002, 2004-2013 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 ( FT_ERR_EQ( error, 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 = FT_THROW( 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 = FT_THROW( 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 = FT_THROW( 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 + 1 )
114    {
115      FT_TRACE2(( "glyph count mismatch!  loca: %d, maxp: %d\n",
116                  face->num_locations - 1, 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 =
122                    ( (FT_Long)( face->root.num_glyphs ) + 1 ) << shift;
123
124        TT_Table  entry = face->dir_tables;
125        TT_Table  limit = entry + face->num_tables;
126
127        FT_Long   pos  = FT_Stream_Pos( stream );
128        FT_Long   dist = 0x7FFFFFFFL;
129
130
131        /* compute the distance to next table in font file */
132        for ( ; entry < limit; entry++ )
133        {
134          FT_Long  diff = entry->Offset - pos;
135
136
137          if ( diff > 0 && diff < dist )
138            dist = diff;
139        }
140
141        if ( entry == limit )
142        {
143          /* `loca' is the last table */
144          dist = stream->size - pos;
145        }
146
147        if ( new_loca_len <= dist )
148        {
149          face->num_locations = face->root.num_glyphs + 1;
150          table_len           = new_loca_len;
151
152          FT_TRACE2(( "adjusting num_locations to %d\n",
153                      face->num_locations ));
154        }
155      }
156    }
157
158    /*
159     * Extract the frame.  We don't need to decompress it since
160     * we are able to parse it directly.
161     */
162    if ( FT_FRAME_EXTRACT( table_len, face->glyph_locations ) )
163      goto Exit;
164
165    FT_TRACE2(( "loaded\n" ));
166
167  Exit:
168    return error;
169  }
170
171
172  FT_LOCAL_DEF( FT_ULong )
173  tt_face_get_location( TT_Face   face,
174                        FT_UInt   gindex,
175                        FT_UInt  *asize )
176  {
177    FT_ULong  pos1, pos2;
178    FT_Byte*  p;
179    FT_Byte*  p_limit;
180
181
182    pos1 = pos2 = 0;
183
184    if ( gindex < face->num_locations )
185    {
186      if ( face->header.Index_To_Loc_Format != 0 )
187      {
188        p       = face->glyph_locations + gindex * 4;
189        p_limit = face->glyph_locations + face->num_locations * 4;
190
191        pos1 = FT_NEXT_ULONG( p );
192        pos2 = pos1;
193
194        if ( p + 4 <= p_limit )
195          pos2 = FT_NEXT_ULONG( p );
196      }
197      else
198      {
199        p       = face->glyph_locations + gindex * 2;
200        p_limit = face->glyph_locations + face->num_locations * 2;
201
202        pos1 = FT_NEXT_USHORT( p );
203        pos2 = pos1;
204
205        if ( p + 2 <= p_limit )
206          pos2 = FT_NEXT_USHORT( p );
207
208        pos1 <<= 1;
209        pos2 <<= 1;
210      }
211    }
212
213    /* Check broken location data */
214    if ( pos1 > face->glyf_len )
215    {
216      FT_TRACE1(( "tt_face_get_location:"
217                  " too large offset=0x%08lx found for gid=0x%04lx,"
218                  " exceeding the end of glyf table (0x%08lx)\n",
219                  pos1, gindex, face->glyf_len ));
220      *asize = 0;
221      return 0;
222    }
223
224    if ( pos2 > face->glyf_len )
225    {
226      FT_TRACE1(( "tt_face_get_location:"
227                  " too large offset=0x%08lx found for gid=0x%04lx,"
228                  " truncate at the end of glyf table (0x%08lx)\n",
229                  pos2, gindex + 1, face->glyf_len ));
230      pos2 = face->glyf_len;
231    }
232
233    /* The `loca' table must be ordered; it refers to the length of */
234    /* an entry as the difference between the current and the next  */
235    /* position.  However, there do exist (malformed) fonts which   */
236    /* don't obey this rule, so we are only able to provide an      */
237    /* upper bound for the size.                                    */
238    /*                                                              */
239    /* We get (intentionally) a wrong, non-zero result in case the  */
240    /* `glyf' table is missing.                                     */
241    if ( pos2 >= pos1 )
242      *asize = (FT_UInt)( pos2 - pos1 );
243    else
244      *asize = (FT_UInt)( face->glyf_len - pos1 );
245
246    return pos1;
247  }
248
249
250  FT_LOCAL_DEF( void )
251  tt_face_done_loca( TT_Face  face )
252  {
253    FT_Stream  stream = face->root.stream;
254
255
256    FT_FRAME_RELEASE( face->glyph_locations );
257    face->num_locations = 0;
258  }
259
260
261
262  /*************************************************************************/
263  /*                                                                       */
264  /* <Function>                                                            */
265  /*    tt_face_load_cvt                                                   */
266  /*                                                                       */
267  /* <Description>                                                         */
268  /*    Load the control value table into a face object.                   */
269  /*                                                                       */
270  /* <InOut>                                                               */
271  /*    face   :: A handle to the target face object.                      */
272  /*                                                                       */
273  /* <Input>                                                               */
274  /*    stream :: A handle to the input stream.                            */
275  /*                                                                       */
276  /* <Return>                                                              */
277  /*    FreeType error code.  0 means success.                             */
278  /*                                                                       */
279  FT_LOCAL_DEF( FT_Error )
280  tt_face_load_cvt( TT_Face    face,
281                    FT_Stream  stream )
282  {
283#ifdef TT_USE_BYTECODE_INTERPRETER
284
285    FT_Error   error;
286    FT_Memory  memory = stream->memory;
287    FT_ULong   table_len;
288
289
290    FT_TRACE2(( "CVT " ));
291
292    error = face->goto_table( face, TTAG_cvt, stream, &table_len );
293    if ( error )
294    {
295      FT_TRACE2(( "is missing\n" ));
296
297      face->cvt_size = 0;
298      face->cvt      = NULL;
299      error          = FT_Err_Ok;
300
301      goto Exit;
302    }
303
304    face->cvt_size = table_len / 2;
305
306    if ( FT_NEW_ARRAY( face->cvt, face->cvt_size ) )
307      goto Exit;
308
309    if ( FT_FRAME_ENTER( face->cvt_size * 2L ) )
310      goto Exit;
311
312    {
313      FT_Short*  cur   = face->cvt;
314      FT_Short*  limit = cur + face->cvt_size;
315
316
317      for ( ; cur < limit; cur++ )
318        *cur = FT_GET_SHORT();
319    }
320
321    FT_FRAME_EXIT();
322    FT_TRACE2(( "loaded\n" ));
323
324#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
325    if ( face->doblend )
326      error = tt_face_vary_cvt( face, stream );
327#endif
328
329  Exit:
330    return error;
331
332#else /* !TT_USE_BYTECODE_INTERPRETER */
333
334    FT_UNUSED( face   );
335    FT_UNUSED( stream );
336
337    return FT_Err_Ok;
338
339#endif
340  }
341
342
343  /*************************************************************************/
344  /*                                                                       */
345  /* <Function>                                                            */
346  /*    tt_face_load_fpgm                                                  */
347  /*                                                                       */
348  /* <Description>                                                         */
349  /*    Load the font program.                                             */
350  /*                                                                       */
351  /* <InOut>                                                               */
352  /*    face   :: A handle to the target face object.                      */
353  /*                                                                       */
354  /* <Input>                                                               */
355  /*    stream :: A handle to the input stream.                            */
356  /*                                                                       */
357  /* <Return>                                                              */
358  /*    FreeType error code.  0 means success.                             */
359  /*                                                                       */
360  FT_LOCAL_DEF( FT_Error )
361  tt_face_load_fpgm( TT_Face    face,
362                     FT_Stream  stream )
363  {
364#ifdef TT_USE_BYTECODE_INTERPRETER
365
366    FT_Error  error;
367    FT_ULong  table_len;
368
369
370    FT_TRACE2(( "Font program " ));
371
372    /* The font program is optional */
373    error = face->goto_table( face, TTAG_fpgm, stream, &table_len );
374    if ( error )
375    {
376      face->font_program      = NULL;
377      face->font_program_size = 0;
378      error                   = FT_Err_Ok;
379
380      FT_TRACE2(( "is missing\n" ));
381    }
382    else
383    {
384      face->font_program_size = table_len;
385      if ( FT_FRAME_EXTRACT( table_len, face->font_program ) )
386        goto Exit;
387
388      FT_TRACE2(( "loaded, %12d bytes\n", face->font_program_size ));
389    }
390
391  Exit:
392    return error;
393
394#else /* !TT_USE_BYTECODE_INTERPRETER */
395
396    FT_UNUSED( face   );
397    FT_UNUSED( stream );
398
399    return FT_Err_Ok;
400
401#endif
402  }
403
404
405  /*************************************************************************/
406  /*                                                                       */
407  /* <Function>                                                            */
408  /*    tt_face_load_prep                                                  */
409  /*                                                                       */
410  /* <Description>                                                         */
411  /*    Load the cvt program.                                              */
412  /*                                                                       */
413  /* <InOut>                                                               */
414  /*    face   :: A handle to the target face object.                      */
415  /*                                                                       */
416  /* <Input>                                                               */
417  /*    stream :: A handle to the input stream.                            */
418  /*                                                                       */
419  /* <Return>                                                              */
420  /*    FreeType error code.  0 means success.                             */
421  /*                                                                       */
422  FT_LOCAL_DEF( FT_Error )
423  tt_face_load_prep( TT_Face    face,
424                     FT_Stream  stream )
425  {
426#ifdef TT_USE_BYTECODE_INTERPRETER
427
428    FT_Error  error;
429    FT_ULong  table_len;
430
431
432    FT_TRACE2(( "Prep program " ));
433
434    error = face->goto_table( face, TTAG_prep, stream, &table_len );
435    if ( error )
436    {
437      face->cvt_program      = NULL;
438      face->cvt_program_size = 0;
439      error                  = FT_Err_Ok;
440
441      FT_TRACE2(( "is missing\n" ));
442    }
443    else
444    {
445      face->cvt_program_size = table_len;
446      if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) )
447        goto Exit;
448
449      FT_TRACE2(( "loaded, %12d bytes\n", face->cvt_program_size ));
450    }
451
452  Exit:
453    return error;
454
455#else /* !TT_USE_BYTECODE_INTERPRETER */
456
457    FT_UNUSED( face   );
458    FT_UNUSED( stream );
459
460    return FT_Err_Ok;
461
462#endif
463  }
464
465
466  /*************************************************************************/
467  /*                                                                       */
468  /* <Function>                                                            */
469  /*    tt_face_load_hdmx                                                  */
470  /*                                                                       */
471  /* <Description>                                                         */
472  /*    Load the `hdmx' table into the face object.                        */
473  /*                                                                       */
474  /* <Input>                                                               */
475  /*    face   :: A handle to the target face object.                      */
476  /*                                                                       */
477  /*    stream :: A handle to the input stream.                            */
478  /*                                                                       */
479  /* <Return>                                                              */
480  /*    FreeType error code.  0 means success.                             */
481  /*                                                                       */
482
483  FT_LOCAL_DEF( FT_Error )
484  tt_face_load_hdmx( TT_Face    face,
485                     FT_Stream  stream )
486  {
487    FT_Error   error;
488    FT_Memory  memory = stream->memory;
489    FT_UInt    version, nn, num_records;
490    FT_ULong   table_size, record_size;
491    FT_Byte*   p;
492    FT_Byte*   limit;
493
494
495    /* this table is optional */
496    error = face->goto_table( face, TTAG_hdmx, stream, &table_size );
497    if ( error || table_size < 8 )
498      return FT_Err_Ok;
499
500    if ( FT_FRAME_EXTRACT( table_size, face->hdmx_table ) )
501      goto Exit;
502
503    p     = face->hdmx_table;
504    limit = p + table_size;
505
506    version     = FT_NEXT_USHORT( p );
507    num_records = FT_NEXT_USHORT( p );
508    record_size = FT_NEXT_ULONG( p );
509
510    /* The maximum number of bytes in an hdmx device record is the */
511    /* maximum number of glyphs + 2; this is 0xFFFF + 2; this is   */
512    /* the reason why `record_size' is a long (which we read as    */
513    /* unsigned long for convenience).  In practice, two bytes     */
514    /* sufficient to hold the size value.                          */
515    /*                                                             */
516    /* There are at least two fonts, HANNOM-A and HANNOM-B version */
517    /* 2.0 (2005), which get this wrong: The upper two bytes of    */
518    /* the size value are set to 0xFF instead of 0x00.  We catch   */
519    /* and fix this.                                               */
520
521    if ( record_size >= 0xFFFF0000UL )
522      record_size &= 0xFFFFU;
523
524    /* The limit for `num_records' is a heuristic value. */
525
526    if ( version != 0 || num_records > 255 || record_size > 0x10001L )
527    {
528      error = FT_THROW( Invalid_File_Format );
529      goto Fail;
530    }
531
532    if ( FT_NEW_ARRAY( face->hdmx_record_sizes, num_records ) )
533      goto Fail;
534
535    for ( nn = 0; nn < num_records; nn++ )
536    {
537      if ( p + record_size > limit )
538        break;
539
540      face->hdmx_record_sizes[nn] = p[0];
541      p                          += record_size;
542    }
543
544    face->hdmx_record_count = nn;
545    face->hdmx_table_size   = table_size;
546    face->hdmx_record_size  = record_size;
547
548  Exit:
549    return error;
550
551  Fail:
552    FT_FRAME_RELEASE( face->hdmx_table );
553    face->hdmx_table_size = 0;
554    goto Exit;
555  }
556
557
558  FT_LOCAL_DEF( void )
559  tt_face_free_hdmx( TT_Face  face )
560  {
561    FT_Stream  stream = face->root.stream;
562    FT_Memory  memory = stream->memory;
563
564
565    FT_FREE( face->hdmx_record_sizes );
566    FT_FRAME_RELEASE( face->hdmx_table );
567  }
568
569
570  /*************************************************************************/
571  /*                                                                       */
572  /* Return the advance width table for a given pixel size if it is found  */
573  /* in the font's `hdmx' table (if any).                                  */
574  /*                                                                       */
575  FT_LOCAL_DEF( FT_Byte* )
576  tt_face_get_device_metrics( TT_Face  face,
577                              FT_UInt  ppem,
578                              FT_UInt  gindex )
579  {
580    FT_UInt   nn;
581    FT_Byte*  result      = NULL;
582    FT_ULong  record_size = face->hdmx_record_size;
583    FT_Byte*  record      = face->hdmx_table + 8;
584
585
586    for ( nn = 0; nn < face->hdmx_record_count; nn++ )
587      if ( face->hdmx_record_sizes[nn] == ppem )
588      {
589        gindex += 2;
590        if ( gindex < record_size )
591          result = record + nn * record_size + gindex;
592        break;
593      }
594
595    return result;
596  }
597
598
599/* END */
600