source: trunk/poppler/freetype2/src/sfnt/ttmtx.c @ 251

Last change on this file since 251 was 251, checked in by Eugene Romanenko, 13 years ago

PDF plugin: freetype library updated to version 2.3.5

File size: 15.9 KB
Line 
1/***************************************************************************/
2/*                                                                         */
3/*  ttmtx.c                                                                */
4/*                                                                         */
5/*    Load the metrics tables common to TTF and OTF fonts (body).          */
6/*                                                                         */
7/*  Copyright 2006, 2007 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#if !defined 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 /* !OPTIMIZE_MEMORY || 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_ERROR(( "%cmtx has more metrics than glyphs.\n" ));
165
166      /* Adobe simply ignores this problem.  So we shall do the same. */
167#if 0
168      error = vertical ? SFNT_Err_Invalid_Vert_Metrics
169                       : SFNT_Err_Invalid_Horiz_Metrics;
170      goto Exit;
171#else
172      num_shorts = 0;
173#endif
174    }
175
176    if ( FT_QNEW_ARRAY( *longs,  num_longs  ) ||
177         FT_QNEW_ARRAY( *shorts, num_shorts ) )
178      goto Fail;
179
180    if ( FT_FRAME_ENTER( table_len ) )
181      goto Fail;
182
183    p = stream->cursor;
184
185    {
186      TT_LongMetrics  cur   = *longs;
187      TT_LongMetrics  limit = cur + num_longs;
188
189
190      for ( ; cur < limit; cur++ )
191      {
192        cur->advance = FT_NEXT_USHORT( p );
193        cur->bearing = FT_NEXT_SHORT( p );
194      }
195    }
196
197    /* do we have an inconsistent number of metric values? */
198    {
199      TT_ShortMetrics*  cur   = *shorts;
200      TT_ShortMetrics*  limit = cur +
201                                FT_MIN( num_shorts, num_shorts_checked );
202
203
204      for ( ; cur < limit; cur++ )
205        *cur = FT_NEXT_SHORT( p );
206
207      /* We fill up the missing left side bearings with the     */
208      /* last valid value.  Since this will occur for buggy CJK */
209      /* fonts usually only, nothing serious will happen.       */
210      if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 )
211      {
212        FT_Short  val = (*shorts)[num_shorts_checked - 1];
213
214
215        limit = *shorts + num_shorts;
216        for ( ; cur < limit; cur++ )
217          *cur = val;
218      }
219    }
220
221    FT_FRAME_EXIT();
222
223    if ( vertical )
224      face->vertical.number_Of_VMetrics = (FT_UShort)num_longs;
225    else
226      face->horizontal.number_Of_HMetrics = (FT_UShort)num_longs;
227
228  Fail:
229    return error;
230  }
231
232#endif /* !OPTIMIZE_MEMORY || OLD_INTERNALS */
233
234
235  /*************************************************************************/
236  /*                                                                       */
237  /* <Function>                                                            */
238  /*    tt_face_load_hhea                                                  */
239  /*                                                                       */
240  /* <Description>                                                         */
241  /*    Load the `hhea' or 'vhea' table into a face object.                */
242  /*                                                                       */
243  /* <Input>                                                               */
244  /*    face     :: A handle to the target face object.                    */
245  /*                                                                       */
246  /*    stream   :: The input stream.                                      */
247  /*                                                                       */
248  /*    vertical :: A boolean flag.  If set, load `vhea'.                  */
249  /*                                                                       */
250  /* <Return>                                                              */
251  /*    FreeType error code.  0 means success.                             */
252  /*                                                                       */
253  FT_LOCAL_DEF( FT_Error )
254  tt_face_load_hhea( TT_Face    face,
255                     FT_Stream  stream,
256                     FT_Bool    vertical )
257  {
258    FT_Error        error;
259    TT_HoriHeader*  header;
260
261    const FT_Frame_Field  metrics_header_fields[] =
262    {
263#undef  FT_STRUCTURE
264#define FT_STRUCTURE  TT_HoriHeader
265
266      FT_FRAME_START( 36 ),
267        FT_FRAME_ULONG ( Version ),
268        FT_FRAME_SHORT ( Ascender ),
269        FT_FRAME_SHORT ( Descender ),
270        FT_FRAME_SHORT ( Line_Gap ),
271        FT_FRAME_USHORT( advance_Width_Max ),
272        FT_FRAME_SHORT ( min_Left_Side_Bearing ),
273        FT_FRAME_SHORT ( min_Right_Side_Bearing ),
274        FT_FRAME_SHORT ( xMax_Extent ),
275        FT_FRAME_SHORT ( caret_Slope_Rise ),
276        FT_FRAME_SHORT ( caret_Slope_Run ),
277        FT_FRAME_SHORT ( caret_Offset ),
278        FT_FRAME_SHORT ( Reserved[0] ),
279        FT_FRAME_SHORT ( Reserved[1] ),
280        FT_FRAME_SHORT ( Reserved[2] ),
281        FT_FRAME_SHORT ( Reserved[3] ),
282        FT_FRAME_SHORT ( metric_Data_Format ),
283        FT_FRAME_USHORT( number_Of_HMetrics ),
284      FT_FRAME_END
285    };
286
287
288    if ( vertical )
289    {
290      void  *v = &face->vertical;
291
292
293      error = face->goto_table( face, TTAG_vhea, stream, 0 );
294      if ( error )
295        goto Fail;
296
297      header = (TT_HoriHeader*)v;
298    }
299    else
300    {
301      error = face->goto_table( face, TTAG_hhea, stream, 0 );
302      if ( error )
303        goto Fail;
304
305      header = &face->horizontal;
306    }
307
308    if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) )
309      goto Fail;
310
311    FT_TRACE3(( "Ascender:          %5d\n", header->Ascender ));
312    FT_TRACE3(( "Descender:         %5d\n", header->Descender ));
313    FT_TRACE3(( "number_Of_Metrics: %5u\n", header->number_Of_HMetrics ));
314
315    header->long_metrics  = NULL;
316    header->short_metrics = NULL;
317
318  Fail:
319    return error;
320  }
321
322
323  /*************************************************************************/
324  /*                                                                       */
325  /* <Function>                                                            */
326  /*    tt_face_get_metrics                                                */
327  /*                                                                       */
328  /* <Description>                                                         */
329  /*    Returns the horizontal or vertical metrics in font units for a     */
330  /*    given glyph.  The metrics are the left side bearing (resp. top     */
331  /*    side bearing) and advance width (resp. advance height).            */
332  /*                                                                       */
333  /* <Input>                                                               */
334  /*    header  :: A pointer to either the horizontal or vertical metrics  */
335  /*               structure.                                              */
336  /*                                                                       */
337  /*    idx     :: The glyph index.                                        */
338  /*                                                                       */
339  /* <Output>                                                              */
340  /*    bearing :: The bearing, either left side or top side.              */
341  /*                                                                       */
342  /*    advance :: The advance width resp. advance height.                 */
343  /*                                                                       */
344#if !defined FT_CONFIG_OPTION_OLD_INTERNALS
345
346  FT_LOCAL_DEF( FT_Error )
347  tt_face_get_metrics( TT_Face     face,
348                       FT_Bool     vertical,
349                       FT_UInt     gindex,
350                       FT_Short   *abearing,
351                       FT_UShort  *aadvance )
352  {
353    FT_Error        error;
354    FT_Stream       stream = face->root.stream;
355    TT_HoriHeader*  header;
356    FT_ULong        table_pos, table_size, table_end;
357    FT_UShort       k;
358
359
360    if ( vertical )
361    {
362      void*  v = &face->vertical;
363
364
365      header     = (TT_HoriHeader*)v;
366      table_pos  = face->vert_metrics_offset;
367      table_size = face->vert_metrics_size;
368    }
369    else
370    {
371      header     = &face->horizontal;
372      table_pos  = face->horz_metrics_offset;
373      table_size = face->horz_metrics_size;
374    }
375
376    table_end = table_pos + table_size;
377
378    k = header->number_Of_HMetrics;
379
380    if ( k > 0 )
381    {
382      if ( gindex < (FT_UInt)k )
383      {
384        table_pos += 4 * gindex;
385        if ( table_pos + 4 > table_end )
386          goto NoData;
387
388        if ( FT_STREAM_SEEK( table_pos ) ||
389             FT_READ_USHORT( *aadvance ) ||
390             FT_READ_SHORT( *abearing )  )
391          goto NoData;
392      }
393      else
394      {
395        table_pos += 4 * ( k - 1 );
396        if ( table_pos + 4 > table_end )
397          goto NoData;
398
399        if ( FT_STREAM_SEEK( table_pos ) ||
400             FT_READ_USHORT( *aadvance ) )
401          goto NoData;
402
403        table_pos += 4 + 2 * ( gindex - k );
404        if ( table_pos + 2 > table_end )
405          *abearing = 0;
406        else
407        {
408          if ( !FT_STREAM_SEEK( table_pos ) )
409            (void)FT_READ_SHORT( *abearing );
410        }
411      }
412    }
413    else
414    {
415    NoData:
416      *abearing = 0;
417      *aadvance = 0;
418    }
419
420    return SFNT_Err_Ok;
421  }
422
423#else /* OLD_INTERNALS */
424
425  FT_LOCAL_DEF( FT_Error )
426  tt_face_get_metrics( TT_Face     face,
427                       FT_Bool     vertical,
428                       FT_UInt     gindex,
429                       FT_Short*   abearing,
430                       FT_UShort*  aadvance )
431  {
432    void*           v = &face->vertical;
433    void*           h = &face->horizontal;
434    TT_HoriHeader*  header = vertical ? (TT_HoriHeader*)v
435                                      : (TT_HoriHeader*)h;
436    TT_LongMetrics  longs_m;
437    FT_UShort       k = header->number_Of_HMetrics;
438
439
440    if ( k == 0                                         ||
441         !header->long_metrics                          ||
442         gindex >= (FT_UInt)face->max_profile.numGlyphs )
443    {
444      *abearing = *aadvance = 0;
445      return SFNT_Err_Ok;
446    }
447
448    if ( gindex < (FT_UInt)k )
449    {
450      longs_m   = (TT_LongMetrics)header->long_metrics + gindex;
451      *abearing = longs_m->bearing;
452      *aadvance = longs_m->advance;
453    }
454    else
455    {
456      *abearing = ((TT_ShortMetrics*)header->short_metrics)[gindex - k];
457      *aadvance = ((TT_LongMetrics)header->long_metrics)[k - 1].advance;
458    }
459
460    return SFNT_Err_Ok;
461  }
462
463#endif /* !OPTIMIZE_MEMORY || OLD_INTERNALS */
464
465
466/* END */
Note: See TracBrowser for help on using the repository browser.