Git init
[framework/graphics/freetype.git] / src / sfnt / ttmtx.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ttmtx.c                                                                */
4 /*                                                                         */
5 /*    Load the metrics tables common to TTF and OTF fonts (body).          */
6 /*                                                                         */
7 /*  Copyright 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_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 */