ttmtx.c

Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  ttmtx.c                                                                */
00004 /*                                                                         */
00005 /*    Load the metrics tables common to TTF and OTF fonts (body).          */
00006 /*                                                                         */
00007 /*  Copyright 2006, 2007, 2008, 2009 by                                    */
00008 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
00009 /*                                                                         */
00010 /*  This file is part of the FreeType project, and may only be used,       */
00011 /*  modified, and distributed under the terms of the FreeType project      */
00012 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00013 /*  this file you indicate that you have read the license and              */
00014 /*  understand and accept it fully.                                        */
00015 /*                                                                         */
00016 /***************************************************************************/
00017 
00018 
00019 #include <ft2build.h>
00020 #include FT_INTERNAL_DEBUG_H
00021 #include FT_INTERNAL_STREAM_H
00022 #include FT_TRUETYPE_TAGS_H
00023 #include "ttmtx.h"
00024 
00025 #include "sferrors.h"
00026 
00027 
00028   /*************************************************************************/
00029   /*                                                                       */
00030   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
00031   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
00032   /* messages during execution.                                            */
00033   /*                                                                       */
00034 #undef  FT_COMPONENT
00035 #define FT_COMPONENT  trace_ttmtx
00036 
00037 
00038   /*
00039    *  Unfortunately, we can't enable our memory optimizations if
00040    *  FT_CONFIG_OPTION_OLD_INTERNALS is defined.  This is because at least
00041    *  one rogue client (libXfont in the X.Org XServer) is directly accessing
00042    *  the metrics.
00043    */
00044 
00045   /*************************************************************************/
00046   /*                                                                       */
00047   /* <Function>                                                            */
00048   /*    tt_face_load_hmtx                                                  */
00049   /*                                                                       */
00050   /* <Description>                                                         */
00051   /*    Load the `hmtx' or `vmtx' table into a face object.                */
00052   /*                                                                       */
00053   /* <Input>                                                               */
00054   /*    face     :: A handle to the target face object.                    */
00055   /*                                                                       */
00056   /*    stream   :: The input stream.                                      */
00057   /*                                                                       */
00058   /*    vertical :: A boolean flag.  If set, load `vmtx'.                  */
00059   /*                                                                       */
00060   /* <Return>                                                              */
00061   /*    FreeType error code.  0 means success.                             */
00062   /*                                                                       */
00063 #ifndef FT_CONFIG_OPTION_OLD_INTERNALS
00064 
00065   FT_LOCAL_DEF( FT_Error )
00066   tt_face_load_hmtx( TT_Face    face,
00067                      FT_Stream  stream,
00068                      FT_Bool    vertical )
00069   {
00070     FT_Error   error;
00071     FT_ULong   tag, table_size;
00072     FT_ULong*  ptable_offset;
00073     FT_ULong*  ptable_size;
00074 
00075 
00076     if ( vertical )
00077     {
00078       tag           = TTAG_vmtx;
00079       ptable_offset = &face->vert_metrics_offset;
00080       ptable_size   = &face->vert_metrics_size;
00081     }
00082     else
00083     {
00084       tag           = TTAG_hmtx;
00085       ptable_offset = &face->horz_metrics_offset;
00086       ptable_size   = &face->horz_metrics_size;
00087     }
00088 
00089     error = face->goto_table( face, tag, stream, &table_size );
00090     if ( error )
00091       goto Fail;
00092 
00093     *ptable_size   = table_size;
00094     *ptable_offset = FT_STREAM_POS();
00095 
00096   Fail:
00097     return error;
00098   }
00099 
00100 #else /* !FT_CONFIG_OPTION_OLD_INTERNALS */
00101 
00102   FT_LOCAL_DEF( FT_Error )
00103   tt_face_load_hmtx( TT_Face    face,
00104                      FT_Stream  stream,
00105                      FT_Bool    vertical )
00106   {
00107     FT_Error   error;
00108     FT_Memory  memory = stream->memory;
00109 
00110     FT_ULong   table_len;
00111     FT_Long    num_shorts, num_longs, num_shorts_checked;
00112 
00113     TT_LongMetrics*    longs;
00114     TT_ShortMetrics**  shorts;
00115     FT_Byte*           p;
00116 
00117 
00118     if ( vertical )
00119     {
00120       void*   lm = &face->vertical.long_metrics;
00121       void**  sm = &face->vertical.short_metrics;
00122 
00123 
00124       error = face->goto_table( face, TTAG_vmtx, stream, &table_len );
00125       if ( error )
00126         goto Fail;
00127 
00128       num_longs = face->vertical.number_Of_VMetrics;
00129       if ( (FT_ULong)num_longs > table_len / 4 )
00130         num_longs = (FT_Long)( table_len / 4 );
00131 
00132       face->vertical.number_Of_VMetrics = 0;
00133 
00134       longs  = (TT_LongMetrics*)lm;
00135       shorts = (TT_ShortMetrics**)sm;
00136     }
00137     else
00138     {
00139       void*   lm = &face->horizontal.long_metrics;
00140       void**  sm = &face->horizontal.short_metrics;
00141 
00142 
00143       error = face->goto_table( face, TTAG_hmtx, stream, &table_len );
00144       if ( error )
00145         goto Fail;
00146 
00147       num_longs = face->horizontal.number_Of_HMetrics;
00148       if ( (FT_ULong)num_longs > table_len / 4 )
00149         num_longs = (FT_Long)( table_len / 4 );
00150 
00151       face->horizontal.number_Of_HMetrics = 0;
00152 
00153       longs  = (TT_LongMetrics*)lm;
00154       shorts = (TT_ShortMetrics**)sm;
00155     }
00156 
00157     /* never trust derived values */
00158 
00159     num_shorts         = face->max_profile.numGlyphs - num_longs;
00160     num_shorts_checked = ( table_len - num_longs * 4L ) / 2;
00161 
00162     if ( num_shorts < 0 )
00163     {
00164       FT_TRACE0(( "tt_face_load_hmtx:"
00165                   " %cmtx has more metrics than glyphs.\n",
00166                   vertical ? "v" : "h" ));
00167 
00168       /* Adobe simply ignores this problem.  So we shall do the same. */
00169 #if 0
00170       error = vertical ? SFNT_Err_Invalid_Vert_Metrics
00171                        : SFNT_Err_Invalid_Horiz_Metrics;
00172       goto Exit;
00173 #else
00174       num_shorts = 0;
00175 #endif
00176     }
00177 
00178     if ( FT_QNEW_ARRAY( *longs,  num_longs  ) ||
00179          FT_QNEW_ARRAY( *shorts, num_shorts ) )
00180       goto Fail;
00181 
00182     if ( FT_FRAME_ENTER( table_len ) )
00183       goto Fail;
00184 
00185     p = stream->cursor;
00186 
00187     {
00188       TT_LongMetrics  cur   = *longs;
00189       TT_LongMetrics  limit = cur + num_longs;
00190 
00191 
00192       for ( ; cur < limit; cur++ )
00193       {
00194         cur->advance = FT_NEXT_USHORT( p );
00195         cur->bearing = FT_NEXT_SHORT( p );
00196       }
00197     }
00198 
00199     /* do we have an inconsistent number of metric values? */
00200     {
00201       TT_ShortMetrics*  cur   = *shorts;
00202       TT_ShortMetrics*  limit = cur +
00203                                 FT_MIN( num_shorts, num_shorts_checked );
00204 
00205 
00206       for ( ; cur < limit; cur++ )
00207         *cur = FT_NEXT_SHORT( p );
00208 
00209       /* We fill up the missing left side bearings with the     */
00210       /* last valid value.  Since this will occur for buggy CJK */
00211       /* fonts usually only, nothing serious will happen.       */
00212       if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 )
00213       {
00214         FT_Short  val = (*shorts)[num_shorts_checked - 1];
00215 
00216 
00217         limit = *shorts + num_shorts;
00218         for ( ; cur < limit; cur++ )
00219           *cur = val;
00220       }
00221     }
00222 
00223     FT_FRAME_EXIT();
00224 
00225     if ( vertical )
00226       face->vertical.number_Of_VMetrics = (FT_UShort)num_longs;
00227     else
00228       face->horizontal.number_Of_HMetrics = (FT_UShort)num_longs;
00229 
00230   Fail:
00231     return error;
00232   }
00233 
00234 #endif /* !FT_CONFIG_OPTION_OLD_INTERNALS */
00235 
00236 
00237   /*************************************************************************/
00238   /*                                                                       */
00239   /* <Function>                                                            */
00240   /*    tt_face_load_hhea                                                  */
00241   /*                                                                       */
00242   /* <Description>                                                         */
00243   /*    Load the `hhea' or 'vhea' table into a face object.                */
00244   /*                                                                       */
00245   /* <Input>                                                               */
00246   /*    face     :: A handle to the target face object.                    */
00247   /*                                                                       */
00248   /*    stream   :: The input stream.                                      */
00249   /*                                                                       */
00250   /*    vertical :: A boolean flag.  If set, load `vhea'.                  */
00251   /*                                                                       */
00252   /* <Return>                                                              */
00253   /*    FreeType error code.  0 means success.                             */
00254   /*                                                                       */
00255   FT_LOCAL_DEF( FT_Error )
00256   tt_face_load_hhea( TT_Face    face,
00257                      FT_Stream  stream,
00258                      FT_Bool    vertical )
00259   {
00260     FT_Error        error;
00261     TT_HoriHeader*  header;
00262 
00263     const FT_Frame_Field  metrics_header_fields[] =
00264     {
00265 #undef  FT_STRUCTURE
00266 #define FT_STRUCTURE  TT_HoriHeader
00267 
00268       FT_FRAME_START( 36 ),
00269         FT_FRAME_ULONG ( Version ),
00270         FT_FRAME_SHORT ( Ascender ),
00271         FT_FRAME_SHORT ( Descender ),
00272         FT_FRAME_SHORT ( Line_Gap ),
00273         FT_FRAME_USHORT( advance_Width_Max ),
00274         FT_FRAME_SHORT ( min_Left_Side_Bearing ),
00275         FT_FRAME_SHORT ( min_Right_Side_Bearing ),
00276         FT_FRAME_SHORT ( xMax_Extent ),
00277         FT_FRAME_SHORT ( caret_Slope_Rise ),
00278         FT_FRAME_SHORT ( caret_Slope_Run ),
00279         FT_FRAME_SHORT ( caret_Offset ),
00280         FT_FRAME_SHORT ( Reserved[0] ),
00281         FT_FRAME_SHORT ( Reserved[1] ),
00282         FT_FRAME_SHORT ( Reserved[2] ),
00283         FT_FRAME_SHORT ( Reserved[3] ),
00284         FT_FRAME_SHORT ( metric_Data_Format ),
00285         FT_FRAME_USHORT( number_Of_HMetrics ),
00286       FT_FRAME_END
00287     };
00288 
00289 
00290     if ( vertical )
00291     {
00292       void  *v = &face->vertical;
00293 
00294 
00295       error = face->goto_table( face, TTAG_vhea, stream, 0 );
00296       if ( error )
00297         goto Fail;
00298 
00299       header = (TT_HoriHeader*)v;
00300     }
00301     else
00302     {
00303       error = face->goto_table( face, TTAG_hhea, stream, 0 );
00304       if ( error )
00305         goto Fail;
00306 
00307       header = &face->horizontal;
00308     }
00309 
00310     if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) )
00311       goto Fail;
00312 
00313     FT_TRACE3(( "Ascender:          %5d\n", header->Ascender ));
00314     FT_TRACE3(( "Descender:         %5d\n", header->Descender ));
00315     FT_TRACE3(( "number_Of_Metrics: %5u\n", header->number_Of_HMetrics ));
00316 
00317     header->long_metrics  = NULL;
00318     header->short_metrics = NULL;
00319 
00320   Fail:
00321     return error;
00322   }
00323 
00324 
00325   /*************************************************************************/
00326   /*                                                                       */
00327   /* <Function>                                                            */
00328   /*    tt_face_get_metrics                                                */
00329   /*                                                                       */
00330   /* <Description>                                                         */
00331   /*    Returns the horizontal or vertical metrics in font units for a     */
00332   /*    given glyph.  The metrics are the left side bearing (resp. top     */
00333   /*    side bearing) and advance width (resp. advance height).            */
00334   /*                                                                       */
00335   /* <Input>                                                               */
00336   /*    header  :: A pointer to either the horizontal or vertical metrics  */
00337   /*               structure.                                              */
00338   /*                                                                       */
00339   /*    idx     :: The glyph index.                                        */
00340   /*                                                                       */
00341   /* <Output>                                                              */
00342   /*    bearing :: The bearing, either left side or top side.              */
00343   /*                                                                       */
00344   /*    advance :: The advance width resp. advance height.                 */
00345   /*                                                                       */
00346 #ifndef FT_CONFIG_OPTION_OLD_INTERNALS
00347 
00348   FT_LOCAL_DEF( FT_Error )
00349   tt_face_get_metrics( TT_Face     face,
00350                        FT_Bool     vertical,
00351                        FT_UInt     gindex,
00352                        FT_Short   *abearing,
00353                        FT_UShort  *aadvance )
00354   {
00355     FT_Error        error;
00356     FT_Stream       stream = face->root.stream;
00357     TT_HoriHeader*  header;
00358     FT_ULong        table_pos, table_size, table_end;
00359     FT_UShort       k;
00360 
00361 
00362     if ( vertical )
00363     {
00364       void*  v = &face->vertical;
00365 
00366 
00367       header     = (TT_HoriHeader*)v;
00368       table_pos  = face->vert_metrics_offset;
00369       table_size = face->vert_metrics_size;
00370     }
00371     else
00372     {
00373       header     = &face->horizontal;
00374       table_pos  = face->horz_metrics_offset;
00375       table_size = face->horz_metrics_size;
00376     }
00377 
00378     table_end = table_pos + table_size;
00379 
00380     k = header->number_Of_HMetrics;
00381 
00382     if ( k > 0 )
00383     {
00384       if ( gindex < (FT_UInt)k )
00385       {
00386         table_pos += 4 * gindex;
00387         if ( table_pos + 4 > table_end )
00388           goto NoData;
00389 
00390         if ( FT_STREAM_SEEK( table_pos ) ||
00391              FT_READ_USHORT( *aadvance ) ||
00392              FT_READ_SHORT( *abearing )  )
00393           goto NoData;
00394       }
00395       else
00396       {
00397         table_pos += 4 * ( k - 1 );
00398         if ( table_pos + 4 > table_end )
00399           goto NoData;
00400 
00401         if ( FT_STREAM_SEEK( table_pos ) ||
00402              FT_READ_USHORT( *aadvance ) )
00403           goto NoData;
00404 
00405         table_pos += 4 + 2 * ( gindex - k );
00406         if ( table_pos + 2 > table_end )
00407           *abearing = 0;
00408         else
00409         {
00410           if ( !FT_STREAM_SEEK( table_pos ) )
00411             (void)FT_READ_SHORT( *abearing );
00412         }
00413       }
00414     }
00415     else
00416     {
00417     NoData:
00418       *abearing = 0;
00419       *aadvance = 0;
00420     }
00421 
00422     return SFNT_Err_Ok;
00423   }
00424 
00425 #else /* !FT_CONFIG_OPTION_OLD_INTERNALS */
00426 
00427   FT_LOCAL_DEF( FT_Error )
00428   tt_face_get_metrics( TT_Face     face,
00429                        FT_Bool     vertical,
00430                        FT_UInt     gindex,
00431                        FT_Short*   abearing,
00432                        FT_UShort*  aadvance )
00433   {
00434     void*           v = &face->vertical;
00435     void*           h = &face->horizontal;
00436     TT_HoriHeader*  header = vertical ? (TT_HoriHeader*)v
00437                                       : (TT_HoriHeader*)h;
00438     TT_LongMetrics  longs_m;
00439     FT_UShort       k = header->number_Of_HMetrics;
00440 
00441 
00442     if ( k == 0                                         ||
00443          !header->long_metrics                          ||
00444          gindex >= (FT_UInt)face->max_profile.numGlyphs )
00445     {
00446       *abearing = *aadvance = 0;
00447       return SFNT_Err_Ok;
00448     }
00449 
00450     if ( gindex < (FT_UInt)k )
00451     {
00452       longs_m   = (TT_LongMetrics)header->long_metrics + gindex;
00453       *abearing = longs_m->bearing;
00454       *aadvance = longs_m->advance;
00455     }
00456     else
00457     {
00458       *abearing = ((TT_ShortMetrics*)header->short_metrics)[gindex - k];
00459       *aadvance = ((TT_LongMetrics)header->long_metrics)[k - 1].advance;
00460     }
00461 
00462     return SFNT_Err_Ok;
00463   }
00464 
00465 #endif /* !FT_CONFIG_OPTION_OLD_INTERNALS */
00466 
00467 
00468 /* END */

Generated on Tue Jul 5 14:13:51 2011 for ROOT_528-00b_version by  doxygen 1.5.1