misc/libfreetype/src/sfnt/ttmtx.c
changeset 9372 915436ff64ab
parent 9371 f3840de881bd
child 9373 b769a8e38cbd
equal deleted inserted replaced
9371:f3840de881bd 9372:915436ff64ab
     1 /***************************************************************************/
       
     2 /*                                                                         */
       
     3 /*  ttmtx.c                                                                */
       
     4 /*                                                                         */
       
     5 /*    Load the metrics tables common to TTF and OTF fonts (body).          */
       
     6 /*                                                                         */
       
     7 /*  Copyright 2006-2009, 2011 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_STREAM_H
       
    22 #include FT_TRUETYPE_TAGS_H
       
    23 #include "ttmtx.h"
       
    24 
       
    25 #include "sferrors.h"
       
    26 
       
    27 
       
    28   /*************************************************************************/
       
    29   /*                                                                       */
       
    30   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
       
    31   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
       
    32   /* messages during execution.                                            */
       
    33   /*                                                                       */
       
    34 #undef  FT_COMPONENT
       
    35 #define FT_COMPONENT  trace_ttmtx
       
    36 
       
    37 
       
    38   /*
       
    39    *  Unfortunately, we can't enable our memory optimizations if
       
    40    *  FT_CONFIG_OPTION_OLD_INTERNALS is defined.  This is because at least
       
    41    *  one rogue client (libXfont in the X.Org XServer) is directly accessing
       
    42    *  the metrics.
       
    43    */
       
    44 
       
    45   /*************************************************************************/
       
    46   /*                                                                       */
       
    47   /* <Function>                                                            */
       
    48   /*    tt_face_load_hmtx                                                  */
       
    49   /*                                                                       */
       
    50   /* <Description>                                                         */
       
    51   /*    Load the `hmtx' or `vmtx' table into a face object.                */
       
    52   /*                                                                       */
       
    53   /* <Input>                                                               */
       
    54   /*    face     :: A handle to the target face object.                    */
       
    55   /*                                                                       */
       
    56   /*    stream   :: The input stream.                                      */
       
    57   /*                                                                       */
       
    58   /*    vertical :: A boolean flag.  If set, load `vmtx'.                  */
       
    59   /*                                                                       */
       
    60   /* <Return>                                                              */
       
    61   /*    FreeType error code.  0 means success.                             */
       
    62   /*                                                                       */
       
    63 #ifndef FT_CONFIG_OPTION_OLD_INTERNALS
       
    64 
       
    65   FT_LOCAL_DEF( FT_Error )
       
    66   tt_face_load_hmtx( TT_Face    face,
       
    67                      FT_Stream  stream,
       
    68                      FT_Bool    vertical )
       
    69   {
       
    70     FT_Error   error;
       
    71     FT_ULong   tag, table_size;
       
    72     FT_ULong*  ptable_offset;
       
    73     FT_ULong*  ptable_size;
       
    74 
       
    75 
       
    76     if ( vertical )
       
    77     {
       
    78       tag           = TTAG_vmtx;
       
    79       ptable_offset = &face->vert_metrics_offset;
       
    80       ptable_size   = &face->vert_metrics_size;
       
    81     }
       
    82     else
       
    83     {
       
    84       tag           = TTAG_hmtx;
       
    85       ptable_offset = &face->horz_metrics_offset;
       
    86       ptable_size   = &face->horz_metrics_size;
       
    87     }
       
    88 
       
    89     error = face->goto_table( face, tag, stream, &table_size );
       
    90     if ( error )
       
    91       goto Fail;
       
    92 
       
    93     *ptable_size   = table_size;
       
    94     *ptable_offset = FT_STREAM_POS();
       
    95 
       
    96   Fail:
       
    97     return error;
       
    98   }
       
    99 
       
   100 #else /* !FT_CONFIG_OPTION_OLD_INTERNALS */
       
   101 
       
   102   FT_LOCAL_DEF( FT_Error )
       
   103   tt_face_load_hmtx( TT_Face    face,
       
   104                      FT_Stream  stream,
       
   105                      FT_Bool    vertical )
       
   106   {
       
   107     FT_Error   error;
       
   108     FT_Memory  memory = stream->memory;
       
   109 
       
   110     FT_ULong   table_len;
       
   111     FT_Long    num_shorts, num_longs, num_shorts_checked;
       
   112 
       
   113     TT_LongMetrics*    longs;
       
   114     TT_ShortMetrics**  shorts;
       
   115     FT_Byte*           p;
       
   116 
       
   117 
       
   118     if ( vertical )
       
   119     {
       
   120       void*   lm = &face->vertical.long_metrics;
       
   121       void**  sm = &face->vertical.short_metrics;
       
   122 
       
   123 
       
   124       error = face->goto_table( face, TTAG_vmtx, stream, &table_len );
       
   125       if ( error )
       
   126         goto Fail;
       
   127 
       
   128       num_longs = face->vertical.number_Of_VMetrics;
       
   129       if ( (FT_ULong)num_longs > table_len / 4 )
       
   130         num_longs = (FT_Long)( table_len / 4 );
       
   131 
       
   132       face->vertical.number_Of_VMetrics = 0;
       
   133 
       
   134       longs  = (TT_LongMetrics*)lm;
       
   135       shorts = (TT_ShortMetrics**)sm;
       
   136     }
       
   137     else
       
   138     {
       
   139       void*   lm = &face->horizontal.long_metrics;
       
   140       void**  sm = &face->horizontal.short_metrics;
       
   141 
       
   142 
       
   143       error = face->goto_table( face, TTAG_hmtx, stream, &table_len );
       
   144       if ( error )
       
   145         goto Fail;
       
   146 
       
   147       num_longs = face->horizontal.number_Of_HMetrics;
       
   148       if ( (FT_ULong)num_longs > table_len / 4 )
       
   149         num_longs = (FT_Long)( table_len / 4 );
       
   150 
       
   151       face->horizontal.number_Of_HMetrics = 0;
       
   152 
       
   153       longs  = (TT_LongMetrics*)lm;
       
   154       shorts = (TT_ShortMetrics**)sm;
       
   155     }
       
   156 
       
   157     /* never trust derived values */
       
   158 
       
   159     num_shorts         = face->max_profile.numGlyphs - num_longs;
       
   160     num_shorts_checked = ( table_len - num_longs * 4L ) / 2;
       
   161 
       
   162     if ( num_shorts < 0 )
       
   163     {
       
   164       FT_TRACE0(( "tt_face_load_hmtx:"
       
   165                   " %cmtx has more metrics than glyphs.\n",
       
   166                   vertical ? 'v' : 'h' ));
       
   167 
       
   168       /* Adobe simply ignores this problem.  So we shall do the same. */
       
   169 #if 0
       
   170       error = vertical ? SFNT_Err_Invalid_Vert_Metrics
       
   171                        : SFNT_Err_Invalid_Horiz_Metrics;
       
   172       goto Exit;
       
   173 #else
       
   174       num_shorts = 0;
       
   175 #endif
       
   176     }
       
   177 
       
   178     if ( FT_QNEW_ARRAY( *longs,  num_longs  ) ||
       
   179          FT_QNEW_ARRAY( *shorts, num_shorts ) )
       
   180       goto Fail;
       
   181 
       
   182     if ( FT_FRAME_ENTER( table_len ) )
       
   183       goto Fail;
       
   184 
       
   185     p = stream->cursor;
       
   186 
       
   187     {
       
   188       TT_LongMetrics  cur   = *longs;
       
   189       TT_LongMetrics  limit = cur + num_longs;
       
   190 
       
   191 
       
   192       for ( ; cur < limit; cur++ )
       
   193       {
       
   194         cur->advance = FT_NEXT_USHORT( p );
       
   195         cur->bearing = FT_NEXT_SHORT( p );
       
   196       }
       
   197     }
       
   198 
       
   199     /* do we have an inconsistent number of metric values? */
       
   200     {
       
   201       TT_ShortMetrics*  cur   = *shorts;
       
   202       TT_ShortMetrics*  limit = cur +
       
   203                                 FT_MIN( num_shorts, num_shorts_checked );
       
   204 
       
   205 
       
   206       for ( ; cur < limit; cur++ )
       
   207         *cur = FT_NEXT_SHORT( p );
       
   208 
       
   209       /* We fill up the missing left side bearings with the     */
       
   210       /* last valid value.  Since this will occur for buggy CJK */
       
   211       /* fonts usually only, nothing serious will happen.       */
       
   212       if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 )
       
   213       {
       
   214         FT_Short  val = (*shorts)[num_shorts_checked - 1];
       
   215 
       
   216 
       
   217         limit = *shorts + num_shorts;
       
   218         for ( ; cur < limit; cur++ )
       
   219           *cur = val;
       
   220       }
       
   221     }
       
   222 
       
   223     FT_FRAME_EXIT();
       
   224 
       
   225     if ( vertical )
       
   226       face->vertical.number_Of_VMetrics = (FT_UShort)num_longs;
       
   227     else
       
   228       face->horizontal.number_Of_HMetrics = (FT_UShort)num_longs;
       
   229 
       
   230   Fail:
       
   231     return error;
       
   232   }
       
   233 
       
   234 #endif /* !FT_CONFIG_OPTION_OLD_INTERNALS */
       
   235 
       
   236 
       
   237   /*************************************************************************/
       
   238   /*                                                                       */
       
   239   /* <Function>                                                            */
       
   240   /*    tt_face_load_hhea                                                  */
       
   241   /*                                                                       */
       
   242   /* <Description>                                                         */
       
   243   /*    Load the `hhea' or 'vhea' table into a face object.                */
       
   244   /*                                                                       */
       
   245   /* <Input>                                                               */
       
   246   /*    face     :: A handle to the target face object.                    */
       
   247   /*                                                                       */
       
   248   /*    stream   :: The input stream.                                      */
       
   249   /*                                                                       */
       
   250   /*    vertical :: A boolean flag.  If set, load `vhea'.                  */
       
   251   /*                                                                       */
       
   252   /* <Return>                                                              */
       
   253   /*    FreeType error code.  0 means success.                             */
       
   254   /*                                                                       */
       
   255   FT_LOCAL_DEF( FT_Error )
       
   256   tt_face_load_hhea( TT_Face    face,
       
   257                      FT_Stream  stream,
       
   258                      FT_Bool    vertical )
       
   259   {
       
   260     FT_Error        error;
       
   261     TT_HoriHeader*  header;
       
   262 
       
   263     const FT_Frame_Field  metrics_header_fields[] =
       
   264     {
       
   265 #undef  FT_STRUCTURE
       
   266 #define FT_STRUCTURE  TT_HoriHeader
       
   267 
       
   268       FT_FRAME_START( 36 ),
       
   269         FT_FRAME_ULONG ( Version ),
       
   270         FT_FRAME_SHORT ( Ascender ),
       
   271         FT_FRAME_SHORT ( Descender ),
       
   272         FT_FRAME_SHORT ( Line_Gap ),
       
   273         FT_FRAME_USHORT( advance_Width_Max ),
       
   274         FT_FRAME_SHORT ( min_Left_Side_Bearing ),
       
   275         FT_FRAME_SHORT ( min_Right_Side_Bearing ),
       
   276         FT_FRAME_SHORT ( xMax_Extent ),
       
   277         FT_FRAME_SHORT ( caret_Slope_Rise ),
       
   278         FT_FRAME_SHORT ( caret_Slope_Run ),
       
   279         FT_FRAME_SHORT ( caret_Offset ),
       
   280         FT_FRAME_SHORT ( Reserved[0] ),
       
   281         FT_FRAME_SHORT ( Reserved[1] ),
       
   282         FT_FRAME_SHORT ( Reserved[2] ),
       
   283         FT_FRAME_SHORT ( Reserved[3] ),
       
   284         FT_FRAME_SHORT ( metric_Data_Format ),
       
   285         FT_FRAME_USHORT( number_Of_HMetrics ),
       
   286       FT_FRAME_END
       
   287     };
       
   288 
       
   289 
       
   290     if ( vertical )
       
   291     {
       
   292       void  *v = &face->vertical;
       
   293 
       
   294 
       
   295       error = face->goto_table( face, TTAG_vhea, stream, 0 );
       
   296       if ( error )
       
   297         goto Fail;
       
   298 
       
   299       header = (TT_HoriHeader*)v;
       
   300     }
       
   301     else
       
   302     {
       
   303       error = face->goto_table( face, TTAG_hhea, stream, 0 );
       
   304       if ( error )
       
   305         goto Fail;
       
   306 
       
   307       header = &face->horizontal;
       
   308     }
       
   309 
       
   310     if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) )
       
   311       goto Fail;
       
   312 
       
   313     FT_TRACE3(( "Ascender:          %5d\n", header->Ascender ));
       
   314     FT_TRACE3(( "Descender:         %5d\n", header->Descender ));
       
   315     FT_TRACE3(( "number_Of_Metrics: %5u\n", header->number_Of_HMetrics ));
       
   316 
       
   317     header->long_metrics  = NULL;
       
   318     header->short_metrics = NULL;
       
   319 
       
   320   Fail:
       
   321     return error;
       
   322   }
       
   323 
       
   324 
       
   325   /*************************************************************************/
       
   326   /*                                                                       */
       
   327   /* <Function>                                                            */
       
   328   /*    tt_face_get_metrics                                                */
       
   329   /*                                                                       */
       
   330   /* <Description>                                                         */
       
   331   /*    Returns the horizontal or vertical metrics in font units for a     */
       
   332   /*    given glyph.  The metrics are the left side bearing (resp. top     */
       
   333   /*    side bearing) and advance width (resp. advance height).            */
       
   334   /*                                                                       */
       
   335   /* <Input>                                                               */
       
   336   /*    header  :: A pointer to either the horizontal or vertical metrics  */
       
   337   /*               structure.                                              */
       
   338   /*                                                                       */
       
   339   /*    idx     :: The glyph index.                                        */
       
   340   /*                                                                       */
       
   341   /* <Output>                                                              */
       
   342   /*    bearing :: The bearing, either left side or top side.              */
       
   343   /*                                                                       */
       
   344   /*    advance :: The advance width resp. advance height.                 */
       
   345   /*                                                                       */
       
   346 #ifndef FT_CONFIG_OPTION_OLD_INTERNALS
       
   347 
       
   348   FT_LOCAL_DEF( FT_Error )
       
   349   tt_face_get_metrics( TT_Face     face,
       
   350                        FT_Bool     vertical,
       
   351                        FT_UInt     gindex,
       
   352                        FT_Short   *abearing,
       
   353                        FT_UShort  *aadvance )
       
   354   {
       
   355     FT_Error        error;
       
   356     FT_Stream       stream = face->root.stream;
       
   357     TT_HoriHeader*  header;
       
   358     FT_ULong        table_pos, table_size, table_end;
       
   359     FT_UShort       k;
       
   360 
       
   361 
       
   362     if ( vertical )
       
   363     {
       
   364       void*  v = &face->vertical;
       
   365 
       
   366 
       
   367       header     = (TT_HoriHeader*)v;
       
   368       table_pos  = face->vert_metrics_offset;
       
   369       table_size = face->vert_metrics_size;
       
   370     }
       
   371     else
       
   372     {
       
   373       header     = &face->horizontal;
       
   374       table_pos  = face->horz_metrics_offset;
       
   375       table_size = face->horz_metrics_size;
       
   376     }
       
   377 
       
   378     table_end = table_pos + table_size;
       
   379 
       
   380     k = header->number_Of_HMetrics;
       
   381 
       
   382     if ( k > 0 )
       
   383     {
       
   384       if ( gindex < (FT_UInt)k )
       
   385       {
       
   386         table_pos += 4 * gindex;
       
   387         if ( table_pos + 4 > table_end )
       
   388           goto NoData;
       
   389 
       
   390         if ( FT_STREAM_SEEK( table_pos ) ||
       
   391              FT_READ_USHORT( *aadvance ) ||
       
   392              FT_READ_SHORT( *abearing )  )
       
   393           goto NoData;
       
   394       }
       
   395       else
       
   396       {
       
   397         table_pos += 4 * ( k - 1 );
       
   398         if ( table_pos + 4 > table_end )
       
   399           goto NoData;
       
   400 
       
   401         if ( FT_STREAM_SEEK( table_pos ) ||
       
   402              FT_READ_USHORT( *aadvance ) )
       
   403           goto NoData;
       
   404 
       
   405         table_pos += 4 + 2 * ( gindex - k );
       
   406         if ( table_pos + 2 > table_end )
       
   407           *abearing = 0;
       
   408         else
       
   409         {
       
   410           if ( !FT_STREAM_SEEK( table_pos ) )
       
   411             (void)FT_READ_SHORT( *abearing );
       
   412         }
       
   413       }
       
   414     }
       
   415     else
       
   416     {
       
   417     NoData:
       
   418       *abearing = 0;
       
   419       *aadvance = 0;
       
   420     }
       
   421 
       
   422     return SFNT_Err_Ok;
       
   423   }
       
   424 
       
   425 #else /* !FT_CONFIG_OPTION_OLD_INTERNALS */
       
   426 
       
   427   FT_LOCAL_DEF( FT_Error )
       
   428   tt_face_get_metrics( TT_Face     face,
       
   429                        FT_Bool     vertical,
       
   430                        FT_UInt     gindex,
       
   431                        FT_Short*   abearing,
       
   432                        FT_UShort*  aadvance )
       
   433   {
       
   434     void*           v = &face->vertical;
       
   435     void*           h = &face->horizontal;
       
   436     TT_HoriHeader*  header = vertical ? (TT_HoriHeader*)v
       
   437                                       : (TT_HoriHeader*)h;
       
   438     TT_LongMetrics  longs_m;
       
   439     FT_UShort       k = header->number_Of_HMetrics;
       
   440 
       
   441 
       
   442     if ( k == 0                                         ||
       
   443          !header->long_metrics                          ||
       
   444          gindex >= (FT_UInt)face->max_profile.numGlyphs )
       
   445     {
       
   446       *abearing = *aadvance = 0;
       
   447       return SFNT_Err_Ok;
       
   448     }
       
   449 
       
   450     if ( gindex < (FT_UInt)k )
       
   451     {
       
   452       longs_m   = (TT_LongMetrics)header->long_metrics + gindex;
       
   453       *abearing = longs_m->bearing;
       
   454       *aadvance = longs_m->advance;
       
   455     }
       
   456     else
       
   457     {
       
   458       *abearing = ((TT_ShortMetrics*)header->short_metrics)[gindex - k];
       
   459       *aadvance = ((TT_LongMetrics)header->long_metrics)[k - 1].advance;
       
   460     }
       
   461 
       
   462     return SFNT_Err_Ok;
       
   463   }
       
   464 
       
   465 #endif /* !FT_CONFIG_OPTION_OLD_INTERNALS */
       
   466 
       
   467 
       
   468 /* END */