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