1/****************************************************************************
2 *
3 * ttmtx.c
4 *
5 * Load the metrics tables common to TTF and OTF fonts (body).
6 *
7 * Copyright (C) 2006-2023 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 )
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 )
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 )
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->tt_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 && face->blend )
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