1 /****************************************************************************
2  *
3  * ttmtx.c
4  *
5  *   Load the metrics tables common to TTF and OTF fonts (body).
6  *
7  * Copyright (C) 2006-2020 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 <freetype/internal/ftdebug.h>
20 #include <freetype/internal/ftstream.h>
21 #include <freetype/tttags.h>
22 
23 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
24 #include <freetype/internal/services/svmetric.h>
25 #endif
26 
27 #include "ttmtx.h"
28 
29 #include "sferrors.h"
30 
31 
32   /* IMPORTANT: The TT_HoriHeader and TT_VertHeader structures should   */
33   /*            be identical except for the names of their fields,      */
34   /*            which are different.                                    */
35   /*                                                                    */
36   /*            This ensures that `tt_face_load_hmtx' is able to read   */
37   /*            both the horizontal and vertical headers.               */
38 
39 
40   /**************************************************************************
41    *
42    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
43    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
44    * messages during execution.
45    */
46 #undef  FT_COMPONENT
47 #define FT_COMPONENT  ttmtx
48 
49 
50   /**************************************************************************
51    *
52    * @Function:
53    *   tt_face_load_hmtx
54    *
55    * @Description:
56    *   Load the `hmtx' or `vmtx' table into a face object.
57    *
58    * @Input:
59    *   face ::
60    *     A handle to the target face object.
61    *
62    *   stream ::
63    *     The input stream.
64    *
65    *   vertical ::
66    *     A boolean flag.  If set, load `vmtx'.
67    *
68    * @Return:
69    *   FreeType error code.  0 means success.
70    */
71   FT_LOCAL_DEF( FT_Error )
tt_face_load_hmtx(TT_Face face,FT_Stream stream,FT_Bool vertical)72   tt_face_load_hmtx( TT_Face    face,
73                      FT_Stream  stream,
74                      FT_Bool    vertical )
75   {
76     FT_Error   error;
77     FT_ULong   tag, table_size;
78     FT_ULong*  ptable_offset;
79     FT_ULong*  ptable_size;
80 
81 
82     if ( vertical )
83     {
84       tag           = TTAG_vmtx;
85       ptable_offset = &face->vert_metrics_offset;
86       ptable_size   = &face->vert_metrics_size;
87     }
88     else
89     {
90       tag           = TTAG_hmtx;
91       ptable_offset = &face->horz_metrics_offset;
92       ptable_size   = &face->horz_metrics_size;
93     }
94 
95     error = face->goto_table( face, tag, stream, &table_size );
96     if ( error )
97       goto Fail;
98 
99     *ptable_size   = table_size;
100     *ptable_offset = FT_STREAM_POS();
101 
102   Fail:
103     return error;
104   }
105 
106 
107   /**************************************************************************
108    *
109    * @Function:
110    *   tt_face_load_hhea
111    *
112    * @Description:
113    *   Load the `hhea' or 'vhea' table into a face object.
114    *
115    * @Input:
116    *   face ::
117    *     A handle to the target face object.
118    *
119    *   stream ::
120    *     The input stream.
121    *
122    *   vertical ::
123    *     A boolean flag.  If set, load `vhea'.
124    *
125    * @Return:
126    *   FreeType error code.  0 means success.
127    */
128   FT_LOCAL_DEF( FT_Error )
tt_face_load_hhea(TT_Face face,FT_Stream stream,FT_Bool vertical)129   tt_face_load_hhea( TT_Face    face,
130                      FT_Stream  stream,
131                      FT_Bool    vertical )
132   {
133     FT_Error        error;
134     TT_HoriHeader*  header;
135 
136     static const FT_Frame_Field  metrics_header_fields[] =
137     {
138 #undef  FT_STRUCTURE
139 #define FT_STRUCTURE  TT_HoriHeader
140 
141       FT_FRAME_START( 36 ),
142         FT_FRAME_ULONG ( Version ),
143         FT_FRAME_SHORT ( Ascender ),
144         FT_FRAME_SHORT ( Descender ),
145         FT_FRAME_SHORT ( Line_Gap ),
146         FT_FRAME_USHORT( advance_Width_Max ),
147         FT_FRAME_SHORT ( min_Left_Side_Bearing ),
148         FT_FRAME_SHORT ( min_Right_Side_Bearing ),
149         FT_FRAME_SHORT ( xMax_Extent ),
150         FT_FRAME_SHORT ( caret_Slope_Rise ),
151         FT_FRAME_SHORT ( caret_Slope_Run ),
152         FT_FRAME_SHORT ( caret_Offset ),
153         FT_FRAME_SHORT ( Reserved[0] ),
154         FT_FRAME_SHORT ( Reserved[1] ),
155         FT_FRAME_SHORT ( Reserved[2] ),
156         FT_FRAME_SHORT ( Reserved[3] ),
157         FT_FRAME_SHORT ( metric_Data_Format ),
158         FT_FRAME_USHORT( number_Of_HMetrics ),
159       FT_FRAME_END
160     };
161 
162 
163     if ( vertical )
164     {
165       void  *v = &face->vertical;
166 
167 
168       error = face->goto_table( face, TTAG_vhea, stream, 0 );
169       if ( error )
170         goto Fail;
171 
172       header = (TT_HoriHeader*)v;
173     }
174     else
175     {
176       error = face->goto_table( face, TTAG_hhea, stream, 0 );
177       if ( error )
178         goto Fail;
179 
180       header = &face->horizontal;
181     }
182 
183     if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) )
184       goto Fail;
185 
186     FT_TRACE3(( "Ascender:          %5d\n", header->Ascender ));
187     FT_TRACE3(( "Descender:         %5d\n", header->Descender ));
188     FT_TRACE3(( "number_Of_Metrics: %5u\n", header->number_Of_HMetrics ));
189 
190     header->long_metrics  = NULL;
191     header->short_metrics = NULL;
192 
193   Fail:
194     return error;
195   }
196 
197 
198   /**************************************************************************
199    *
200    * @Function:
201    *   tt_face_get_metrics
202    *
203    * @Description:
204    *   Return the horizontal or vertical metrics in font units for a
205    *   given glyph.  The values are the left side bearing (top side
206    *   bearing for vertical metrics) and advance width (advance height
207    *   for vertical metrics).
208    *
209    * @Input:
210    *   face ::
211    *     A pointer to the TrueType face structure.
212    *
213    *   vertical ::
214    *     If set to TRUE, get vertical metrics.
215    *
216    *   gindex ::
217    *     The glyph index.
218    *
219    * @Output:
220    *   abearing ::
221    *     The bearing, either left side or top side.
222    *
223    *   aadvance ::
224    *     The advance width or advance height, depending on
225    *     the `vertical' flag.
226    */
227   FT_LOCAL_DEF( void )
tt_face_get_metrics(TT_Face face,FT_Bool vertical,FT_UInt gindex,FT_Short * abearing,FT_UShort * aadvance)228   tt_face_get_metrics( TT_Face     face,
229                        FT_Bool     vertical,
230                        FT_UInt     gindex,
231                        FT_Short   *abearing,
232                        FT_UShort  *aadvance )
233   {
234     FT_Error        error;
235     FT_Stream       stream = face->root.stream;
236     TT_HoriHeader*  header;
237     FT_ULong        table_pos, table_size, table_end;
238     FT_UShort       k;
239 
240 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
241     FT_Service_MetricsVariations  var =
242       (FT_Service_MetricsVariations)face->var;
243 #endif
244 
245 
246     if ( vertical )
247     {
248       void*  v = &face->vertical;
249 
250 
251       header     = (TT_HoriHeader*)v;
252       table_pos  = face->vert_metrics_offset;
253       table_size = face->vert_metrics_size;
254     }
255     else
256     {
257       header     = &face->horizontal;
258       table_pos  = face->horz_metrics_offset;
259       table_size = face->horz_metrics_size;
260     }
261 
262     table_end = table_pos + table_size;
263 
264     k = header->number_Of_HMetrics;
265 
266     if ( k > 0 )
267     {
268       if ( gindex < (FT_UInt)k )
269       {
270         table_pos += 4 * gindex;
271         if ( table_pos + 4 > table_end )
272           goto NoData;
273 
274         if ( FT_STREAM_SEEK( table_pos ) ||
275              FT_READ_USHORT( *aadvance ) ||
276              FT_READ_SHORT( *abearing )  )
277           goto NoData;
278       }
279       else
280       {
281         table_pos += 4 * ( k - 1 );
282         if ( table_pos + 2 > table_end )
283           goto NoData;
284 
285         if ( FT_STREAM_SEEK( table_pos ) ||
286              FT_READ_USHORT( *aadvance ) )
287           goto NoData;
288 
289         table_pos += 4 + 2 * ( gindex - k );
290         if ( table_pos + 2 > table_end )
291           *abearing = 0;
292         else
293         {
294           if ( FT_STREAM_SEEK( table_pos ) )
295             *abearing = 0;
296           else
297             (void)FT_READ_SHORT( *abearing );
298         }
299       }
300     }
301     else
302     {
303     NoData:
304       *abearing = 0;
305       *aadvance = 0;
306     }
307 
308 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
309     if ( var )
310     {
311       FT_Face  f = FT_FACE( face );
312       FT_Int   a = (FT_Int)*aadvance;
313       FT_Int   b = (FT_Int)*abearing;
314 
315 
316       if ( vertical )
317       {
318         if ( var->vadvance_adjust )
319           var->vadvance_adjust( f, gindex, &a );
320         if ( var->tsb_adjust )
321           var->tsb_adjust( f, gindex, &b );
322       }
323       else
324       {
325         if ( var->hadvance_adjust )
326           var->hadvance_adjust( f, gindex, &a );
327         if ( var->lsb_adjust )
328           var->lsb_adjust( f, gindex, &b );
329       }
330 
331       *aadvance = (FT_UShort)a;
332       *abearing = (FT_Short)b;
333     }
334 #endif
335   }
336 
337 
338 /* END */
339