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